According to Dougall's pseudocode, else_icmp operates as:
if r0l == 0:
r0l = n
elif r0l == 1:
if cc.compare(A[thread], B[thread]):
r0l = 0
else:
r0l = 1
exec_mask[thread] = (r0l == 0)
Notice that the comparison only happens when r0l == 1, that is, for threads that
are about to enter the else block. Threads that just executed the if body are
still active (r0l = 0) and skip the comparison. As such, the sources of
else_icmp are only read in the else block, and hence the whole instruction
should be placed in the else block for correctness with respect to live range
splitting.
shader-db is a wash, but shows some improvements due to correctly modelling the
liveness of the condition variable.
total instructions in shared programs: 1778376 -> 1778390 (<.01%)
instructions in affected programs: 14753 -> 14767 (0.09%)
helped: 35
HURT: 39
Inconclusive result (value mean confidence interval includes 0).
total bytes in shared programs:
12185018 ->
12185102 (<.01%)
bytes in affected programs: 101522 -> 101606 (0.08%)
helped: 35
HURT: 39
Inconclusive result (value mean confidence interval includes 0).
total halfregs in shared programs: 531174 -> 531032 (-0.03%)
halfregs in affected programs: 2320 -> 2178 (-6.12%)
helped: 40
HURT: 1
Halfregs are helped.
total threads in shared programs:
18909184 ->
18909440 (<.01%)
threads in affected programs: 1792 -> 2048 (14.29%)
helped: 2
HURT: 0
Signed-off-by: Alyssa Rosenzweig <alyssa@rosenzweig.io>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/24635>
_b.cursor = agx_after_block(ctx->current_block);
agx_emit_logical_end(&_b);
- agx_else_icmp(&_b, cond, agx_zero(), 1, AGX_ICOND_UEQ, false);
agx_block *else_block = emit_cf_list(ctx, &nif->else_list);
agx_block *end_else = ctx->current_block;
+ _b.cursor = agx_before_block(else_block);
+ agx_else_icmp(&_b, cond, agx_zero(), 1, AGX_ICOND_UEQ, false);
+
ctx->after_block = agx_create_block(ctx);
agx_block_add_successor(first_block, if_block);
agx_foreach_dest(ins, v) \
if (ins->dest[v].type == AGX_INDEX_NORMAL)
-/* Phis only come at the start so we stop as soon as we hit a non-phi */
+/* Phis only come at the start (after else instructions) so we stop as soon as
+ * we hit a non-phi
+ */
#define agx_foreach_phi_in_block(block, v) \
agx_foreach_instr_in_block(block, v) \
- if (v->op != AGX_OPCODE_PHI) \
- break; \
- else
-
-/* Everything else comes after, so we stop as soon as we hit a phi in reverse */
-#define agx_foreach_non_phi_in_block_rev(block, v) \
- agx_foreach_instr_in_block_rev(block, v) \
- if (v->op == AGX_OPCODE_PHI) \
+ if (v->op == AGX_OPCODE_ELSE_ICMP || v->op == AGX_OPCODE_ELSE_FCMP) \
+ continue; \
+ else if (v->op != AGX_OPCODE_PHI) \
break; \
else
/* Update its liveness information */
memcpy(blk->live_in, blk->live_out, words * sizeof(BITSET_WORD));
- agx_foreach_non_phi_in_block_rev(blk, I)
- agx_liveness_ins_update(blk->live_in, I);
+ agx_foreach_instr_in_block_rev(blk, I) {
+ if (I->op != AGX_OPCODE_PHI)
+ agx_liveness_ins_update(blk->live_in, I);
+ }
/* Propagate the live in of the successor (blk) to the live out of
* predecessors.
* block contains control flow, it must come after a p_logical_end marker.
* Therefore the form of a valid block is:
*
+ * Control flow instructions (else)
* Phi nodes
* General instructions
* Logical end
- * Control flow instructions
+ * Control flow instructions (except else)
*
* Validate that this form is satisfied.
*
* that should be deferred though?
*/
enum agx_block_state {
- AGX_BLOCK_STATE_PHI = 0,
- AGX_BLOCK_STATE_BODY = 1,
- AGX_BLOCK_STATE_CF = 2
+ AGX_BLOCK_STATE_CF_ELSE = 0,
+ AGX_BLOCK_STATE_PHI = 1,
+ AGX_BLOCK_STATE_BODY = 2,
+ AGX_BLOCK_STATE_CF = 3
};
static bool
agx_validate_block_form(agx_block *block)
{
- enum agx_block_state state = AGX_BLOCK_STATE_PHI;
+ enum agx_block_state state = AGX_BLOCK_STATE_CF_ELSE;
agx_foreach_instr_in_block(block, I) {
switch (I->op) {
+ case AGX_OPCODE_ELSE_ICMP:
+ case AGX_OPCODE_ELSE_FCMP:
+ agx_validate_assert(state == AGX_BLOCK_STATE_CF_ELSE);
+ break;
+
case AGX_OPCODE_PHI:
- agx_validate_assert(state == AGX_BLOCK_STATE_PHI);
+ agx_validate_assert(state == AGX_BLOCK_STATE_CF_ELSE ||
+ state == AGX_BLOCK_STATE_PHI);
+
+ state = AGX_BLOCK_STATE_PHI;
break;
default:
case AGX_OPCODE_JMP_EXEC_NONE:
case AGX_OPCODE_POP_EXEC:
case AGX_OPCODE_IF_ICMP:
- case AGX_OPCODE_ELSE_ICMP:
case AGX_OPCODE_WHILE_ICMP:
case AGX_OPCODE_IF_FCMP:
- case AGX_OPCODE_ELSE_FCMP:
case AGX_OPCODE_WHILE_FCMP:
case AGX_OPCODE_STOP:
agx_validate_assert(state == AGX_BLOCK_STATE_CF);