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