1 /*
2 * Copyright (c) 2019 Lima Project
3 *
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, sub license,
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:
10 *
11 * The above copyright notice and this permission notice (including the
12 * next paragraph) shall be included in all copies or substantial portions
13 * of the Software.
14 *
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 NON-INFRINGEMENT. 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
21 * DEALINGS IN THE SOFTWARE.
22 *
23 */
24
25 #include "ppir.h"
26
27 /* Propagates liveness from a liveness set to another by performing the
28 * union between sets. */
29 static void
ppir_liveness_propagate(ppir_compiler * comp,BITSET_WORD * dest_set,BITSET_WORD * src_set,uint8_t * dest_mask,uint8_t * src_mask)30 ppir_liveness_propagate(ppir_compiler *comp,
31 BITSET_WORD *dest_set, BITSET_WORD *src_set,
32 uint8_t *dest_mask, uint8_t *src_mask)
33 {
34 for (int i = 0; i < BITSET_WORDS(comp->reg_num); i++)
35 dest_set[i] |= src_set[i];
36
37 for (int i = 0; i < reg_mask_size(comp->reg_num); i++)
38 dest_mask[i] |= src_mask[i];
39 }
40
41 /* Check whether two liveness sets are equal. */
42 static bool
ppir_liveness_set_equal(ppir_compiler * comp,BITSET_WORD * set1,BITSET_WORD * set2,uint8_t * mask1,uint8_t * mask2)43 ppir_liveness_set_equal(ppir_compiler *comp,
44 BITSET_WORD *set1, BITSET_WORD *set2,
45 uint8_t *mask1, uint8_t *mask2)
46 {
47 for (int i = 0; i < BITSET_WORDS(comp->reg_num); i++)
48 if (set1[i] != set2[i])
49 return false;
50
51 for (int i = 0; i < reg_mask_size(comp->reg_num); i++)
52 if (mask1[i] != mask2[i])
53 return false;
54
55 return true;
56 }
57
58 /* Update the liveness information of the instruction by adding its srcs
59 * as live registers to the live_in set. */
60 static void
ppir_liveness_instr_srcs(ppir_compiler * comp,ppir_instr * instr)61 ppir_liveness_instr_srcs(ppir_compiler *comp, ppir_instr *instr)
62 {
63 for (int i = PPIR_INSTR_SLOT_NUM-1; i >= 0; i--) {
64 ppir_node *node = instr->slots[i];
65 if (!node)
66 continue;
67
68 switch(node->op) {
69 case ppir_op_const:
70 case ppir_op_undef:
71 continue;
72 default:
73 break;
74 }
75
76 for (int i = 0; i < ppir_node_get_src_num(node); i++) {
77 ppir_src *src = ppir_node_get_src(node, i);
78 if (!src || src->type == ppir_target_pipeline)
79 continue;
80
81 ppir_reg *reg = ppir_src_get_reg(src);
82 if (!reg || reg->undef)
83 continue;
84
85 unsigned int index = reg->regalloc_index;
86
87 /* if some other op on this same instruction is writing,
88 * we just need to reserve a register for this particular
89 * instruction. */
90 if (src->node && src->node->instr == instr) {
91 BITSET_SET(instr->live_internal, index);
92 continue;
93 }
94
95 bool live = BITSET_TEST(instr->live_set, index);
96 if (src->type == ppir_target_ssa) {
97 /* reg is read, needs to be live before instr */
98 if (live)
99 continue;
100
101 BITSET_SET(instr->live_set, index);
102 }
103 else {
104 unsigned int mask = ppir_src_get_mask(src);
105 uint8_t live_mask = get_reg_mask(instr->live_mask, index);
106
107 /* read reg is type register, need to check if this sets
108 * any additional bits in the current mask */
109 if (live && (live_mask == (live_mask | mask)))
110 continue;
111
112 /* some new components */
113 set_reg_mask(instr->live_mask, index, (live_mask | mask));
114 BITSET_SET(instr->live_set, index);
115 }
116 }
117 }
118 }
119
120
121 /* Update the liveness information of the instruction by removing its
122 * dests from the live_in set. */
123 static void
ppir_liveness_instr_dest(ppir_compiler * comp,ppir_instr * instr)124 ppir_liveness_instr_dest(ppir_compiler *comp, ppir_instr *instr)
125 {
126 for (int i = PPIR_INSTR_SLOT_NUM-1; i >= 0; i--) {
127 ppir_node *node = instr->slots[i];
128 if (!node)
129 continue;
130
131 switch(node->op) {
132 case ppir_op_const:
133 case ppir_op_undef:
134 continue;
135 default:
136 break;
137 }
138
139 ppir_dest *dest = ppir_node_get_dest(node);
140 if (!dest || dest->type == ppir_target_pipeline)
141 continue;
142 ppir_reg *reg = ppir_dest_get_reg(dest);
143 if (!reg || reg->undef)
144 continue;
145
146 unsigned int index = reg->regalloc_index;
147 bool live = BITSET_TEST(instr->live_set, index);
148
149 /* If a register is written but wasn't read in a later instruction, it is
150 * either dead code or a bug. For now, assign an interference to it to
151 * ensure it doesn't get assigned a live register and overwrites it. */
152 if (!live) {
153 BITSET_SET(instr->live_internal, index);
154 continue;
155 }
156
157 if (dest->type == ppir_target_ssa) {
158 /* reg is written and ssa, is not live before instr */
159 BITSET_CLEAR(instr->live_set, index);
160 }
161 else {
162 unsigned int mask = dest->write_mask;
163 uint8_t live_mask = get_reg_mask(instr->live_mask, index);
164 /* written reg is type register, need to check if this clears
165 * the remaining mask to remove it from the live set */
166 if (live_mask == (live_mask & ~mask))
167 continue;
168
169 set_reg_mask(instr->live_mask, index, (live_mask & ~mask));
170 /* unset reg if all remaining bits were cleared */
171 if ((live_mask & ~mask) == 0) {
172 BITSET_CLEAR(instr->live_set, index);
173 }
174 }
175 }
176 }
177
178 /* Main loop, iterate blocks/instructions/ops backwards, propagate
179 * livenss and update liveness of each instruction. */
180 static bool
ppir_liveness_compute_live_sets(ppir_compiler * comp)181 ppir_liveness_compute_live_sets(ppir_compiler *comp)
182 {
183 uint8_t temp_live_mask[reg_mask_size(comp->reg_num)];
184 BITSET_DECLARE(temp_live_set, comp->reg_num);
185 bool cont = false;
186 list_for_each_entry_rev(ppir_block, block, &comp->block_list, list) {
187 if (list_is_empty(&block->instr_list))
188 continue;
189
190 ppir_instr *last = list_last_entry(&block->instr_list, ppir_instr, list);
191 assert(last);
192
193 list_for_each_entry_rev(ppir_instr, instr, &block->instr_list, list) {
194 /* initial copy to check for changes */
195 memset(temp_live_mask, 0, sizeof(temp_live_mask));
196 memset(temp_live_set, 0, sizeof(temp_live_set));
197
198 ppir_liveness_propagate(comp,
199 temp_live_set, instr->live_set,
200 temp_live_mask, instr->live_mask);
201
202 /* inherit (or-) live variables from next instr or block */
203 if (instr == last) {
204 ppir_instr *next_instr;
205 /* inherit liveness from the first instruction in the next blocks */
206 for (int i = 0; i < 2; i++) {
207 ppir_block *succ = block->successors[i];
208 if (!succ)
209 continue;
210
211 /* if the block is empty, go for the next-next until a non-empty
212 * one is found */
213 while (list_is_empty(&succ->instr_list)) {
214 assert(succ->successors[0] && !succ->successors[1]);
215 succ = succ->successors[0];
216 }
217
218 next_instr = list_first_entry(&succ->instr_list, ppir_instr, list);
219 assert(next_instr);
220
221 ppir_liveness_propagate(comp,
222 instr->live_set, next_instr->live_set,
223 instr->live_mask, next_instr->live_mask);
224 }
225 }
226 else {
227 ppir_instr *next_instr = LIST_ENTRY(ppir_instr, instr->list.next, list);
228 ppir_liveness_propagate(comp,
229 instr->live_set, next_instr->live_set,
230 instr->live_mask, next_instr->live_mask);
231 }
232
233 ppir_liveness_instr_dest(comp, instr);
234 ppir_liveness_instr_srcs(comp, instr);
235
236 cont |= !ppir_liveness_set_equal(comp,
237 temp_live_set, instr->live_set,
238 temp_live_mask, instr->live_mask);
239 }
240 }
241
242 return cont;
243 }
244
245 /*
246 * Liveness analysis is based on https://en.wikipedia.org/wiki/Live_variable_analysis
247 * This implementation calculates liveness for each instruction.
248 * The liveness set in this implementation is defined as the set of
249 * registers live before the instruction executes.
250 * Blocks/instructions/ops are iterated backwards so register reads are
251 * propagated up to the instruction that writes it.
252 *
253 * 1) Before computing liveness for an instruction, propagate liveness
254 * from the next instruction. If it is the last instruction in a
255 * block, propagate liveness from all possible next instructions in
256 * the successor blocks.
257 * 2) Calculate the live set for the instruction. The initial live set
258 * is a propagated set of the live set from the next instructions.
259 * - Registers which aren't touched by this instruction are kept
260 * intact.
261 * - If a register is written by this instruction, it no longer needs
262 * to be live before the instruction, so it is removed from the live
263 * set of that instruction.
264 * - If a register is read by this instruction, it needs to be live
265 * before its execution, so add it to its live set.
266 * - Non-ssa registers are a special case. For this, the algorithm
267 * keeps and updates the mask of live components following the same
268 * logic as above. The register is only removed from the live set of
269 * the instruction when no live components are left.
270 * - If a non-ssa register is written and read in the same
271 * instruction, it stays in the live set.
272 * - Another special case is when a register is only written and read
273 * within a single instruciton. In this case a register needs to be
274 * reserved but not propagated. The algorithm adds it to the
275 * live_internal set so that the register allocator properly assigns
276 * an interference for it.
277 * 3) The algorithm must run over the entire program until it converges,
278 * i.e. a full run happens without changes. This is because blocks
279 * are updated sequentially and updates in a block may need to be
280 * propagated to parent blocks that were already calculated in the
281 * current run.
282 */
283 void
ppir_liveness_analysis(ppir_compiler * comp)284 ppir_liveness_analysis(ppir_compiler *comp)
285 {
286 while (ppir_liveness_compute_live_sets(comp))
287 ;
288 }
289