2 * Copyright © 2014 Broadcom
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
25 * @file v3d_opt_copy_propagation.c
27 * This implements simple copy propagation for VIR without control flow.
29 * For each temp, it keeps a qreg of which source it was MOVed from, if it
30 * was. If we see that used later, we can just reuse the source value, since
31 * we know we don't have control flow, and we have SSA for our values so
32 * there's no killing to worry about.
35 #include "v3d_compiler.h"
38 is_copy_mov(struct qinst
*inst
)
43 if (inst
->qpu
.type
!= V3D_QPU_INSTR_TYPE_ALU
||
44 (inst
->qpu
.alu
.mul
.op
!= V3D_QPU_M_FMOV
&&
45 inst
->qpu
.alu
.mul
.op
!= V3D_QPU_M_MOV
)) {
49 if (inst
->dst
.file
!= QFILE_TEMP
)
52 if (inst
->src
[0].file
!= QFILE_TEMP
&&
53 inst
->src
[0].file
!= QFILE_UNIF
) {
57 if (inst
->qpu
.alu
.add
.output_pack
!= V3D_QPU_PACK_NONE
||
58 inst
->qpu
.alu
.mul
.output_pack
!= V3D_QPU_PACK_NONE
) {
62 if (inst
->qpu
.flags
.ac
!= V3D_QPU_COND_NONE
||
63 inst
->qpu
.flags
.mc
!= V3D_QPU_COND_NONE
) {
67 switch (inst
->src
[0].file
) {
69 /* No copy propagating from R3/R4/R5 -- the MOVs from those
70 * are there to register allocate values produced into R3/4/5
71 * to other regs (though hopefully r3/4/5).
73 switch (inst
->src
[0].index
) {
74 case V3D_QPU_WADDR_R3
:
75 case V3D_QPU_WADDR_R4
:
76 case V3D_QPU_WADDR_R5
:
84 switch (inst
->src
[0].index
) {
88 /* MOVs from rf0/1/2 are only to track the live
89 * intervals for W/centroid W/Z.
103 vir_has_unpack(struct qinst
*inst
, int chan
)
105 assert(chan
== 0 || chan
== 1);
107 if (vir_is_add(inst
)) {
109 return inst
->qpu
.alu
.add
.a_unpack
!= V3D_QPU_UNPACK_NONE
;
111 return inst
->qpu
.alu
.add
.b_unpack
!= V3D_QPU_UNPACK_NONE
;
114 return inst
->qpu
.alu
.mul
.a_unpack
!= V3D_QPU_UNPACK_NONE
;
116 return inst
->qpu
.alu
.mul
.b_unpack
!= V3D_QPU_UNPACK_NONE
;
121 try_copy_prop(struct v3d_compile
*c
, struct qinst
*inst
, struct qinst
**movs
)
124 bool progress
= false;
126 for (int i
= 0; i
< vir_get_nsrc(inst
); i
++) {
127 if (inst
->src
[i
].file
!= QFILE_TEMP
)
130 /* We have two ways of finding MOVs we can copy propagate
131 * from. One is if it's an SSA def: then we can reuse it from
132 * any block in the program, as long as its source is also an
133 * SSA def. Alternatively, if it's in the "movs" array
134 * tracked within the block, then we know the sources for it
135 * haven't been changed since we saw the instruction within
138 struct qinst
*mov
= movs
[inst
->src
[i
].index
];
140 if (!is_copy_mov(c
->defs
[inst
->src
[i
].index
]))
142 mov
= c
->defs
[inst
->src
[i
].index
];
144 if (mov
->src
[0].file
== QFILE_TEMP
&&
145 !c
->defs
[mov
->src
[0].index
])
149 if (vir_has_unpack(mov
, 0)) {
150 /* Make sure that the meaning of the unpack
151 * would be the same between the two
154 if (v3d_qpu_unpacks_f32(&inst
->qpu
) !=
155 v3d_qpu_unpacks_f32(&mov
->qpu
) ||
156 v3d_qpu_unpacks_f16(&inst
->qpu
) !=
157 v3d_qpu_unpacks_f16(&mov
->qpu
)) {
161 /* No composing the unpacks. */
162 if (vir_has_unpack(inst
, i
))
165 /* these ops can't represent abs. */
166 if (mov
->qpu
.alu
.mul
.a_unpack
== V3D_QPU_UNPACK_ABS
) {
167 switch (inst
->qpu
.alu
.add
.op
) {
168 case V3D_QPU_A_VFPACK
:
169 case V3D_QPU_A_FROUND
:
170 case V3D_QPU_A_FTRUNC
:
171 case V3D_QPU_A_FFLOOR
:
172 case V3D_QPU_A_FCEIL
:
175 case V3D_QPU_A_FTOIN
:
176 case V3D_QPU_A_FTOIZ
:
177 case V3D_QPU_A_FTOUZ
:
187 fprintf(stderr
, "Copy propagate: ");
188 vir_dump_inst(c
, inst
);
189 fprintf(stderr
, "\n");
192 inst
->src
[i
] = mov
->src
[0];
193 if (vir_has_unpack(mov
, 0)) {
194 enum v3d_qpu_input_unpack unpack
= mov
->qpu
.alu
.mul
.a_unpack
;
196 vir_set_unpack(inst
, i
, unpack
);
200 fprintf(stderr
, "to: ");
201 vir_dump_inst(c
, inst
);
202 fprintf(stderr
, "\n");
212 apply_kills(struct v3d_compile
*c
, struct qinst
**movs
, struct qinst
*inst
)
214 if (inst
->dst
.file
!= QFILE_TEMP
)
217 for (int i
= 0; i
< c
->num_temps
; i
++) {
219 (movs
[i
]->dst
.index
== inst
->dst
.index
||
220 (movs
[i
]->src
[0].file
== QFILE_TEMP
&&
221 movs
[i
]->src
[0].index
== inst
->dst
.index
))) {
228 vir_opt_copy_propagate(struct v3d_compile
*c
)
230 bool progress
= false;
233 movs
= ralloc_array(c
, struct qinst
*, c
->num_temps
);
237 vir_for_each_block(block
, c
) {
238 /* The MOVs array tracks only available movs within the
241 memset(movs
, 0, sizeof(struct qinst
*) * c
->num_temps
);
243 vir_for_each_inst(inst
, block
) {
244 progress
= try_copy_prop(c
, inst
, movs
) || progress
;
246 apply_kills(c
, movs
, inst
);
248 if (is_copy_mov(inst
))
249 movs
[inst
->dst
.index
] = inst
;