• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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