diff --git a/src/asahi/compiler/agx_builder.h.py b/src/asahi/compiler/agx_builder.h.py index 4594d5cbc07..4ae5f5ad1dd 100644 --- a/src/asahi/compiler/agx_builder.h.py +++ b/src/asahi/compiler/agx_builder.h.py @@ -131,7 +131,7 @@ agx_fmov_to(agx_builder *b, agx_index dst0, agx_index src0) static inline agx_instr * agx_push_exec(agx_builder *b, unsigned n) { - return agx_if_fcmp(b, agx_zero(), agx_zero(), n, AGX_FCOND_EQ, false); + return agx_if_fcmp(b, agx_zero(), agx_zero(), n, AGX_FCOND_EQ, false, NULL); } static inline agx_instr * diff --git a/src/asahi/compiler/agx_compile.c b/src/asahi/compiler/agx_compile.c index 693981500ed..ff255ad1dd3 100644 --- a/src/asahi/compiler/agx_compile.c +++ b/src/asahi/compiler/agx_compile.c @@ -1788,7 +1788,7 @@ agx_emit_jump(agx_builder *b, nir_jump_instr *instr) agx_block_add_successor(ctx->current_block, ctx->break_block); } - agx_break(b, nestings); + agx_break(b, nestings, ctx->break_block); ctx->current_block->unconditional_jumps = true; } @@ -1941,7 +1941,8 @@ 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_if_icmp(&_b, cond, agx_zero(), 1, AGX_ICOND_UEQ, true); + agx_instr *if_ = agx_if_icmp(&_b, cond, agx_zero(), 1, AGX_ICOND_UEQ, true, + NULL /* filled in later */); ctx->loop_nesting++; ctx->total_nesting++; @@ -1954,11 +1955,16 @@ emit_if(agx_context *ctx, nir_if *nif) agx_block *else_block = emit_cf_list(ctx, &nif->else_list); agx_block *end_else = ctx->current_block; + /* If the "if" fails, we fallthrough to the else */ + if_->target = else_block; + /* Insert an else instruction at the beginning of the else block. We use * "else_fcmp 0.0, 0.0, eq" as unconditional else, matching the blob. + * + * If it fails, we fall through to the logical end of the last else block. */ _b.cursor = agx_before_block(else_block); - agx_else_fcmp(&_b, agx_zero(), agx_zero(), 1, AGX_FCOND_EQ, false); + agx_else_fcmp(&_b, agx_zero(), agx_zero(), 1, AGX_FCOND_EQ, false, end_else); ctx->after_block = agx_create_block(ctx); @@ -2019,8 +2025,11 @@ emit_loop(agx_context *ctx, nir_loop *nloop) */ _b.cursor = agx_after_block(ctx->current_block); - if (ctx->loop_continues) - agx_while_icmp(&_b, agx_zero(), agx_zero(), 2, AGX_ICOND_UEQ, false); + if (ctx->loop_continues) { + agx_while_icmp( + &_b, agx_zero(), agx_zero(), 2, AGX_ICOND_UEQ, false, + NULL /* no semantic target, used purely for side effects */); + } agx_jmp_exec_any(&_b, start_block); agx_pop_exec(&_b, ctx->loop_continues ? 2 : 1); diff --git a/src/asahi/compiler/agx_compiler.h b/src/asahi/compiler/agx_compiler.h index 072d7c4f5dd..b4300813960 100644 --- a/src/asahi/compiler/agx_compiler.h +++ b/src/asahi/compiler/agx_compiler.h @@ -275,6 +275,12 @@ typedef struct { uint8_t nr_dests; uint8_t nr_srcs; + /* TODO: More efficient */ + union { + enum agx_icond icond; + enum agx_fcond fcond; + }; + union { uint64_t imm; uint32_t writeout; @@ -285,8 +291,6 @@ typedef struct { uint16_t pixel_offset; uint16_t zs; enum agx_sr sr; - enum agx_icond icond; - enum agx_fcond fcond; enum agx_round round; enum agx_atomic_opc atomic_opc; enum agx_lod_mode lod_mode; diff --git a/src/asahi/compiler/agx_lower_pseudo.c b/src/asahi/compiler/agx_lower_pseudo.c index 093f360d851..02b9585a5fa 100644 --- a/src/asahi/compiler/agx_lower_pseudo.c +++ b/src/asahi/compiler/agx_lower_pseudo.c @@ -14,10 +14,10 @@ while_for_break_if(agx_builder *b, agx_instr *I) { if (I->op == AGX_OPCODE_BREAK_IF_FCMP) { return agx_while_fcmp(b, I->src[0], I->src[1], I->nest, I->fcond, - !I->invert_cond); + !I->invert_cond, NULL); } else { return agx_while_icmp(b, I->src[0], I->src[1], I->nest, I->icond, - !I->invert_cond); + !I->invert_cond, NULL); } } diff --git a/src/asahi/compiler/agx_opcodes.py b/src/asahi/compiler/agx_opcodes.py index 443853ea39c..b0b56205c15 100644 --- a/src/asahi/compiler/agx_opcodes.py +++ b/src/asahi/compiler/agx_opcodes.py @@ -350,7 +350,7 @@ for is_float in [False, True]: name = "{}_{}cmp".format(cf, "f" if is_float else "i") exact = 0x42 | (0x0 if is_float else 0x10) | (cf_op << 9) mask = 0x7F | (0x3 << 9) | mod_mask | (0x3 << 44) - imms = [NEST, FCOND if is_float else ICOND, INVERT_COND] + imms = [NEST, FCOND if is_float else ICOND, INVERT_COND, TARGET] op(name, (exact, mask, 6, _), dests = 0, srcs = 2, can_eliminate = False, imms = imms, is_float = is_float, @@ -426,10 +426,10 @@ op("preload", _, srcs = 1, schedule_class = "preload") # Pseudo-instructions to set the nesting counter. Lowers to r0l writes after RA. op("begin_cf", _, dests = 0, can_eliminate = False) -op("break", _, dests = 0, imms = [NEST], can_eliminate = False, +op("break", _, dests = 0, imms = [NEST, TARGET], can_eliminate = False, schedule_class = "invalid") for (name, is_float) in [("break_if_icmp", False), ("break_if_fcmp", True)]: op(name, _, dests = 0, srcs = 2, - imms = [NEST, INVERT_COND, FCOND if is_float else ICOND], + imms = [NEST, INVERT_COND, FCOND if is_float else ICOND, TARGET], can_eliminate = False, schedule_class = "invalid") diff --git a/src/asahi/compiler/agx_opt_break_if.c b/src/asahi/compiler/agx_opt_break_if.c index 473af81a84f..bcc0dc8839c 100644 --- a/src/asahi/compiler/agx_opt_break_if.c +++ b/src/asahi/compiler/agx_opt_break_if.c @@ -61,10 +61,10 @@ match_block(agx_context *ctx, agx_block *block) if (if_->op == AGX_OPCODE_IF_FCMP) { agx_break_if_fcmp(&b, if_->src[0], if_->src[1], new_nest, - if_->invert_cond, if_->fcond); + if_->invert_cond, if_->fcond, break_->target); } else { agx_break_if_icmp(&b, if_->src[0], if_->src[1], new_nest, - if_->invert_cond, if_->icond); + if_->invert_cond, if_->icond, break_->target); } agx_remove_instruction(if_); diff --git a/src/asahi/compiler/test/test-optimizer.cpp b/src/asahi/compiler/test/test-optimizer.cpp index bc0d84ed081..47fc4c8daf8 100644 --- a/src/asahi/compiler/test/test-optimizer.cpp +++ b/src/asahi/compiler/test/test-optimizer.cpp @@ -203,16 +203,16 @@ TEST_F(Optimizer, NoConversionsOn16BitALU) TEST_F(Optimizer, IfCondition) { CASE_NO_RETURN(agx_if_icmp(b, agx_icmp(b, wx, wy, AGX_ICOND_UEQ, true), - agx_zero(), 1, AGX_ICOND_UEQ, true), - agx_if_icmp(b, wx, wy, 1, AGX_ICOND_UEQ, true)); + agx_zero(), 1, AGX_ICOND_UEQ, true, NULL), + agx_if_icmp(b, wx, wy, 1, AGX_ICOND_UEQ, true, NULL)); CASE_NO_RETURN(agx_if_icmp(b, agx_fcmp(b, wx, wy, AGX_FCOND_EQ, true), - agx_zero(), 1, AGX_ICOND_UEQ, true), - agx_if_fcmp(b, wx, wy, 1, AGX_FCOND_EQ, true)); + agx_zero(), 1, AGX_ICOND_UEQ, true, NULL), + agx_if_fcmp(b, wx, wy, 1, AGX_FCOND_EQ, true, NULL)); CASE_NO_RETURN(agx_if_icmp(b, agx_fcmp(b, hx, hy, AGX_FCOND_LT, false), - agx_zero(), 1, AGX_ICOND_UEQ, true), - agx_if_fcmp(b, hx, hy, 1, AGX_FCOND_LT, false)); + agx_zero(), 1, AGX_ICOND_UEQ, true, NULL), + agx_if_fcmp(b, hx, hy, 1, AGX_FCOND_LT, false, NULL)); } TEST_F(Optimizer, SelectCondition)