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
)
55 if (inst
->qpu
.alu
.add
.output_pack
!= V3D_QPU_PACK_NONE
||
56 inst
->qpu
.alu
.mul
.output_pack
!= V3D_QPU_PACK_NONE
) {
60 if (inst
->qpu
.flags
.ac
!= V3D_QPU_COND_NONE
||
61 inst
->qpu
.flags
.mc
!= V3D_QPU_COND_NONE
) {
65 switch (inst
->src
[0].file
) {
67 /* No copy propagating from R3/R4/R5 -- the MOVs from those
68 * are there to register allocate values produced into R3/4/5
69 * to other regs (though hopefully r3/4/5).
71 switch (inst
->src
[0].index
) {
72 case V3D_QPU_WADDR_R3
:
73 case V3D_QPU_WADDR_R4
:
74 case V3D_QPU_WADDR_R5
:
82 switch (inst
->src
[0].index
) {
86 /* MOVs from rf0/1/2 are only to track the live
87 * intervals for W/centroid W/Z.
101 vir_has_unpack(struct qinst
*inst
, int chan
)
103 assert(chan
== 0 || chan
== 1);
105 if (vir_is_add(inst
)) {
107 return inst
->qpu
.alu
.add
.a_unpack
!= V3D_QPU_UNPACK_NONE
;
109 return inst
->qpu
.alu
.add
.b_unpack
!= V3D_QPU_UNPACK_NONE
;
112 return inst
->qpu
.alu
.mul
.a_unpack
!= V3D_QPU_UNPACK_NONE
;
114 return inst
->qpu
.alu
.mul
.b_unpack
!= V3D_QPU_UNPACK_NONE
;
119 try_copy_prop(struct v3d_compile
*c
, struct qinst
*inst
, struct qinst
**movs
)
122 bool progress
= false;
124 for (int i
= 0; i
< vir_get_nsrc(inst
); i
++) {
125 if (inst
->src
[i
].file
!= QFILE_TEMP
)
128 /* We have two ways of finding MOVs we can copy propagate
129 * from. One is if it's an SSA def: then we can reuse it from
130 * any block in the program, as long as its source is also an
131 * SSA def. Alternatively, if it's in the "movs" array
132 * tracked within the block, then we know the sources for it
133 * haven't been changed since we saw the instruction within
136 struct qinst
*mov
= movs
[inst
->src
[i
].index
];
138 if (!is_copy_mov(c
->defs
[inst
->src
[i
].index
]))
140 mov
= c
->defs
[inst
->src
[i
].index
];
142 if (mov
->src
[0].file
== QFILE_TEMP
&&
143 !c
->defs
[mov
->src
[0].index
])
147 if (vir_has_unpack(mov
, 0)) {
148 /* Make sure that the meaning of the unpack
149 * would be the same between the two
152 if (v3d_qpu_unpacks_f32(&inst
->qpu
) !=
153 v3d_qpu_unpacks_f32(&mov
->qpu
) ||
154 v3d_qpu_unpacks_f16(&inst
->qpu
) !=
155 v3d_qpu_unpacks_f16(&mov
->qpu
)) {
159 /* No composing the unpacks. */
160 if (vir_has_unpack(inst
, i
))
163 /* these ops can't represent abs. */
164 if (mov
->qpu
.alu
.mul
.a_unpack
== V3D_QPU_UNPACK_ABS
) {
165 switch (inst
->qpu
.alu
.add
.op
) {
166 case V3D_QPU_A_VFPACK
:
167 case V3D_QPU_A_FROUND
:
168 case V3D_QPU_A_FTRUNC
:
169 case V3D_QPU_A_FFLOOR
:
170 case V3D_QPU_A_FCEIL
:
173 case V3D_QPU_A_FTOIN
:
174 case V3D_QPU_A_FTOIZ
:
175 case V3D_QPU_A_FTOUZ
:
185 fprintf(stderr
, "Copy propagate: ");
186 vir_dump_inst(c
, inst
);
187 fprintf(stderr
, "\n");
190 inst
->src
[i
] = mov
->src
[0];
191 if (vir_has_unpack(mov
, 0)) {
192 enum v3d_qpu_input_unpack unpack
= mov
->qpu
.alu
.mul
.a_unpack
;
194 vir_set_unpack(inst
, i
, unpack
);
198 fprintf(stderr
, "to: ");
199 vir_dump_inst(c
, inst
);
200 fprintf(stderr
, "\n");
210 apply_kills(struct v3d_compile
*c
, struct qinst
**movs
, struct qinst
*inst
)
212 if (inst
->dst
.file
!= QFILE_TEMP
)
215 for (int i
= 0; i
< c
->num_temps
; i
++) {
217 (movs
[i
]->dst
.index
== inst
->dst
.index
||
218 (movs
[i
]->src
[0].file
== QFILE_TEMP
&&
219 movs
[i
]->src
[0].index
== inst
->dst
.index
))) {
226 vir_opt_copy_propagate(struct v3d_compile
*c
)
228 bool progress
= false;
231 movs
= ralloc_array(c
, struct qinst
*, c
->num_temps
);
235 vir_for_each_block(block
, c
) {
236 /* The MOVs array tracks only available movs within the
239 memset(movs
, 0, sizeof(struct qinst
*) * c
->num_temps
);
241 vir_for_each_inst(inst
, block
) {
242 progress
= try_copy_prop(c
, inst
, movs
) || progress
;
244 apply_kills(c
, movs
, inst
);
246 if (is_copy_mov(inst
))
247 movs
[inst
->dst
.index
] = inst
;