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