diff --git a/src/asahi/compiler/agx_optimizer.c b/src/asahi/compiler/agx_optimizer.c index fe9124bea79..915ebb804d6 100644 --- a/src/asahi/compiler/agx_optimizer.c +++ b/src/asahi/compiler/agx_optimizer.c @@ -321,6 +321,31 @@ agx_optimizer_if_cmp(agx_instr **defs, agx_instr *I) } } +/* + * Fuse invert into if. Acts on if_icmp and fuses: + * + * if_icmp(xor(x, 1), 0, ne) -> if_cmp(x, 0, eq) + */ +static void +agx_optimizer_if_not(agx_instr **defs, agx_instr *I) +{ + /* Check for unfused if */ + if (!agx_is_equiv(I->src[1], agx_zero()) || I->icond != AGX_ICOND_UEQ || + I->src[0].type != AGX_INDEX_NORMAL) + return; + + /* Check for invert */ + agx_instr *def = defs[I->src[0].value]; + if (def->op != AGX_OPCODE_BITOP || + !agx_is_equiv(def->src[1], agx_immediate(1)) || + def->truth_table != AGX_BITOP_XOR) + return; + + /* Fuse */ + I->src[0] = def->src[0]; + I->invert_cond = !I->invert_cond; +} + /* * Fuse conditions into select. Specifically, acts on icmpsel and fuses: * @@ -455,14 +480,17 @@ agx_optimizer_forward(agx_context *ctx) I->op != AGX_OPCODE_BLOCK_IMAGE_STORE && I->op != AGX_OPCODE_EXPORT) agx_optimizer_inline_imm(defs, I); - if (I->op == AGX_OPCODE_IF_ICMP) + if (I->op == AGX_OPCODE_IF_ICMP) { + agx_optimizer_if_not(defs, I); agx_optimizer_if_cmp(defs, I); - else if (I->op == AGX_OPCODE_ICMPSEL) + } else if (I->op == AGX_OPCODE_ICMPSEL) { agx_optimizer_cmpsel(defs, I); - else if (I->op == AGX_OPCODE_BALLOT || I->op == AGX_OPCODE_QUAD_BALLOT) + } else if (I->op == AGX_OPCODE_BALLOT || + I->op == AGX_OPCODE_QUAD_BALLOT) { agx_optimizer_ballot(ctx, defs, I); - else if (I->op == AGX_OPCODE_BITOP) + } else if (I->op == AGX_OPCODE_BITOP) { agx_optimizer_bitop(defs, I); + } } free(defs); diff --git a/src/asahi/compiler/test/test-optimizer.cpp b/src/asahi/compiler/test/test-optimizer.cpp index 7f060db2737..4dbca759cf0 100644 --- a/src/asahi/compiler/test/test-optimizer.cpp +++ b/src/asahi/compiler/test/test-optimizer.cpp @@ -353,3 +353,15 @@ TEST_F(Optimizer, SelectCondition) agx_zero(), wz, wx, AGX_ICOND_UEQ), agx_fcmpsel_to(b, out, wx, wy, wz, wx, AGX_FCOND_LT)); } + +TEST_F(Optimizer, IfInverted) +{ + CASE_NO_RETURN( + agx_if_icmp(b, agx_xor(b, hx, agx_immediate(1)), agx_zero(), 1, + AGX_ICOND_UEQ, true, NULL), + agx_if_icmp(b, hx, agx_zero(), 1, AGX_ICOND_UEQ, false, NULL)); + + CASE_NO_RETURN(agx_if_icmp(b, agx_xor(b, hx, agx_immediate(1)), agx_zero(), + 1, AGX_ICOND_UEQ, false, NULL), + agx_if_icmp(b, hx, agx_zero(), 1, AGX_ICOND_UEQ, true, NULL)); +}