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 vc4_opt_copy_propagation.c
27 * This implements simple copy propagation for QIR 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.
38 is_copy_mov(struct qinst
*inst
)
43 if (inst
->op
!= QOP_MOV
&&
44 inst
->op
!= QOP_FMOV
&&
45 inst
->op
!= QOP_MMOV
) {
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
->dst
.pack
|| inst
->cond
!= QPU_COND_ALWAYS
)
65 try_copy_prop(struct vc4_compile
*c
, struct qinst
*inst
, struct qinst
**movs
)
68 bool progress
= false;
70 for (int i
= 0; i
< qir_get_nsrc(inst
); i
++) {
71 if (inst
->src
[i
].file
!= QFILE_TEMP
)
74 /* We have two ways of finding MOVs we can copy propagate
75 * from. One is if it's an SSA def: then we can reuse it from
76 * any block in the program, as long as its source is also an
77 * SSA def. Alternatively, if it's in the "movs" array
78 * tracked within the block, then we know the sources for it
79 * haven't been changed since we saw the instruction within
82 struct qinst
*mov
= movs
[inst
->src
[i
].index
];
84 if (!is_copy_mov(c
->defs
[inst
->src
[i
].index
]))
86 mov
= c
->defs
[inst
->src
[i
].index
];
88 if (mov
->src
[0].file
== QFILE_TEMP
&&
89 !c
->defs
[mov
->src
[0].index
])
93 /* Mul rotation's source needs to be in an r0-r3 accumulator,
94 * so no uniforms or regfile-a/r4 unpacking allowed.
96 if (inst
->op
== QOP_ROT_MUL
&&
97 (mov
->src
[0].file
!= QFILE_TEMP
||
102 if (mov
->src
[0].pack
) {
103 /* Make sure that the meaning of the unpack
104 * would be the same between the two
107 if (qir_is_float_input(inst
) !=
108 qir_is_float_input(mov
)) {
112 /* There's only one unpack field, so make sure
113 * this instruction doesn't already use it.
115 bool already_has_unpack
= false;
116 for (int j
= 0; j
< qir_get_nsrc(inst
); j
++) {
117 if (inst
->src
[j
].pack
)
118 already_has_unpack
= true;
120 if (already_has_unpack
)
123 /* A destination pack requires the PM bit to
124 * be set to a specific value already, which
125 * may be different from ours.
130 unpack
= mov
->src
[0].pack
;
132 unpack
= inst
->src
[i
].pack
;
136 fprintf(stderr
, "Copy propagate: ");
137 qir_dump_inst(c
, inst
);
138 fprintf(stderr
, "\n");
141 inst
->src
[i
] = mov
->src
[0];
142 inst
->src
[i
].pack
= unpack
;
145 fprintf(stderr
, "to: ");
146 qir_dump_inst(c
, inst
);
147 fprintf(stderr
, "\n");
157 apply_kills(struct vc4_compile
*c
, struct qinst
**movs
, struct qinst
*inst
)
159 if (inst
->dst
.file
!= QFILE_TEMP
)
162 for (int i
= 0; i
< c
->num_temps
; i
++) {
164 (movs
[i
]->dst
.index
== inst
->dst
.index
||
165 (movs
[i
]->src
[0].file
== QFILE_TEMP
&&
166 movs
[i
]->src
[0].index
== inst
->dst
.index
))) {
173 qir_opt_copy_propagation(struct vc4_compile
*c
)
175 bool progress
= false;
178 movs
= ralloc_array(c
, struct qinst
*, c
->num_temps
);
182 qir_for_each_block(block
, c
) {
183 /* The MOVs array tracks only available movs within the
186 memset(movs
, 0, sizeof(struct qinst
*) * c
->num_temps
);
188 qir_for_each_inst(inst
, block
) {
189 progress
= try_copy_prop(c
, inst
, movs
) || progress
;
191 apply_kills(c
, movs
, inst
);
193 if (is_copy_mov(inst
))
194 movs
[inst
->dst
.index
] = inst
;