1 /* -*- mesa-c++ -*-
2 *
3 * Copyright (c) 2022 Collabora LTD
4 *
5 * Author: Gert Wollny <gert.wollny@collabora.com>
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * on the rights to use, copy, modify, merge, publish, distribute, sub
11 * license, and/or sell copies of the Software, and to permit persons to whom
12 * the Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the next
15 * paragraph) shall be included in all copies or substantial portions of the
16 * Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
21 * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
22 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
24 * USE OR OTHER DEALINGS IN THE SOFTWARE.
25 */
26
27 #include "sfn_peephole.h"
28
29 namespace r600 {
30
31
32 class PeepholeVisitor : public InstrVisitor {
33 public:
34 void visit(AluInstr *instr) override;
35 void visit(AluGroup *instr) override;
visit(TexInstr * instr)36 void visit(TexInstr *instr) override {(void)instr;};
visit(ExportInstr * instr)37 void visit(ExportInstr *instr) override {(void)instr;}
visit(FetchInstr * instr)38 void visit(FetchInstr *instr) override {(void)instr;}
39 void visit(Block *instr) override;
visit(ControlFlowInstr * instr)40 void visit(ControlFlowInstr *instr) override {(void)instr;}
41 void visit(IfInstr *instr) override;
visit(ScratchIOInstr * instr)42 void visit(ScratchIOInstr *instr) override {(void)instr;}
visit(StreamOutInstr * instr)43 void visit(StreamOutInstr *instr) override {(void)instr;}
visit(MemRingOutInstr * instr)44 void visit(MemRingOutInstr *instr) override {(void)instr;}
visit(EmitVertexInstr * instr)45 void visit(EmitVertexInstr *instr) override {(void)instr;}
visit(GDSInstr * instr)46 void visit(GDSInstr *instr) override {(void)instr;};
visit(WriteTFInstr * instr)47 void visit(WriteTFInstr *instr) override {(void)instr;};
visit(LDSAtomicInstr * instr)48 void visit(LDSAtomicInstr *instr) override {(void)instr;};
visit(LDSReadInstr * instr)49 void visit(LDSReadInstr *instr) override {(void)instr;};
visit(RatInstr * instr)50 void visit(RatInstr *instr) override {(void)instr;};
51
52 bool src_is_zero(PVirtualValue value);
53 bool src_is_one(PVirtualValue value);
54
55 void convert_to_mov(AluInstr *alu, int src_idx);
56
57
58 bool progress{false};
59 };
60
61
peephole(Shader & sh)62 bool peephole(Shader& sh)
63 {
64 PeepholeVisitor peephole;
65 for(auto b : sh.func())
66 b->accept(peephole);
67 return peephole.progress;
68 }
69
visit(AluInstr * instr)70 void PeepholeVisitor::visit(AluInstr *instr)
71 {
72 switch (instr->opcode()) {
73 case op2_add:
74 case op2_add_int:
75 if (src_is_zero(instr->psrc(0)))
76 convert_to_mov(instr, 1);
77 else if (src_is_zero(instr->psrc(1)))
78 convert_to_mov(instr, 0);
79 break;
80 case op2_mul:
81 case op2_mul_ieee:
82 if (src_is_one(instr->psrc(0)))
83 convert_to_mov(instr, 1);
84 else if (src_is_one(instr->psrc(1)))
85 convert_to_mov(instr, 0);
86 break;
87 case op3_muladd:
88 case op3_muladd_ieee:
89 if (src_is_zero(instr->psrc(0)) ||
90 src_is_zero(instr->psrc(1)))
91 convert_to_mov(instr, 2);
92 break;
93 default:
94 ;
95 }
96 }
97
src_is_zero(PVirtualValue value)98 bool PeepholeVisitor::src_is_zero(PVirtualValue value)
99 {
100 if (value->as_inline_const() &&
101 value->as_inline_const()->sel() == ALU_SRC_0)
102 return true;
103
104 if (value->as_literal() &&
105 value->as_literal()->value() == 0)
106 return true;
107
108 return false;
109 }
110
src_is_one(PVirtualValue value)111 bool PeepholeVisitor::src_is_one(PVirtualValue value)
112 {
113 if (value->as_inline_const() &&
114 value->as_inline_const()->sel() == ALU_SRC_1)
115 return true;
116
117 if (value->as_literal() &&
118 value->as_literal()->value() == 0x3f800000)
119 return true;
120
121 return false;
122 }
123
convert_to_mov(AluInstr * alu,int src_idx)124 void PeepholeVisitor::convert_to_mov(AluInstr *alu, int src_idx)
125 {
126 AluInstr::SrcValues new_src{alu->psrc(src_idx)};
127 alu->set_sources(new_src);
128 alu->set_op(op1_mov);
129 progress = true;
130 }
131
132
visit(AluGroup * instr)133 void PeepholeVisitor::visit(AluGroup *instr)
134 {
135
136 }
137
visit(Block * instr)138 void PeepholeVisitor::visit(Block *instr)
139 {
140 for (auto& i: *instr)
141 i->accept(*this);
142 }
143
144 class ReplaceIfPredicate : public AluInstrVisitor {
145 public:
ReplaceIfPredicate(AluInstr * pred)146 ReplaceIfPredicate(AluInstr *pred):
147 m_pred(pred) {}
148
149 using AluInstrVisitor::visit;
150
151 void visit(AluInstr *alu) override;
152
153 AluInstr *m_pred;
154 bool success{false};
155 };
156
visit(IfInstr * instr)157 void PeepholeVisitor::visit(IfInstr *instr)
158 {
159 auto pred = instr->predicate();
160
161 auto& src1 = pred->src(1);
162 if (src1.as_inline_const() &&
163 src1.as_inline_const()->sel() == ALU_SRC_0) {
164 auto src0 = pred->src(0).as_register();
165 if (src0 && src0->is_ssa()) {
166 assert(!src0->parents().empty());
167 auto parent = *src0->parents().begin();
168
169 ReplaceIfPredicate visitor(pred);
170 parent->accept(visitor);
171 progress |= visitor.success;
172 }
173 }
174 }
175
pred_from_op(EAluOp pred_op,EAluOp op)176 static EAluOp pred_from_op(EAluOp pred_op, EAluOp op)
177 {
178 switch (pred_op) {
179 case op2_pred_setne_int:
180 switch (op) {
181 /*
182 case op2_setge_dx10 : return op2_pred_setge_int;
183 case op2_setgt_dx10 : return op2_pred_setgt_int;
184 case op2_sete_dx10 : return op2_prede_int;
185 case op2_setne_dx10 : return op2_pred_setne_int;
186 */
187 case op2_setge_int : return op2_pred_setge_int;
188 case op2_setgt_int : return op2_pred_setgt_int;
189 case op2_setge_uint : return op2_pred_setge_uint;
190 case op2_setgt_uint : return op2_pred_setgt_uint;
191 case op2_sete_int : return op2_prede_int;
192 case op2_setne_int : return op2_pred_setne_int;
193 default:
194 return op0_nop;
195 }
196 case op2_prede_int:
197 switch (op) {
198 case op2_sete_int : return op2_pred_setne_int;
199 case op2_setne_int : return op2_prede_int;
200 default:
201 return op0_nop;
202 }
203 default:
204 return op0_nop;
205 }
206 }
207
visit(AluInstr * alu)208 void ReplaceIfPredicate::visit(AluInstr *alu)
209 {
210 auto new_op = pred_from_op(m_pred->opcode(), alu->opcode());
211
212 if (new_op == op0_nop)
213 return;
214
215 for (auto& s : alu->sources()) {
216 auto reg = s->as_register();
217 /* Protext against propagating
218 *
219 * V = COND(R, X)
220 * R = SOME_OP
221 * IF (V)
222 *
223 * to
224 *
225 * R = SOME_OP
226 * IF (COND(R, X))
227 */
228 if (reg && !reg->is_ssa())
229 return;
230 }
231
232 m_pred->set_op(new_op);
233 m_pred->set_sources(alu->sources());
234
235 if (alu->has_alu_flag(alu_src0_abs))
236 m_pred->set_alu_flag(alu_src0_abs);
237 if (alu->has_alu_flag(alu_src1_abs))
238 m_pred->set_alu_flag(alu_src1_abs);
239
240 if (alu->has_alu_flag(alu_src0_neg))
241 m_pred->set_alu_flag(alu_src0_neg);
242
243 if (alu->has_alu_flag(alu_src1_neg))
244 m_pred->set_alu_flag(alu_src1_neg);
245
246 success = true;
247 }
248
249 }
250