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 c->cur_block = block; 103 vir_for_each_inst(inst, block) { 104 if (inst->qpu.type != V3D_QPU_INSTR_TYPE_ALU || 105 inst->qpu.flags.auf != V3D_QPU_UF_NONE || 106 inst->qpu.flags.muf != V3D_QPU_UF_NONE) { 107 last_flags = NULL; 108 continue; 109 } 110 111 /* Flags aren't preserved across a thrsw. 112 * 113 * In V3D 4.2+ flags are preserved across thread switches. 114 */ 115 if (c->devinfo->ver < 42) { 116 if (inst->qpu.sig.thrsw) 117 last_flags = NULL; 118 } 119 120 if (inst->qpu.flags.apf != V3D_QPU_PF_NONE || 121 inst->qpu.flags.mpf != V3D_QPU_PF_NONE) { 122 if (last_flags && 123 vir_instr_flags_op_equal(inst, last_flags)) { 124 vir_dce_pf(c, inst); 125 progress = true; 126 } else { 127 last_flags = inst; 128 } 129 } 130 131 if (last_flags && vir_sources_modified(last_flags, inst)) { 132 last_flags = NULL; 133 } 134 } 135 136 return progress; 137} 138 139bool 140vir_opt_redundant_flags(struct v3d_compile *c) 141{ 142 bool progress = false; 143 144 vir_for_each_block(block, c) { 145 progress = vir_opt_redundant_flags_block(c, block) || progress; 146 } 147 148 return progress; 149} 150