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