1/* 2 * Copyright © 2019 Broadcom 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 * IN THE SOFTWARE. 22 */ 23 24/** 25 * @file v3d_opt_redundant_flags.c 26 * 27 * This eliminates the APF/MPF flags for redundant flags updates. These are 28 * often produced by our channel masking in nonuniform control flow. 29 */ 30 31#include "v3d_compiler.h" 32 33static bool debug; 34 35static void 36vir_dce_pf(struct v3d_compile *c, struct qinst *inst) 37{ 38 if (debug) { 39 fprintf(stderr, 40 "Removing flags write from: "); 41 vir_dump_inst(c, inst); 42 fprintf(stderr, "\n"); 43 } 44 45 assert(inst->qpu.type == V3D_QPU_INSTR_TYPE_ALU); 46 47 inst->qpu.flags.apf = V3D_QPU_PF_NONE; 48 inst->qpu.flags.mpf = V3D_QPU_PF_NONE; 49} 50 51static bool 52vir_sources_modified(struct qinst *srcs, struct qinst *write) 53{ 54 for (int i = 0; i < vir_get_nsrc(srcs); i++) { 55 if (write->dst.file == QFILE_TEMP && 56 srcs->src[i].file == QFILE_TEMP && 57 srcs->src[i].index == write->dst.index) { 58 return true; 59 } 60 61 /* assume magic regs may be modified by basically anything. */ 62 if (srcs->src[i].file != QFILE_TEMP && 63 srcs->src[i].file != QFILE_SMALL_IMM) 64 return true; 65 } 66 67 return false; 68} 69 70static bool 71vir_instr_flags_op_equal(struct qinst *a, struct qinst *b) 72{ 73 for (int i = 0; i < vir_get_nsrc(a); i++) { 74 if (a->src[i].file != b->src[i].file || 75 a->src[i].index != b->src[i].index) { 76 return false; 77 } 78 } 79 80 if (a->qpu.flags.apf != b->qpu.flags.apf || 81 a->qpu.flags.mpf != b->qpu.flags.mpf || 82 a->qpu.alu.add.op != b->qpu.alu.add.op || 83 a->qpu.alu.mul.op != b->qpu.alu.mul.op || 84 a->qpu.alu.add.a_unpack != b->qpu.alu.add.a_unpack || 85 a->qpu.alu.add.b_unpack != b->qpu.alu.add.b_unpack || 86 a->qpu.alu.add.output_pack != b->qpu.alu.add.output_pack || 87 a->qpu.alu.mul.a_unpack != b->qpu.alu.mul.a_unpack || 88 a->qpu.alu.mul.b_unpack != b->qpu.alu.mul.b_unpack || 89 a->qpu.alu.mul.output_pack != b->qpu.alu.mul.output_pack) { 90 return false; 91 } 92 93 return true; 94} 95 96static bool 97vir_opt_redundant_flags_block(struct v3d_compile *c, struct qblock *block) 98{ 99 struct qinst *last_flags = NULL; 100 bool progress = false; 101 102 vir_for_each_inst(inst, block) { 103 if (inst->qpu.type != V3D_QPU_INSTR_TYPE_ALU || 104 inst->qpu.flags.auf != V3D_QPU_UF_NONE || 105 inst->qpu.flags.muf != V3D_QPU_UF_NONE) { 106 last_flags = NULL; 107 continue; 108 } 109 110 /* Flags aren't preserved across a thrsw. 111 * 112 * In V3D 4.2+ flags are preserved across thread switches. 113 */ 114 if (c->devinfo->ver < 42) { 115 if (inst->qpu.sig.thrsw) 116 last_flags = NULL; 117 } 118 119 if (inst->qpu.flags.apf != V3D_QPU_PF_NONE || 120 inst->qpu.flags.mpf != V3D_QPU_PF_NONE) { 121 if (last_flags && 122 vir_instr_flags_op_equal(inst, last_flags)) { 123 vir_dce_pf(c, inst); 124 progress = true; 125 } else { 126 last_flags = inst; 127 } 128 } 129 130 if (last_flags && vir_sources_modified(last_flags, inst)) { 131 last_flags = NULL; 132 } 133 } 134 135 return progress; 136} 137 138bool 139vir_opt_redundant_flags(struct v3d_compile *c) 140{ 141 bool progress = false; 142 143 vir_for_each_block(block, c) { 144 progress = vir_opt_redundant_flags_block(c, block) || progress; 145 } 146 147 return progress; 148} 149