xref: /aosp_15_r20/external/mesa3d/src/freedreno/ir3/ir3_cf.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1*61046927SAndroid Build Coastguard Worker /*
2*61046927SAndroid Build Coastguard Worker  * Copyright © 2019 Google.
3*61046927SAndroid Build Coastguard Worker  * SPDX-License-Identifier: MIT
4*61046927SAndroid Build Coastguard Worker  */
5*61046927SAndroid Build Coastguard Worker 
6*61046927SAndroid Build Coastguard Worker #include "util/ralloc.h"
7*61046927SAndroid Build Coastguard Worker 
8*61046927SAndroid Build Coastguard Worker #include "ir3.h"
9*61046927SAndroid Build Coastguard Worker 
10*61046927SAndroid Build Coastguard Worker static bool
is_safe_conv(struct ir3_instruction * instr,type_t src_type,opc_t * src_opc)11*61046927SAndroid Build Coastguard Worker is_safe_conv(struct ir3_instruction *instr, type_t src_type, opc_t *src_opc)
12*61046927SAndroid Build Coastguard Worker {
13*61046927SAndroid Build Coastguard Worker    if (instr->opc != OPC_MOV)
14*61046927SAndroid Build Coastguard Worker       return false;
15*61046927SAndroid Build Coastguard Worker 
16*61046927SAndroid Build Coastguard Worker    /* Only allow half->full or full->half without any type conversion (like
17*61046927SAndroid Build Coastguard Worker     * int to float).
18*61046927SAndroid Build Coastguard Worker     */
19*61046927SAndroid Build Coastguard Worker    if (type_size(instr->cat1.src_type) == type_size(instr->cat1.dst_type) ||
20*61046927SAndroid Build Coastguard Worker        full_type(instr->cat1.src_type) != full_type(instr->cat1.dst_type))
21*61046927SAndroid Build Coastguard Worker       return false;
22*61046927SAndroid Build Coastguard Worker 
23*61046927SAndroid Build Coastguard Worker    /* mul.s24/u24 always return 32b result regardless of its sources size,
24*61046927SAndroid Build Coastguard Worker     * hence we cannot guarantee the high 16b of dst being zero or sign extended.
25*61046927SAndroid Build Coastguard Worker     */
26*61046927SAndroid Build Coastguard Worker    if ((*src_opc == OPC_MUL_S24 || *src_opc == OPC_MUL_U24) &&
27*61046927SAndroid Build Coastguard Worker        type_size(instr->cat1.src_type) == 16)
28*61046927SAndroid Build Coastguard Worker       return false;
29*61046927SAndroid Build Coastguard Worker 
30*61046927SAndroid Build Coastguard Worker    struct ir3_register *dst = instr->dsts[0];
31*61046927SAndroid Build Coastguard Worker    struct ir3_register *src = instr->srcs[0];
32*61046927SAndroid Build Coastguard Worker 
33*61046927SAndroid Build Coastguard Worker    /* disallow conversions that cannot be folded into
34*61046927SAndroid Build Coastguard Worker     * alu instructions:
35*61046927SAndroid Build Coastguard Worker     */
36*61046927SAndroid Build Coastguard Worker    if (instr->cat1.round != ROUND_ZERO)
37*61046927SAndroid Build Coastguard Worker       return false;
38*61046927SAndroid Build Coastguard Worker 
39*61046927SAndroid Build Coastguard Worker    if (dst->flags & (IR3_REG_RELATIV | IR3_REG_ARRAY))
40*61046927SAndroid Build Coastguard Worker       return false;
41*61046927SAndroid Build Coastguard Worker    if (src->flags & (IR3_REG_RELATIV | IR3_REG_ARRAY))
42*61046927SAndroid Build Coastguard Worker       return false;
43*61046927SAndroid Build Coastguard Worker 
44*61046927SAndroid Build Coastguard Worker    /* Check that the source of the conv matches the type of the src
45*61046927SAndroid Build Coastguard Worker     * instruction.
46*61046927SAndroid Build Coastguard Worker     */
47*61046927SAndroid Build Coastguard Worker    if (src_type == instr->cat1.src_type)
48*61046927SAndroid Build Coastguard Worker       return true;
49*61046927SAndroid Build Coastguard Worker 
50*61046927SAndroid Build Coastguard Worker    /* We can handle mismatches with integer types by converting the opcode
51*61046927SAndroid Build Coastguard Worker     * but not when an integer is reinterpreted as a float or vice-versa.
52*61046927SAndroid Build Coastguard Worker     */
53*61046927SAndroid Build Coastguard Worker    if (type_float(src_type) != type_float(instr->cat1.src_type))
54*61046927SAndroid Build Coastguard Worker       return false;
55*61046927SAndroid Build Coastguard Worker 
56*61046927SAndroid Build Coastguard Worker    /* We have types with mismatched signedness. Mismatches on the signedness
57*61046927SAndroid Build Coastguard Worker     * don't matter when narrowing:
58*61046927SAndroid Build Coastguard Worker     */
59*61046927SAndroid Build Coastguard Worker    if (type_size(instr->cat1.dst_type) < type_size(instr->cat1.src_type))
60*61046927SAndroid Build Coastguard Worker       return true;
61*61046927SAndroid Build Coastguard Worker 
62*61046927SAndroid Build Coastguard Worker    /* Try swapping the opcode: */
63*61046927SAndroid Build Coastguard Worker    bool can_swap = true;
64*61046927SAndroid Build Coastguard Worker    *src_opc = ir3_try_swap_signedness(*src_opc, &can_swap);
65*61046927SAndroid Build Coastguard Worker    return can_swap;
66*61046927SAndroid Build Coastguard Worker }
67*61046927SAndroid Build Coastguard Worker 
68*61046927SAndroid Build Coastguard Worker static bool
all_uses_safe_conv(struct ir3_instruction * conv_src,type_t src_type)69*61046927SAndroid Build Coastguard Worker all_uses_safe_conv(struct ir3_instruction *conv_src, type_t src_type)
70*61046927SAndroid Build Coastguard Worker {
71*61046927SAndroid Build Coastguard Worker    opc_t opc = conv_src->opc;
72*61046927SAndroid Build Coastguard Worker    bool first = true;
73*61046927SAndroid Build Coastguard Worker    foreach_ssa_use (use, conv_src) {
74*61046927SAndroid Build Coastguard Worker       opc_t new_opc = opc;
75*61046927SAndroid Build Coastguard Worker       if (!is_safe_conv(use, src_type, &new_opc))
76*61046927SAndroid Build Coastguard Worker          return false;
77*61046927SAndroid Build Coastguard Worker       /* Check if multiple uses have conflicting requirements on the opcode.
78*61046927SAndroid Build Coastguard Worker        */
79*61046927SAndroid Build Coastguard Worker       if (!first && opc != new_opc)
80*61046927SAndroid Build Coastguard Worker          return false;
81*61046927SAndroid Build Coastguard Worker       first = false;
82*61046927SAndroid Build Coastguard Worker       opc = new_opc;
83*61046927SAndroid Build Coastguard Worker    }
84*61046927SAndroid Build Coastguard Worker    conv_src->opc = opc;
85*61046927SAndroid Build Coastguard Worker    return true;
86*61046927SAndroid Build Coastguard Worker }
87*61046927SAndroid Build Coastguard Worker 
88*61046927SAndroid Build Coastguard Worker /* For an instruction which has a conversion folded in, re-write the
89*61046927SAndroid Build Coastguard Worker  * uses of *all* conv's that used that src to be a simple mov that
90*61046927SAndroid Build Coastguard Worker  * cp can eliminate.  This avoids invalidating the SSA uses, it just
91*61046927SAndroid Build Coastguard Worker  * shifts the use to a simple mov.
92*61046927SAndroid Build Coastguard Worker  */
93*61046927SAndroid Build Coastguard Worker static void
rewrite_src_uses(struct ir3_instruction * src)94*61046927SAndroid Build Coastguard Worker rewrite_src_uses(struct ir3_instruction *src)
95*61046927SAndroid Build Coastguard Worker {
96*61046927SAndroid Build Coastguard Worker    foreach_ssa_use (use, src) {
97*61046927SAndroid Build Coastguard Worker       assert(use->opc == OPC_MOV);
98*61046927SAndroid Build Coastguard Worker 
99*61046927SAndroid Build Coastguard Worker       if (is_half(src)) {
100*61046927SAndroid Build Coastguard Worker          use->srcs[0]->flags |= IR3_REG_HALF;
101*61046927SAndroid Build Coastguard Worker       } else {
102*61046927SAndroid Build Coastguard Worker          use->srcs[0]->flags &= ~IR3_REG_HALF;
103*61046927SAndroid Build Coastguard Worker       }
104*61046927SAndroid Build Coastguard Worker 
105*61046927SAndroid Build Coastguard Worker       use->cat1.src_type = use->cat1.dst_type;
106*61046927SAndroid Build Coastguard Worker    }
107*61046927SAndroid Build Coastguard Worker }
108*61046927SAndroid Build Coastguard Worker 
109*61046927SAndroid Build Coastguard Worker static bool
try_conversion_folding(struct ir3_instruction * conv)110*61046927SAndroid Build Coastguard Worker try_conversion_folding(struct ir3_instruction *conv)
111*61046927SAndroid Build Coastguard Worker {
112*61046927SAndroid Build Coastguard Worker    struct ir3_instruction *src;
113*61046927SAndroid Build Coastguard Worker 
114*61046927SAndroid Build Coastguard Worker    if (conv->opc != OPC_MOV)
115*61046927SAndroid Build Coastguard Worker       return false;
116*61046927SAndroid Build Coastguard Worker 
117*61046927SAndroid Build Coastguard Worker    /* Don't fold in conversions to/from shared */
118*61046927SAndroid Build Coastguard Worker    if ((conv->srcs[0]->flags & IR3_REG_SHARED) !=
119*61046927SAndroid Build Coastguard Worker        (conv->dsts[0]->flags & IR3_REG_SHARED))
120*61046927SAndroid Build Coastguard Worker       return false;
121*61046927SAndroid Build Coastguard Worker 
122*61046927SAndroid Build Coastguard Worker    /* NOTE: we can have non-ssa srcs after copy propagation: */
123*61046927SAndroid Build Coastguard Worker    src = ssa(conv->srcs[0]);
124*61046927SAndroid Build Coastguard Worker    if (!src)
125*61046927SAndroid Build Coastguard Worker       return false;
126*61046927SAndroid Build Coastguard Worker 
127*61046927SAndroid Build Coastguard Worker    if (!is_alu(src))
128*61046927SAndroid Build Coastguard Worker       return false;
129*61046927SAndroid Build Coastguard Worker 
130*61046927SAndroid Build Coastguard Worker    bool can_fold;
131*61046927SAndroid Build Coastguard Worker    type_t base_type = ir3_output_conv_type(src, &can_fold);
132*61046927SAndroid Build Coastguard Worker    if (!can_fold)
133*61046927SAndroid Build Coastguard Worker       return false;
134*61046927SAndroid Build Coastguard Worker 
135*61046927SAndroid Build Coastguard Worker    type_t src_type = ir3_output_conv_src_type(src, base_type);
136*61046927SAndroid Build Coastguard Worker    type_t dst_type = ir3_output_conv_dst_type(src, base_type);
137*61046927SAndroid Build Coastguard Worker 
138*61046927SAndroid Build Coastguard Worker    /* Avoid cases where we've already folded in a conversion. We assume that
139*61046927SAndroid Build Coastguard Worker     * if there is a chain of conversions that's foldable then it's been
140*61046927SAndroid Build Coastguard Worker     * folded in NIR already.
141*61046927SAndroid Build Coastguard Worker     */
142*61046927SAndroid Build Coastguard Worker    if (src_type != dst_type)
143*61046927SAndroid Build Coastguard Worker       return false;
144*61046927SAndroid Build Coastguard Worker 
145*61046927SAndroid Build Coastguard Worker    if (!all_uses_safe_conv(src, src_type))
146*61046927SAndroid Build Coastguard Worker       return false;
147*61046927SAndroid Build Coastguard Worker 
148*61046927SAndroid Build Coastguard Worker    ir3_set_dst_type(src, is_half(conv));
149*61046927SAndroid Build Coastguard Worker    rewrite_src_uses(src);
150*61046927SAndroid Build Coastguard Worker 
151*61046927SAndroid Build Coastguard Worker    return true;
152*61046927SAndroid Build Coastguard Worker }
153*61046927SAndroid Build Coastguard Worker 
154*61046927SAndroid Build Coastguard Worker bool
ir3_cf(struct ir3 * ir)155*61046927SAndroid Build Coastguard Worker ir3_cf(struct ir3 *ir)
156*61046927SAndroid Build Coastguard Worker {
157*61046927SAndroid Build Coastguard Worker    void *mem_ctx = ralloc_context(NULL);
158*61046927SAndroid Build Coastguard Worker    bool progress = false;
159*61046927SAndroid Build Coastguard Worker 
160*61046927SAndroid Build Coastguard Worker    ir3_find_ssa_uses(ir, mem_ctx, false);
161*61046927SAndroid Build Coastguard Worker 
162*61046927SAndroid Build Coastguard Worker    foreach_block (block, &ir->block_list) {
163*61046927SAndroid Build Coastguard Worker       foreach_instr (instr, &block->instr_list) {
164*61046927SAndroid Build Coastguard Worker          progress |= try_conversion_folding(instr);
165*61046927SAndroid Build Coastguard Worker       }
166*61046927SAndroid Build Coastguard Worker    }
167*61046927SAndroid Build Coastguard Worker 
168*61046927SAndroid Build Coastguard Worker    ralloc_free(mem_ctx);
169*61046927SAndroid Build Coastguard Worker 
170*61046927SAndroid Build Coastguard Worker    return progress;
171*61046927SAndroid Build Coastguard Worker }
172