1/* 2 * Copyright (C) 2021 Alyssa Rosenzweig 3 * Copyright (C) 2019-2020 Collabora, Ltd. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 * and/or sell copies of the Software, and to permit persons to whom the 10 * Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice (including the next 13 * paragraph) shall be included in all copies or substantial portions of the 14 * Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 * SOFTWARE. 23 */ 24 25#include "agx_compiler.h" 26#include "util/u_memory.h" 27#include "util/list.h" 28#include "util/set.h" 29 30/* Liveness analysis is a backwards-may dataflow analysis pass. Within a block, 31 * we compute live_out from live_in. The intrablock pass is linear-time. It 32 * returns whether progress was made. */ 33 34/* live_in[s] = GEN[s] + (live_out[s] - KILL[s]) */ 35 36void 37agx_liveness_ins_update(BITSET_WORD *live, agx_instr *I) 38{ 39 agx_foreach_dest(I, d) { 40 if (I->dest[d].type == AGX_INDEX_NORMAL) 41 BITSET_CLEAR(live, I->dest[d].value); 42 } 43 44 agx_foreach_src(I, s) { 45 if (I->src[s].type == AGX_INDEX_NORMAL) { 46 /* If the source is not live after this instruction, but becomes live 47 * at this instruction, this is the use that kills the source */ 48 I->src[s].kill = !BITSET_TEST(live, I->src[s].value); 49 BITSET_SET(live, I->src[s].value); 50 } 51 } 52} 53 54/* Globally, liveness analysis uses a fixed-point algorithm based on a 55 * worklist. We initialize a work list with the exit block. We iterate the work 56 * list to compute live_in from live_out for each block on the work list, 57 * adding the predecessors of the block to the work list if we made progress. 58 */ 59 60void 61agx_compute_liveness(agx_context *ctx) 62{ 63 u_worklist worklist; 64 u_worklist_init(&worklist, ctx->num_blocks, NULL); 65 66 /* Free any previous liveness, and allocate */ 67 unsigned words = BITSET_WORDS(ctx->alloc); 68 69 agx_foreach_block(ctx, block) { 70 if (block->live_in) 71 ralloc_free(block->live_in); 72 73 if (block->live_out) 74 ralloc_free(block->live_out); 75 76 block->live_in = rzalloc_array(block, BITSET_WORD, words); 77 block->live_out = rzalloc_array(block, BITSET_WORD, words); 78 79 agx_worklist_push_head(&worklist, block); 80 } 81 82 /* Iterate the work list */ 83 while(!u_worklist_is_empty(&worklist)) { 84 /* Pop in reverse order since liveness is a backwards pass */ 85 agx_block *blk = agx_worklist_pop_head(&worklist); 86 87 /* Update its liveness information */ 88 memcpy(blk->live_in, blk->live_out, words * sizeof(BITSET_WORD)); 89 90 agx_foreach_instr_in_block_rev(blk, I) { 91 /* Phi nodes are handled separately, so we skip them. As phi nodes are at 92 * the beginning and we're iterating backwards, we stop as soon as we hit 93 * a phi node. 94 */ 95 if (I->op == AGX_OPCODE_PHI) 96 break; 97 98 agx_liveness_ins_update(blk->live_in, I); 99 } 100 101 /* Propagate the live in of the successor (blk) to the live out of 102 * predecessors. 103 * 104 * Phi nodes are logically on the control flow edge and act in parallel. To 105 * handle when propagating, we kill writes from phis and make live the 106 * corresponding sources. 107 */ 108 agx_foreach_predecessor(blk, pred) { 109 BITSET_WORD *live = ralloc_array(blk, BITSET_WORD, words); 110 memcpy(live, blk->live_in, words * sizeof(BITSET_WORD)); 111 112 /* Kill write */ 113 agx_foreach_instr_in_block(blk, I) { 114 if (I->op != AGX_OPCODE_PHI) break; 115 116 assert(I->dest[0].type == AGX_INDEX_NORMAL); 117 BITSET_CLEAR(live, I->dest[0].value); 118 } 119 120 /* Make live the corresponding source */ 121 agx_foreach_instr_in_block(blk, I) { 122 if (I->op != AGX_OPCODE_PHI) break; 123 124 agx_index operand = I->src[agx_predecessor_index(blk, *pred)]; 125 assert(operand.type == AGX_INDEX_NORMAL); 126 BITSET_SET(live, operand.value); 127 } 128 129 bool progress = false; 130 131 for (unsigned i = 0; i < words; ++i) { 132 progress |= live[i] & ~((*pred)->live_out[i]); 133 (*pred)->live_out[i] |= live[i]; 134 } 135 136 if (progress) 137 agx_worklist_push_tail(&worklist, *pred); 138 } 139 } 140 141 u_worklist_fini(&worklist); 142} 143