Path: blob/21.2-virgl/src/gallium/drivers/etnaviv/etnaviv_compiler_nir_liveness.c
4570 views
/*1* Copyright (c) 2019 Zodiac Inflight Innovations2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* the rights to use, copy, modify, merge, publish, distribute, sub license,7* and/or sell copies of the Software, and to permit persons to whom the8* Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice (including the11* next paragraph) shall be included in all copies or substantial portions12* of the Software.13*14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL17* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER18* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING19* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER20* DEALINGS IN THE SOFTWARE.21*22* Authors:23* Jonathan Marek <[email protected]>24*/2526#include "etnaviv_compiler_nir.h"27#include "compiler/nir/nir_worklist.h"2829static void30range_include(struct live_def *def, unsigned index)31{32if (def->live_start > index)33def->live_start = index;34if (def->live_end < index)35def->live_end = index;36}3738struct live_defs_state {39unsigned num_defs;40unsigned bitset_words;4142nir_function_impl *impl;43nir_block *block; /* current block pointer */44unsigned index; /* current live index */4546struct live_def *defs;47unsigned *live_map; /* to map ssa/reg index into defs array */4849nir_block_worklist worklist;50};5152static bool53init_liveness_block(nir_block *block,54struct live_defs_state *state)55{56block->live_in = reralloc(block, block->live_in, BITSET_WORD,57state->bitset_words);58memset(block->live_in, 0, state->bitset_words * sizeof(BITSET_WORD));5960block->live_out = reralloc(block, block->live_out, BITSET_WORD,61state->bitset_words);62memset(block->live_out, 0, state->bitset_words * sizeof(BITSET_WORD));6364nir_block_worklist_push_head(&state->worklist, block);6566return true;67}6869static bool70set_src_live(nir_src *src, void *void_state)71{72struct live_defs_state *state = void_state;7374if (src->is_ssa) {75nir_instr *instr = src->ssa->parent_instr;7677if (is_sysval(instr) || instr->type == nir_instr_type_deref)78return true;7980switch (instr->type) {81case nir_instr_type_load_const:82case nir_instr_type_ssa_undef:83return true;84case nir_instr_type_alu: {85/* alu op bypass */86nir_alu_instr *alu = nir_instr_as_alu(instr);87if (instr->pass_flags & BYPASS_SRC) {88for (unsigned i = 0; i < nir_op_infos[alu->op].num_inputs; i++)89set_src_live(&alu->src[i].src, state);90return true;91}92} break;93default:94break;95}96}9798unsigned i = state->live_map[src_index(state->impl, src)];99assert(i != ~0u);100101BITSET_SET(state->block->live_in, i);102range_include(&state->defs[i], state->index);103104return true;105}106107static bool108propagate_across_edge(nir_block *pred, nir_block *succ,109struct live_defs_state *state)110{111BITSET_WORD progress = 0;112for (unsigned i = 0; i < state->bitset_words; ++i) {113progress |= succ->live_in[i] & ~pred->live_out[i];114pred->live_out[i] |= succ->live_in[i];115}116return progress != 0;117}118119unsigned120etna_live_defs(nir_function_impl *impl, struct live_def *defs, unsigned *live_map)121{122struct live_defs_state state;123unsigned block_live_index[impl->num_blocks + 1];124125state.impl = impl;126state.defs = defs;127state.live_map = live_map;128129state.num_defs = 0;130nir_foreach_block(block, impl) {131block_live_index[block->index] = state.num_defs;132nir_foreach_instr(instr, block) {133nir_dest *dest = dest_for_instr(instr);134if (!dest)135continue;136137unsigned idx = dest_index(impl, dest);138/* register is already in defs */139if (live_map[idx] != ~0u)140continue;141142defs[state.num_defs] = (struct live_def) {instr, dest, state.num_defs, 0};143144/* input live from the start */145if (instr->type == nir_instr_type_intrinsic) {146nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);147if (intr->intrinsic == nir_intrinsic_load_input ||148intr->intrinsic == nir_intrinsic_load_instance_id)149defs[state.num_defs].live_start = 0;150}151152live_map[idx] = state.num_defs;153state.num_defs++;154}155}156block_live_index[impl->num_blocks] = state.num_defs;157158nir_block_worklist_init(&state.worklist, impl->num_blocks, NULL);159160/* We now know how many unique ssa definitions we have and we can go161* ahead and allocate live_in and live_out sets and add all of the162* blocks to the worklist.163*/164state.bitset_words = BITSET_WORDS(state.num_defs);165nir_foreach_block(block, impl) {166init_liveness_block(block, &state);167}168169/* We're now ready to work through the worklist and update the liveness170* sets of each of the blocks. By the time we get to this point, every171* block in the function implementation has been pushed onto the172* worklist in reverse order. As long as we keep the worklist173* up-to-date as we go, everything will get covered.174*/175while (!nir_block_worklist_is_empty(&state.worklist)) {176/* We pop them off in the reverse order we pushed them on. This way177* the first walk of the instructions is backwards so we only walk178* once in the case of no control flow.179*/180nir_block *block = nir_block_worklist_pop_head(&state.worklist);181state.block = block;182183memcpy(block->live_in, block->live_out,184state.bitset_words * sizeof(BITSET_WORD));185186state.index = block_live_index[block->index + 1];187188nir_if *following_if = nir_block_get_following_if(block);189if (following_if)190set_src_live(&following_if->condition, &state);191192nir_foreach_instr_reverse(instr, block) {193/* when we come across the next "live" instruction, decrement index */194if (state.index && instr == defs[state.index - 1].instr) {195state.index--;196/* the only source of writes to registers is phis:197* we don't expect any partial write_mask alus198* so clearing live_in here is OK199*/200BITSET_CLEAR(block->live_in, state.index);201}202203/* don't set_src_live for not-emitted instructions */204if (instr->pass_flags)205continue;206207unsigned index = state.index;208209/* output live till the end */210if (instr->type == nir_instr_type_intrinsic) {211nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);212if (intr->intrinsic == nir_intrinsic_store_deref)213state.index = ~0u;214}215216nir_foreach_src(instr, set_src_live, &state);217218state.index = index;219}220assert(state.index == block_live_index[block->index]);221222/* Walk over all of the predecessors of the current block updating223* their live in with the live out of this one. If anything has224* changed, add the predecessor to the work list so that we ensure225* that the new information is used.226*/227set_foreach(block->predecessors, entry) {228nir_block *pred = (nir_block *)entry->key;229if (propagate_across_edge(pred, block, &state))230nir_block_worklist_push_tail(&state.worklist, pred);231}232}233234nir_block_worklist_fini(&state.worklist);235236/* apply live_in/live_out to ranges */237238nir_foreach_block(block, impl) {239int i;240241BITSET_FOREACH_SET(i, block->live_in, state.num_defs)242range_include(&state.defs[i], block_live_index[block->index]);243244BITSET_FOREACH_SET(i, block->live_out, state.num_defs)245range_include(&state.defs[i], block_live_index[block->index + 1]);246}247248return state.num_defs;249}250251252