• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
33 static bool debug;
34 
35 static void
vir_dce_pf(struct v3d_compile * c,struct qinst * inst)36 vir_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 
51 static bool
vir_sources_modified(struct qinst * srcs,struct qinst * write)52 vir_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 
70 static bool
vir_instr_flags_op_equal(struct qinst * a,struct qinst * b)71 vir_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 
96 static bool
vir_opt_redundant_flags_block(struct v3d_compile * c,struct qblock * block)97 vir_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 
138 bool
vir_opt_redundant_flags(struct v3d_compile * c)139 vir_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