xref: /aosp_15_r20/external/mesa3d/src/asahi/compiler/agx_lower_pseudo.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Copyright 2022 Alyssa Rosenzweig
3  * SPDX-License-Identifier: MIT
4  */
5 
6 #include "agx_builder.h"
7 #include "agx_compiler.h"
8 #include "agx_opcodes.h"
9 
10 /* Lower pseudo instructions created during optimization. */
11 
12 static agx_instr *
while_for_break_if(agx_builder * b,agx_instr * I)13 while_for_break_if(agx_builder *b, agx_instr *I)
14 {
15    if (I->op == AGX_OPCODE_BREAK_IF_FCMP) {
16       return agx_while_fcmp(b, I->src[0], I->src[1], I->nest, I->fcond,
17                             !I->invert_cond, NULL);
18    } else {
19       return agx_while_icmp(b, I->src[0], I->src[1], I->nest, I->icond,
20                             !I->invert_cond, NULL);
21    }
22 }
23 
24 static agx_instr *
cmpsel_for_break_if(agx_builder * b,agx_instr * I)25 cmpsel_for_break_if(agx_builder *b, agx_instr *I)
26 {
27    agx_index r0l = agx_register(0, AGX_SIZE_16);
28 
29    /* If the condition is true, set r0l to nest to break */
30    agx_index t = agx_immediate(I->nest);
31    agx_index f = r0l;
32 
33    if (I->invert_cond) {
34       agx_index temp = t;
35       t = f;
36       f = temp;
37    }
38 
39    if (I->op == AGX_OPCODE_BREAK_IF_FCMP)
40       agx_fcmpsel_to(b, r0l, I->src[0], I->src[1], t, f, I->fcond);
41    else
42       agx_icmpsel_to(b, r0l, I->src[0], I->src[1], t, f, I->icond);
43 
44    return agx_push_exec(b, 0);
45 }
46 
47 static agx_instr *
lower(agx_builder * b,agx_instr * I)48 lower(agx_builder *b, agx_instr *I)
49 {
50    switch (I->op) {
51 
52    /* Various instructions are implemented as bitwise truth tables */
53    case AGX_OPCODE_MOV:
54       return agx_bitop_to(b, I->dest[0], I->src[0], agx_zero(), AGX_BITOP_MOV);
55 
56    case AGX_OPCODE_NOT:
57       return agx_bitop_to(b, I->dest[0], I->src[0], agx_zero(), AGX_BITOP_NOT);
58 
59    /* Unfused comparisons are fused with a 0/1 select */
60    case AGX_OPCODE_ICMP:
61       return agx_icmpsel_to(b, I->dest[0], I->src[0], I->src[1],
62                             agx_immediate(I->invert_cond ? 0 : 1),
63                             agx_immediate(I->invert_cond ? 1 : 0), I->icond);
64 
65    case AGX_OPCODE_FCMP:
66       return agx_fcmpsel_to(b, I->dest[0], I->src[0], I->src[1],
67                             agx_immediate(I->invert_cond ? 0 : 1),
68                             agx_immediate(I->invert_cond ? 1 : 0), I->fcond);
69 
70    case AGX_OPCODE_BALLOT:
71       return agx_icmp_ballot_to(b, I->dest[0], I->src[0], agx_zero(),
72                                 AGX_ICOND_UEQ, true /* invert */);
73 
74    case AGX_OPCODE_QUAD_BALLOT:
75       return agx_icmp_quad_ballot_to(b, I->dest[0], I->src[0], agx_zero(),
76                                      AGX_ICOND_UEQ, true /* invert */);
77 
78    /* Writes to the nesting counter lowered to the real register */
79    case AGX_OPCODE_BEGIN_CF:
80       return agx_mov_imm_to(b, agx_register(0, AGX_SIZE_16), 0);
81 
82    case AGX_OPCODE_BREAK:
83       agx_mov_imm_to(b, agx_register(0, AGX_SIZE_16), I->nest);
84       return agx_pop_exec(b, 0);
85 
86    case AGX_OPCODE_BREAK_IF_ICMP:
87    case AGX_OPCODE_BREAK_IF_FCMP: {
88       if (I->nest == 1)
89          return while_for_break_if(b, I);
90       else
91          return cmpsel_for_break_if(b, I);
92    }
93 
94    case AGX_OPCODE_EXPORT:
95       /* We already lowered exports during RA, we just need to remove them late
96        * after inserting waits.
97        */
98       return (void *)true;
99 
100    default:
101       return NULL;
102    }
103 }
104 
105 void
agx_lower_pseudo(agx_context * ctx)106 agx_lower_pseudo(agx_context *ctx)
107 {
108    agx_foreach_instr_global_safe(ctx, I) {
109       agx_builder b = agx_init_builder(ctx, agx_before_instr(I));
110 
111       if (lower(&b, I))
112          agx_remove_instruction(I);
113    }
114 }
115