diff --git a/src/asahi/compiler/agx_compile.c b/src/asahi/compiler/agx_compile.c index f0807d60602..1bec5f15438 100644 --- a/src/asahi/compiler/agx_compile.c +++ b/src/asahi/compiler/agx_compile.c @@ -1718,20 +1718,6 @@ agx_emit_tex(agx_builder *b, nir_tex_instr *instr) I->mask = agx_expand_tex_to(b, &instr->def, tmp, masked); } -/* - * Mark the logical end of the current block by emitting a p_logical_end marker. - * Note if an unconditional jump is emitted (for instance, to break out of a - * loop from inside an if), the block has already reached its logical end so we - * don't re-emit p_logical_end. The validator checks this, and correct register - * allocation depends on it. - */ -static void -agx_emit_logical_end(agx_builder *b) -{ - if (!b->shader->current_block->unconditional_jumps) - agx_logical_end(b); -} - /* * NIR loops are treated as a pair of AGX loops: * @@ -1768,9 +1754,6 @@ agx_emit_jump(agx_builder *b, nir_jump_instr *instr) /* Update the counter and flush */ agx_nest(b, nestings); - - /* Jumps must come at the end of a block */ - agx_emit_logical_end(b); agx_pop_exec(b, 0); ctx->current_block->unconditional_jumps = true; @@ -1925,7 +1908,6 @@ emit_if(agx_context *ctx, nir_if *nif) agx_builder _b = agx_init_builder(ctx, agx_after_block(first_block)); agx_index cond = agx_src_index(&nif->condition); - agx_emit_logical_end(&_b); agx_if_icmp(&_b, cond, agx_zero(), 1, AGX_ICOND_UEQ, true); ctx->loop_nesting++; @@ -1934,7 +1916,6 @@ emit_if(agx_context *ctx, nir_if *nif) agx_block *end_then = ctx->current_block; _b.cursor = agx_after_block(ctx->current_block); - agx_emit_logical_end(&_b); agx_block *else_block = emit_cf_list(ctx, &nif->else_list); agx_block *end_else = ctx->current_block; @@ -1953,7 +1934,6 @@ emit_if(agx_context *ctx, nir_if *nif) agx_block_add_successor(end_else, ctx->after_block); _b.cursor = agx_after_block(ctx->current_block); - agx_emit_logical_end(&_b); agx_pop_exec(&_b, 1); ctx->loop_nesting--; } @@ -1974,7 +1954,6 @@ emit_loop(agx_context *ctx, nir_loop *nloop) /* Make room for break/continue nesting (TODO: skip if no divergent CF) */ agx_builder _b = agx_init_builder(ctx, agx_after_block(ctx->current_block)); - agx_emit_logical_end(&_b); agx_push_exec(&_b, 2); /* Fallthrough to body */ @@ -1988,7 +1967,6 @@ emit_loop(agx_context *ctx, nir_loop *nloop) /* Fix up the nesting counter via an always true while_icmp, and branch back * to start of loop if any lanes are active */ _b.cursor = agx_after_block(ctx->current_block); - agx_emit_logical_end(&_b); agx_while_icmp(&_b, agx_zero(), agx_zero(), 2, AGX_ICOND_UEQ, false); agx_jmp_exec_any(&_b, start_block); agx_pop_exec(&_b, 2); @@ -2526,7 +2504,6 @@ agx_compile_function_nir(nir_shader *nir, nir_function_impl *impl, */ agx_block *last_block = list_last_entry(&ctx->blocks, agx_block, link); agx_builder _b = agx_init_builder(ctx, agx_after_block(last_block)); - agx_logical_end(&_b); agx_stop(&_b); /* Index blocks now that we're done emitting so the order is consistent */ diff --git a/src/asahi/compiler/agx_compiler.h b/src/asahi/compiler/agx_compiler.h index 32468192ba7..eca198d1f54 100644 --- a/src/asahi/compiler/agx_compiler.h +++ b/src/asahi/compiler/agx_compiler.h @@ -670,24 +670,6 @@ agx_after_instr(agx_instr *instr) }; } -/* - * Get a cursor inserting at the logical end of the block. In particular, this - * is before branches or control flow instructions, which occur after the - * logical end but before the physical end. - */ -static inline agx_cursor -agx_after_block_logical(agx_block *block) -{ - /* Search for a p_logical_end */ - agx_foreach_instr_in_block_rev(block, I) { - if (I->op == AGX_OPCODE_LOGICAL_END) - return agx_before_instr(I); - } - - /* If there's no p_logical_end, use the physical end */ - return agx_after_block(block); -} - static inline agx_cursor agx_before_nonempty_block(agx_block *block) { @@ -706,6 +688,42 @@ agx_before_block(agx_block *block) return agx_before_nonempty_block(block); } +static inline bool +instr_after_logical_end(const agx_instr *I) +{ + switch (I->op) { + case AGX_OPCODE_JMP_EXEC_ANY: + case AGX_OPCODE_JMP_EXEC_NONE: + case AGX_OPCODE_POP_EXEC: + case AGX_OPCODE_IF_ICMP: + case AGX_OPCODE_WHILE_ICMP: + case AGX_OPCODE_IF_FCMP: + case AGX_OPCODE_WHILE_FCMP: + case AGX_OPCODE_STOP: + return true; + default: + return false; + } +} + +/* + * Get a cursor inserting at the logical end of the block. In particular, this + * is before branches or control flow instructions, which occur after the + * logical end but before the physical end. + */ +static inline agx_cursor +agx_after_block_logical(agx_block *block) +{ + /* Search for the first instruction that's not past the logical end */ + agx_foreach_instr_in_block_rev(block, I) { + if (!instr_after_logical_end(I)) + return agx_after_instr(I); + } + + /* If we got here, the block is either empty or entirely control flow */ + return agx_before_block(block); +} + /* IR builder in terms of cursor infrastructure */ typedef struct { diff --git a/src/asahi/compiler/agx_opcodes.py b/src/asahi/compiler/agx_opcodes.py index 6c81d2c5ed8..71a9a45a5fa 100644 --- a/src/asahi/compiler/agx_opcodes.py +++ b/src/asahi/compiler/agx_opcodes.py @@ -410,10 +410,6 @@ op("xor", _, srcs = 2) op("and", _, srcs = 2) op("or", _, srcs = 2) -# Indicates the logical end of the block, before final branches/control flow -op("logical_end", _, dests = 0, srcs = 0, can_eliminate = False, - schedule_class = "invalid") - op("collect", _, srcs = VARIABLE) op("split", _, srcs = 1, dests = VARIABLE) op("phi", _, srcs = VARIABLE, schedule_class = "preload") diff --git a/src/asahi/compiler/agx_opt_empty_else.c b/src/asahi/compiler/agx_opt_empty_else.c index eb22651a884..653782b6abc 100644 --- a/src/asahi/compiler/agx_opt_empty_else.c +++ b/src/asahi/compiler/agx_opt_empty_else.c @@ -12,7 +12,6 @@ * Detect blocks with the sole contents: * * else n=1 - * logical_end * pop_exec n=1 * * The else instruction is a no-op. To see that, consider the pseudocode for the @@ -50,7 +49,6 @@ enum block_state { STATE_ELSE = 0, - STATE_LOGICAL_END, STATE_POP_EXEC, STATE_DONE, @@ -66,9 +64,6 @@ state_for_instr(const agx_instr *I) case AGX_OPCODE_ELSE_FCMP: return (I->nest == 1) ? STATE_ELSE : STATE_NONE; - case AGX_OPCODE_LOGICAL_END: - return STATE_LOGICAL_END; - case AGX_OPCODE_POP_EXEC: return (I->nest == 1) ? STATE_POP_EXEC : STATE_NONE; diff --git a/src/asahi/compiler/agx_pack.c b/src/asahi/compiler/agx_pack.c index 68c1f9eec03..6cf796a4d2c 100644 --- a/src/asahi/compiler/agx_pack.c +++ b/src/asahi/compiler/agx_pack.c @@ -984,15 +984,6 @@ agx_pack_binary(agx_context *ctx, struct util_dynarray *emission) struct util_dynarray fixups; util_dynarray_init(&fixups, ctx); - agx_foreach_block(ctx, block) { - agx_foreach_instr_in_block_rev(block, I) { - if (I->op == AGX_OPCODE_LOGICAL_END) { - agx_remove_instruction(I); - break; - } - } - } - agx_foreach_block(ctx, block) { /* Relative to the start of the binary, the block begins at the current * number of bytes emitted */ diff --git a/src/asahi/compiler/agx_pressure_schedule.c b/src/asahi/compiler/agx_pressure_schedule.c index 4ae25f15161..78e0b44e67c 100644 --- a/src/asahi/compiler/agx_pressure_schedule.c +++ b/src/asahi/compiler/agx_pressure_schedule.c @@ -59,7 +59,7 @@ create_dag(agx_context *ctx, agx_block *block, void *memctx) agx_foreach_instr_in_block(block, I) { /* Don't touch control flow */ - if (I->op == AGX_OPCODE_LOGICAL_END) + if (instr_after_logical_end(I)) break; struct sched_node *node = rzalloc(memctx, struct sched_node); diff --git a/src/asahi/compiler/agx_validate.c b/src/asahi/compiler/agx_validate.c index a19a794efcb..5acd9501aab 100644 --- a/src/asahi/compiler/agx_validate.c +++ b/src/asahi/compiler/agx_validate.c @@ -17,13 +17,12 @@ /* * If a block contains phi nodes, they must come at the start of the block. If a - * block contains control flow, it must come after a p_logical_end marker. + * block contains control flow, it must come at the beginning/end as applicable. * Therefore the form of a valid block is: * * Control flow instructions (else) * Phi nodes * General instructions - * Logical end * Control flow instructions (except else) * * Validate that this form is satisfied. @@ -58,24 +57,12 @@ agx_validate_block_form(agx_block *block) break; default: - agx_validate_assert(state != AGX_BLOCK_STATE_CF); - state = AGX_BLOCK_STATE_BODY; - break; - - case AGX_OPCODE_LOGICAL_END: - agx_validate_assert(state != AGX_BLOCK_STATE_CF); - state = AGX_BLOCK_STATE_CF; - break; - - case AGX_OPCODE_JMP_EXEC_ANY: - case AGX_OPCODE_JMP_EXEC_NONE: - case AGX_OPCODE_POP_EXEC: - case AGX_OPCODE_IF_ICMP: - case AGX_OPCODE_WHILE_ICMP: - case AGX_OPCODE_IF_FCMP: - case AGX_OPCODE_WHILE_FCMP: - case AGX_OPCODE_STOP: - agx_validate_assert(state == AGX_BLOCK_STATE_CF); + if (instr_after_logical_end(I)) { + state = AGX_BLOCK_STATE_CF; + } else { + agx_validate_assert(state != AGX_BLOCK_STATE_CF); + state = AGX_BLOCK_STATE_BODY; + } break; } }