1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright (C) 2021 Valve Corporation 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, sublicense, 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 next 12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 13bf215546Sopenharmony_ci * 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 NONINFRINGEMENT. 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 FROM, 20bf215546Sopenharmony_ci * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21bf215546Sopenharmony_ci * SOFTWARE. 22bf215546Sopenharmony_ci */ 23bf215546Sopenharmony_ci 24bf215546Sopenharmony_ci/* This pass lowers array accesses to SSA. 25bf215546Sopenharmony_ci * 26bf215546Sopenharmony_ci * After this pass, instructions writing arrays implicitly read the contents of 27bf215546Sopenharmony_ci * the array defined in instr->dsts[0]->def (possibly a phi node), perform the 28bf215546Sopenharmony_ci * operation, and store to instr->dsts[0]. 29bf215546Sopenharmony_ci * 30bf215546Sopenharmony_ci * This makes arrays appear like "normal" SSA values, even if the false 31bf215546Sopenharmony_ci * dependencies mean that they always stay in CSSA form (i.e. able to removed 32bf215546Sopenharmony_ci * out-of-SSA with no copies.) While hopefully they shouldn't induce copies in 33bf215546Sopenharmony_ci * most cases, we can't make that guarantee while also splitting spilling from 34bf215546Sopenharmony_ci * RA and guaranteeing a certain number of registers are used, so we have to 35bf215546Sopenharmony_ci * insert the phi nodes to be able to know when copying should happen. 36bf215546Sopenharmony_ci * 37bf215546Sopenharmony_ci * The implementation is based on the idea in "Simple and Efficient Construction 38bf215546Sopenharmony_ci * of Static Single Assignment Form" of scanning backwards to find the 39bf215546Sopenharmony_ci * definition. However, since we're not doing this on-the-fly we can simplify 40bf215546Sopenharmony_ci * things a little by doing a pre-pass to get the last definition of each array 41bf215546Sopenharmony_ci * in each block. Then we optimize trivial phis in a separate pass, "on the fly" 42bf215546Sopenharmony_ci * so that we don't have to rewrite (and keep track of) users. 43bf215546Sopenharmony_ci */ 44bf215546Sopenharmony_ci 45bf215546Sopenharmony_ci#include <stdlib.h> 46bf215546Sopenharmony_ci#include "ir3.h" 47bf215546Sopenharmony_ci 48bf215546Sopenharmony_cistruct array_state { 49bf215546Sopenharmony_ci struct ir3_register *live_in_definition; 50bf215546Sopenharmony_ci struct ir3_register *live_out_definition; 51bf215546Sopenharmony_ci bool constructed; 52bf215546Sopenharmony_ci bool optimized; 53bf215546Sopenharmony_ci}; 54bf215546Sopenharmony_ci 55bf215546Sopenharmony_cistruct array_ctx { 56bf215546Sopenharmony_ci struct array_state *states; 57bf215546Sopenharmony_ci struct ir3 *ir; 58bf215546Sopenharmony_ci unsigned array_count; 59bf215546Sopenharmony_ci}; 60bf215546Sopenharmony_ci 61bf215546Sopenharmony_cistatic struct array_state * 62bf215546Sopenharmony_ciget_state(struct array_ctx *ctx, struct ir3_block *block, unsigned id) 63bf215546Sopenharmony_ci{ 64bf215546Sopenharmony_ci return &ctx->states[ctx->array_count * block->index + id]; 65bf215546Sopenharmony_ci} 66bf215546Sopenharmony_ci 67bf215546Sopenharmony_cistatic struct ir3_register *read_value_beginning(struct array_ctx *ctx, 68bf215546Sopenharmony_ci struct ir3_block *block, 69bf215546Sopenharmony_ci struct ir3_array *arr); 70bf215546Sopenharmony_ci 71bf215546Sopenharmony_cistatic struct ir3_register * 72bf215546Sopenharmony_ciread_value_end(struct array_ctx *ctx, struct ir3_block *block, 73bf215546Sopenharmony_ci struct ir3_array *arr) 74bf215546Sopenharmony_ci{ 75bf215546Sopenharmony_ci struct array_state *state = get_state(ctx, block, arr->id); 76bf215546Sopenharmony_ci if (state->live_out_definition) 77bf215546Sopenharmony_ci return state->live_out_definition; 78bf215546Sopenharmony_ci 79bf215546Sopenharmony_ci state->live_out_definition = read_value_beginning(ctx, block, arr); 80bf215546Sopenharmony_ci return state->live_out_definition; 81bf215546Sopenharmony_ci} 82bf215546Sopenharmony_ci 83bf215546Sopenharmony_ci/* Roughly equivalent to readValueRecursive from the paper: */ 84bf215546Sopenharmony_cistatic struct ir3_register * 85bf215546Sopenharmony_ciread_value_beginning(struct array_ctx *ctx, struct ir3_block *block, 86bf215546Sopenharmony_ci struct ir3_array *arr) 87bf215546Sopenharmony_ci{ 88bf215546Sopenharmony_ci struct array_state *state = get_state(ctx, block, arr->id); 89bf215546Sopenharmony_ci 90bf215546Sopenharmony_ci if (state->constructed) 91bf215546Sopenharmony_ci return state->live_in_definition; 92bf215546Sopenharmony_ci 93bf215546Sopenharmony_ci if (block->predecessors_count == 0) { 94bf215546Sopenharmony_ci state->constructed = true; 95bf215546Sopenharmony_ci return NULL; 96bf215546Sopenharmony_ci } 97bf215546Sopenharmony_ci 98bf215546Sopenharmony_ci if (block->predecessors_count == 1) { 99bf215546Sopenharmony_ci state->live_in_definition = 100bf215546Sopenharmony_ci read_value_end(ctx, block->predecessors[0], arr); 101bf215546Sopenharmony_ci state->constructed = true; 102bf215546Sopenharmony_ci return state->live_in_definition; 103bf215546Sopenharmony_ci } 104bf215546Sopenharmony_ci 105bf215546Sopenharmony_ci unsigned flags = IR3_REG_ARRAY | (arr->half ? IR3_REG_HALF : 0); 106bf215546Sopenharmony_ci struct ir3_instruction *phi = 107bf215546Sopenharmony_ci ir3_instr_create(block, OPC_META_PHI, 1, block->predecessors_count); 108bf215546Sopenharmony_ci list_del(&phi->node); 109bf215546Sopenharmony_ci list_add(&phi->node, &block->instr_list); 110bf215546Sopenharmony_ci 111bf215546Sopenharmony_ci struct ir3_register *dst = __ssa_dst(phi); 112bf215546Sopenharmony_ci dst->flags |= flags; 113bf215546Sopenharmony_ci dst->array.id = arr->id; 114bf215546Sopenharmony_ci dst->size = arr->length; 115bf215546Sopenharmony_ci 116bf215546Sopenharmony_ci state->live_in_definition = phi->dsts[0]; 117bf215546Sopenharmony_ci state->constructed = true; 118bf215546Sopenharmony_ci 119bf215546Sopenharmony_ci for (unsigned i = 0; i < block->predecessors_count; i++) { 120bf215546Sopenharmony_ci struct ir3_register *src = 121bf215546Sopenharmony_ci read_value_end(ctx, block->predecessors[i], arr); 122bf215546Sopenharmony_ci struct ir3_register *src_reg; 123bf215546Sopenharmony_ci if (src) { 124bf215546Sopenharmony_ci src_reg = __ssa_src(phi, src->instr, flags); 125bf215546Sopenharmony_ci } else { 126bf215546Sopenharmony_ci src_reg = ir3_src_create(phi, INVALID_REG, flags | IR3_REG_SSA); 127bf215546Sopenharmony_ci } 128bf215546Sopenharmony_ci src_reg->array.id = arr->id; 129bf215546Sopenharmony_ci src_reg->size = arr->length; 130bf215546Sopenharmony_ci } 131bf215546Sopenharmony_ci return phi->dsts[0]; 132bf215546Sopenharmony_ci} 133bf215546Sopenharmony_ci 134bf215546Sopenharmony_cistatic struct ir3_register * 135bf215546Sopenharmony_ciremove_trivial_phi(struct ir3_instruction *phi) 136bf215546Sopenharmony_ci{ 137bf215546Sopenharmony_ci /* Break cycles */ 138bf215546Sopenharmony_ci if (phi->data) 139bf215546Sopenharmony_ci return phi->data; 140bf215546Sopenharmony_ci 141bf215546Sopenharmony_ci phi->data = phi->dsts[0]; 142bf215546Sopenharmony_ci 143bf215546Sopenharmony_ci struct ir3_register *unique_def = NULL; 144bf215546Sopenharmony_ci bool unique = true; 145bf215546Sopenharmony_ci for (unsigned i = 0; i < phi->block->predecessors_count; i++) { 146bf215546Sopenharmony_ci struct ir3_register *src = phi->srcs[i]; 147bf215546Sopenharmony_ci 148bf215546Sopenharmony_ci /* If there are any undef sources, then the remaining sources may not 149bf215546Sopenharmony_ci * dominate the phi node, even if they are all equal. So we need to 150bf215546Sopenharmony_ci * bail out in this case. 151bf215546Sopenharmony_ci * 152bf215546Sopenharmony_ci * This seems to be a bug in the original paper. 153bf215546Sopenharmony_ci */ 154bf215546Sopenharmony_ci if (!src->def) { 155bf215546Sopenharmony_ci unique = false; 156bf215546Sopenharmony_ci break; 157bf215546Sopenharmony_ci } 158bf215546Sopenharmony_ci 159bf215546Sopenharmony_ci struct ir3_instruction *src_instr = src->def->instr; 160bf215546Sopenharmony_ci 161bf215546Sopenharmony_ci /* phi sources which point to the phi itself don't count for 162bf215546Sopenharmony_ci * figuring out if the phi is trivial 163bf215546Sopenharmony_ci */ 164bf215546Sopenharmony_ci if (src_instr == phi) 165bf215546Sopenharmony_ci continue; 166bf215546Sopenharmony_ci 167bf215546Sopenharmony_ci if (src_instr->opc == OPC_META_PHI) { 168bf215546Sopenharmony_ci src->def = remove_trivial_phi(src->def->instr); 169bf215546Sopenharmony_ci } 170bf215546Sopenharmony_ci 171bf215546Sopenharmony_ci if (unique_def) { 172bf215546Sopenharmony_ci if (unique_def != src->def) { 173bf215546Sopenharmony_ci unique = false; 174bf215546Sopenharmony_ci break; 175bf215546Sopenharmony_ci } 176bf215546Sopenharmony_ci } else { 177bf215546Sopenharmony_ci unique_def = src->def; 178bf215546Sopenharmony_ci } 179bf215546Sopenharmony_ci } 180bf215546Sopenharmony_ci 181bf215546Sopenharmony_ci if (unique) { 182bf215546Sopenharmony_ci phi->data = unique_def; 183bf215546Sopenharmony_ci return unique_def; 184bf215546Sopenharmony_ci } else { 185bf215546Sopenharmony_ci return phi->dsts[0]; 186bf215546Sopenharmony_ci } 187bf215546Sopenharmony_ci} 188bf215546Sopenharmony_ci 189bf215546Sopenharmony_cistatic struct ir3_register * 190bf215546Sopenharmony_cilookup_value(struct ir3_register *reg) 191bf215546Sopenharmony_ci{ 192bf215546Sopenharmony_ci if (reg->instr->opc == OPC_META_PHI) 193bf215546Sopenharmony_ci return reg->instr->data; 194bf215546Sopenharmony_ci return reg; 195bf215546Sopenharmony_ci} 196bf215546Sopenharmony_ci 197bf215546Sopenharmony_cistatic struct ir3_register * 198bf215546Sopenharmony_cilookup_live_in(struct array_ctx *ctx, struct ir3_block *block, unsigned id) 199bf215546Sopenharmony_ci{ 200bf215546Sopenharmony_ci struct array_state *state = get_state(ctx, block, id); 201bf215546Sopenharmony_ci if (state->live_in_definition) 202bf215546Sopenharmony_ci return lookup_value(state->live_in_definition); 203bf215546Sopenharmony_ci 204bf215546Sopenharmony_ci return NULL; 205bf215546Sopenharmony_ci} 206bf215546Sopenharmony_ci 207bf215546Sopenharmony_cibool 208bf215546Sopenharmony_ciir3_array_to_ssa(struct ir3 *ir) 209bf215546Sopenharmony_ci{ 210bf215546Sopenharmony_ci struct array_ctx ctx = {}; 211bf215546Sopenharmony_ci 212bf215546Sopenharmony_ci foreach_array (array, &ir->array_list) { 213bf215546Sopenharmony_ci ctx.array_count = MAX2(ctx.array_count, array->id + 1); 214bf215546Sopenharmony_ci } 215bf215546Sopenharmony_ci 216bf215546Sopenharmony_ci if (ctx.array_count == 0) 217bf215546Sopenharmony_ci return false; 218bf215546Sopenharmony_ci 219bf215546Sopenharmony_ci unsigned i = 0; 220bf215546Sopenharmony_ci foreach_block (block, &ir->block_list) { 221bf215546Sopenharmony_ci block->index = i++; 222bf215546Sopenharmony_ci } 223bf215546Sopenharmony_ci 224bf215546Sopenharmony_ci ctx.ir = ir; 225bf215546Sopenharmony_ci ctx.states = calloc(ctx.array_count * i, sizeof(struct array_state)); 226bf215546Sopenharmony_ci 227bf215546Sopenharmony_ci foreach_block (block, &ir->block_list) { 228bf215546Sopenharmony_ci foreach_instr (instr, &block->instr_list) { 229bf215546Sopenharmony_ci foreach_dst (dst, instr) { 230bf215546Sopenharmony_ci if (dst->flags & IR3_REG_ARRAY) { 231bf215546Sopenharmony_ci struct array_state *state = 232bf215546Sopenharmony_ci get_state(&ctx, block, dst->array.id); 233bf215546Sopenharmony_ci state->live_out_definition = dst; 234bf215546Sopenharmony_ci } 235bf215546Sopenharmony_ci } 236bf215546Sopenharmony_ci } 237bf215546Sopenharmony_ci } 238bf215546Sopenharmony_ci 239bf215546Sopenharmony_ci foreach_block (block, &ir->block_list) { 240bf215546Sopenharmony_ci foreach_instr (instr, &block->instr_list) { 241bf215546Sopenharmony_ci if (instr->opc == OPC_META_PHI) 242bf215546Sopenharmony_ci continue; 243bf215546Sopenharmony_ci 244bf215546Sopenharmony_ci foreach_dst (reg, instr) { 245bf215546Sopenharmony_ci if ((reg->flags & IR3_REG_ARRAY) && !reg->tied) { 246bf215546Sopenharmony_ci struct ir3_array *arr = ir3_lookup_array(ir, reg->array.id); 247bf215546Sopenharmony_ci 248bf215546Sopenharmony_ci /* Construct any phi nodes necessary to read this value */ 249bf215546Sopenharmony_ci read_value_beginning(&ctx, block, arr); 250bf215546Sopenharmony_ci } 251bf215546Sopenharmony_ci } 252bf215546Sopenharmony_ci foreach_src (reg, instr) { 253bf215546Sopenharmony_ci if ((reg->flags & IR3_REG_ARRAY) && !reg->def) { 254bf215546Sopenharmony_ci struct ir3_array *arr = ir3_lookup_array(ir, reg->array.id); 255bf215546Sopenharmony_ci 256bf215546Sopenharmony_ci /* Construct any phi nodes necessary to read this value */ 257bf215546Sopenharmony_ci read_value_beginning(&ctx, block, arr); 258bf215546Sopenharmony_ci } 259bf215546Sopenharmony_ci } 260bf215546Sopenharmony_ci } 261bf215546Sopenharmony_ci } 262bf215546Sopenharmony_ci 263bf215546Sopenharmony_ci foreach_block (block, &ir->block_list) { 264bf215546Sopenharmony_ci foreach_instr_safe (instr, &block->instr_list) { 265bf215546Sopenharmony_ci if (instr->opc == OPC_META_PHI) 266bf215546Sopenharmony_ci remove_trivial_phi(instr); 267bf215546Sopenharmony_ci else 268bf215546Sopenharmony_ci break; 269bf215546Sopenharmony_ci } 270bf215546Sopenharmony_ci } 271bf215546Sopenharmony_ci 272bf215546Sopenharmony_ci foreach_block (block, &ir->block_list) { 273bf215546Sopenharmony_ci foreach_instr_safe (instr, &block->instr_list) { 274bf215546Sopenharmony_ci if (instr->opc == OPC_META_PHI) { 275bf215546Sopenharmony_ci if (!(instr->flags & IR3_REG_ARRAY)) 276bf215546Sopenharmony_ci continue; 277bf215546Sopenharmony_ci if (instr->data != instr->dsts[0]) { 278bf215546Sopenharmony_ci list_del(&instr->node); 279bf215546Sopenharmony_ci continue; 280bf215546Sopenharmony_ci } 281bf215546Sopenharmony_ci for (unsigned i = 0; i < instr->srcs_count; i++) { 282bf215546Sopenharmony_ci instr->srcs[i] = lookup_value(instr->srcs[i]); 283bf215546Sopenharmony_ci } 284bf215546Sopenharmony_ci } else { 285bf215546Sopenharmony_ci foreach_dst (reg, instr) { 286bf215546Sopenharmony_ci if ((reg->flags & IR3_REG_ARRAY)) { 287bf215546Sopenharmony_ci if (!reg->tied) { 288bf215546Sopenharmony_ci struct ir3_register *def = 289bf215546Sopenharmony_ci lookup_live_in(&ctx, block, reg->array.id); 290bf215546Sopenharmony_ci if (def) 291bf215546Sopenharmony_ci ir3_reg_set_last_array(instr, reg, def); 292bf215546Sopenharmony_ci } 293bf215546Sopenharmony_ci reg->flags |= IR3_REG_SSA; 294bf215546Sopenharmony_ci } 295bf215546Sopenharmony_ci } 296bf215546Sopenharmony_ci foreach_src (reg, instr) { 297bf215546Sopenharmony_ci if ((reg->flags & IR3_REG_ARRAY)) { 298bf215546Sopenharmony_ci /* It is assumed that before calling 299bf215546Sopenharmony_ci * ir3_array_to_ssa(), reg->def was set to the 300bf215546Sopenharmony_ci * previous writer of the array within the current 301bf215546Sopenharmony_ci * block or NULL if none. 302bf215546Sopenharmony_ci */ 303bf215546Sopenharmony_ci if (!reg->def) { 304bf215546Sopenharmony_ci reg->def = lookup_live_in(&ctx, block, reg->array.id); 305bf215546Sopenharmony_ci } 306bf215546Sopenharmony_ci reg->flags |= IR3_REG_SSA; 307bf215546Sopenharmony_ci } 308bf215546Sopenharmony_ci } 309bf215546Sopenharmony_ci } 310bf215546Sopenharmony_ci } 311bf215546Sopenharmony_ci } 312bf215546Sopenharmony_ci 313bf215546Sopenharmony_ci free(ctx.states); 314bf215546Sopenharmony_ci return true; 315bf215546Sopenharmony_ci} 316