Path: blob/21.2-virgl/src/panfrost/util/pan_liveness.c
4560 views
/*1* Copyright (C) 2019-2020 Collabora, Ltd.2*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, sublicense,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 the next11* paragraph) shall be included in all copies or substantial portions of the12* 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 NONINFRINGEMENT. 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, ARISING FROM,19* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE20* SOFTWARE.21*/2223#include "pan_ir.h"24#include "util/u_memory.h"25#include "util/list.h"26#include "util/set.h"2728/* Routines for liveness analysis. Liveness is tracked per byte per node. Per29* byte granularity is necessary for proper handling of int8 */3031void32pan_liveness_gen(uint16_t *live, unsigned node, unsigned max, uint16_t mask)33{34if (node >= max)35return;3637live[node] |= mask;38}3940void41pan_liveness_kill(uint16_t *live, unsigned node, unsigned max, uint16_t mask)42{43if (node >= max)44return;4546live[node] &= ~mask;47}4849bool50pan_liveness_get(uint16_t *live, unsigned node, uint16_t max)51{52if (node >= max)53return false;5455return live[node];56}5758/* live_out[s] = sum { p in succ[s] } ( live_in[p] ) */5960static void61liveness_block_live_out(pan_block *blk, unsigned temp_count)62{63pan_foreach_successor(blk, succ) {64for (unsigned i = 0; i < temp_count; ++i)65blk->live_out[i] |= succ->live_in[i];66}67}6869/* Liveness analysis is a backwards-may dataflow analysis pass. Within a block,70* we compute live_out from live_in. The intrablock pass is linear-time. It71* returns whether progress was made. */7273static bool74liveness_block_update(75pan_block *blk, unsigned temp_count,76pan_liveness_update callback)77{78bool progress = false;7980liveness_block_live_out(blk, temp_count);8182uint16_t *live = ralloc_array(blk, uint16_t, temp_count);83memcpy(live, blk->live_out, temp_count * sizeof(uint16_t));8485pan_foreach_instr_in_block_rev(blk, ins)86callback(live, (void *) ins, temp_count);8788/* To figure out progress, diff live_in */8990for (unsigned i = 0; (i < temp_count) && !progress; ++i)91progress |= (blk->live_in[i] != live[i]);9293ralloc_free(blk->live_in);94blk->live_in = live;9596return progress;97}9899100/* Globally, liveness analysis uses a fixed-point algorithm based on a101* worklist. We initialize a work list with the exit block. We iterate the work102* list to compute live_in from live_out for each block on the work list,103* adding the predecessors of the block to the work list if we made progress.104*/105106void107pan_compute_liveness(108struct list_head *blocks,109unsigned temp_count,110pan_liveness_update callback)111{112113/* Set of pan_block */114struct set *work_list = _mesa_set_create(NULL,115_mesa_hash_pointer,116_mesa_key_pointer_equal);117118struct set *visited = _mesa_set_create(NULL,119_mesa_hash_pointer,120_mesa_key_pointer_equal);121122/* Free any previous liveness, and allocate */123124pan_free_liveness(blocks);125126list_for_each_entry(pan_block, block, blocks, link) {127block->live_in = rzalloc_array(block, uint16_t, temp_count);128block->live_out = rzalloc_array(block, uint16_t, temp_count);129}130131/* Initialize the work list with the exit block */132struct set_entry *cur;133134cur = _mesa_set_add(work_list, pan_exit_block(blocks));135136/* Iterate the work list */137138do {139/* Pop off a block */140pan_block *blk = (struct pan_block *) cur->key;141_mesa_set_remove(work_list, cur);142143/* Update its liveness information */144bool progress = liveness_block_update(blk, temp_count, callback);145146/* If we made progress, we need to process the predecessors */147148if (progress || !_mesa_set_search(visited, blk)) {149pan_foreach_predecessor(blk, pred)150_mesa_set_add(work_list, pred);151}152153_mesa_set_add(visited, blk);154} while((cur = _mesa_set_next_entry(work_list, NULL)) != NULL);155156_mesa_set_destroy(visited, NULL);157_mesa_set_destroy(work_list, NULL);158}159160void161pan_free_liveness(struct list_head *blocks)162{163list_for_each_entry(pan_block, block, blocks, link) {164if (block->live_in)165ralloc_free(block->live_in);166167if (block->live_out)168ralloc_free(block->live_out);169170block->live_in = NULL;171block->live_out = NULL;172}173}174175176