• 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_optimizer.h"
28 
29 #include "sfn_instr_alugroup.h"
30 #include "sfn_instr_controlflow.h"
31 #include "sfn_instr_export.h"
32 #include "sfn_instr_tex.h"
33 #include "sfn_instr_fetch.h"
34 #include "sfn_instr_lds.h"
35 #include "sfn_peephole.h"
36 #include "sfn_debug.h"
37 
38 #include <sstream>
39 
40 namespace r600 {
41 
optimize(Shader & shader)42 bool optimize(Shader& shader)
43 {
44    bool progress;
45 
46    sfn_log << SfnLog::opt  << "Shader before optimization\n";
47    if (sfn_log.has_debug_flag(SfnLog::opt)) {
48       std::stringstream ss;
49       shader.print(ss);
50       sfn_log << ss.str() << "\n\n";
51    }
52 
53    do {
54       progress = false;
55       progress |= copy_propagation_fwd(shader);
56       progress |= dead_code_elimination(shader);
57       progress |= copy_propagation_backward(shader);
58       progress |= dead_code_elimination(shader);
59       progress |= simplify_source_vectors(shader);
60       progress |= peephole(shader);
61       progress |= dead_code_elimination(shader);
62    } while (progress);
63 
64    return progress;
65 }
66 
67 class DCEVisitor : public InstrVisitor {
68 public:
69    DCEVisitor();
70 
71    void visit(AluInstr *instr) override;
72    void visit(AluGroup *instr) override;
73    void visit(TexInstr  *instr) override;
visit(ExportInstr * instr)74    void visit(ExportInstr *instr) override {(void)instr;};
75    void visit(FetchInstr *instr) override;
76    void visit(Block *instr) override;
77 
visit(ControlFlowInstr * instr)78    void visit(ControlFlowInstr *instr) override {(void)instr;};
visit(IfInstr * instr)79    void visit(IfInstr *instr) override {(void)instr;};
visit(ScratchIOInstr * instr)80    void visit(ScratchIOInstr *instr) override {(void)instr;};
visit(StreamOutInstr * instr)81    void visit(StreamOutInstr *instr) override {(void)instr;};
visit(MemRingOutInstr * instr)82    void visit(MemRingOutInstr *instr) override {(void)instr;};
visit(EmitVertexInstr * instr)83    void visit(EmitVertexInstr *instr) override {(void)instr;};
visit(GDSInstr * instr)84    void visit(GDSInstr *instr) override {(void)instr;};
visit(WriteTFInstr * instr)85    void visit(WriteTFInstr *instr) override {(void)instr;};
visit(LDSAtomicInstr * instr)86    void visit(LDSAtomicInstr *instr) override {(void)instr;};
87    void visit(LDSReadInstr *instr) override;
visit(RatInstr * instr)88    void visit(RatInstr *instr) override {(void)instr;};
89 
90 
91    bool progress;
92 };
93 
dead_code_elimination(Shader & shader)94 bool dead_code_elimination(Shader& shader)
95 {
96    DCEVisitor dce;
97 
98    do {
99 
100       sfn_log << SfnLog::opt << "start dce run\n";
101 
102       dce.progress = false;
103       for (auto& b : shader.func())
104          b->accept(dce);
105 
106       sfn_log << SfnLog::opt << "finished dce run\n\n";
107 
108    }  while (dce.progress);
109 
110    sfn_log << SfnLog::opt  << "Shader after DCE\n";
111    if (sfn_log.has_debug_flag(SfnLog::opt)) {
112       std::stringstream ss;
113       shader.print(ss);
114       sfn_log << ss.str() << "\n\n";
115    }
116 
117    return dce.progress;
118 }
119 
DCEVisitor()120 DCEVisitor::DCEVisitor():progress(false)
121 {
122 }
123 
visit(AluInstr * instr)124 void DCEVisitor::visit(AluInstr *instr)
125 {
126    sfn_log << SfnLog::opt << "DCE: visit '" << *instr;
127 
128    if (instr->has_instr_flag(Instr::dead))
129       return;
130 
131    if (instr->dest() &&
132        (instr->dest()->has_uses() || !instr->dest()->is_ssa()) ) {
133       sfn_log << SfnLog::opt << " dest used\n";
134       return;
135    }
136 
137    switch (instr->opcode()) {
138    case op2_kille:
139    case op2_killne:
140    case op2_kille_int:
141    case op2_killne_int:
142    case op2_killge:
143    case op2_killge_int:
144    case op2_killge_uint:
145    case op2_killgt:
146    case op2_killgt_int:
147    case op2_killgt_uint:
148    case op0_group_barrier:
149       sfn_log << SfnLog::opt << " never kill\n";
150       return;
151    default:
152       ;
153    }
154 
155    bool dead = instr->set_dead();
156    sfn_log << SfnLog::opt << (dead ? "dead" : "alive") << "\n";
157    progress |= dead;
158 }
159 
visit(LDSReadInstr * instr)160 void DCEVisitor::visit(LDSReadInstr *instr)
161 {
162    sfn_log << SfnLog::opt << "visit " << *instr << "\n";
163    progress |= instr->remove_unused_components();
164 }
165 
visit(AluGroup * instr)166 void DCEVisitor::visit(AluGroup *instr)
167 {
168    /* Groups are created because the instructions are used together
169     * so don't try to eliminate code there */
170    (void)instr;
171 }
172 
visit(TexInstr * instr)173 void DCEVisitor::visit(TexInstr *instr)
174 {
175    auto& dest = instr->dst();
176 
177    bool has_uses = false;
178    RegisterVec4::Swizzle swz = instr->all_dest_swizzle();
179    for (int i = 0; i < 4; ++i) {
180       if (!dest[i]->has_uses())
181          swz[i] = 7;
182       else
183          has_uses |= true;
184    }
185    instr->set_dest_swizzle(swz);
186 
187    if (has_uses)
188       return;
189 
190    progress |= instr->set_dead();
191 }
192 
visit(FetchInstr * instr)193 void DCEVisitor::visit(FetchInstr *instr)
194 {
195    auto& dest = instr->dst();
196 
197    bool has_uses = false;
198    RegisterVec4::Swizzle swz = instr->all_dest_swizzle();
199    for (int i = 0; i < 4; ++i) {
200       if (!dest[i]->has_uses())
201          swz[i] = 7;
202       else
203          has_uses |= true;
204    }
205    instr->set_dest_swizzle(swz);
206 
207    if (has_uses)
208       return;
209 
210    sfn_log << SfnLog::opt << "set dead: " << *instr << "\n";
211 
212    progress |= instr->set_dead();
213 }
214 
visit(Block * block)215 void DCEVisitor::visit(Block *block)
216 {
217    auto i = block->begin();
218    auto e = block->end();
219    while (i != e) {
220       auto n = i++;
221       if (!(*n)->keep()) {
222          (*n)->accept(*this);
223          if ((*n)->is_dead()) {
224             block->erase(n);
225          }
226       }
227    }
228 }
229 
visit(ControlFlowInstr * instr)230 void visit(ControlFlowInstr *instr)
231 {
232    (void)instr;
233 }
234 
visit(IfInstr * instr)235 void visit(IfInstr *instr)
236 {
237    (void)instr;
238 }
239 
240 class CopyPropFwdVisitor : public InstrVisitor {
241 public:
242    CopyPropFwdVisitor();
243 
244    void visit(AluInstr *instr) override;
245    void visit(AluGroup *instr) override;
246    void visit(TexInstr *instr) override;
visit(ExportInstr * instr)247    void visit(ExportInstr *instr) override {(void)instr;}
248    void visit(FetchInstr *instr) override;
249    void visit(Block *instr) override;
visit(ControlFlowInstr * instr)250    void visit(ControlFlowInstr *instr) override {(void)instr;}
visit(IfInstr * instr)251    void visit(IfInstr *instr) override {(void)instr;}
visit(ScratchIOInstr * instr)252    void visit(ScratchIOInstr *instr) override {(void)instr;}
visit(StreamOutInstr * instr)253    void visit(StreamOutInstr *instr) override {(void)instr;}
visit(MemRingOutInstr * instr)254    void visit(MemRingOutInstr *instr) override {(void)instr;}
visit(EmitVertexInstr * instr)255    void visit(EmitVertexInstr *instr) override {(void)instr;}
visit(GDSInstr * instr)256    void visit(GDSInstr *instr) override {(void)instr;};
visit(WriteTFInstr * instr)257    void visit(WriteTFInstr *instr) override {(void)instr;};
visit(RatInstr * instr)258    void visit(RatInstr *instr) override {(void)instr;};
259 
260    // TODO: these two should use copy propagation
visit(LDSAtomicInstr * instr)261    void visit(LDSAtomicInstr *instr) override {(void)instr;};
visit(LDSReadInstr * instr)262    void visit(LDSReadInstr *instr) override {(void)instr;};
263 
264    bool progress;
265 };
266 
267 
268 class CopyPropBackVisitor : public InstrVisitor {
269 public:
270    CopyPropBackVisitor();
271 
272    void visit(AluInstr *instr) override;
273    void visit(AluGroup *instr) override;
274    void visit(TexInstr *instr) override;
visit(ExportInstr * instr)275    void visit(ExportInstr *instr) override {(void)instr;}
276    void visit(FetchInstr *instr) override;
277    void visit(Block *instr) override;
visit(ControlFlowInstr * instr)278    void visit(ControlFlowInstr *instr) override {(void)instr;}
visit(IfInstr * instr)279    void visit(IfInstr *instr) override {(void)instr;}
visit(ScratchIOInstr * instr)280    void visit(ScratchIOInstr *instr) override {(void)instr;}
visit(StreamOutInstr * instr)281    void visit(StreamOutInstr *instr) override {(void)instr;}
visit(MemRingOutInstr * instr)282    void visit(MemRingOutInstr *instr) override {(void)instr;}
visit(EmitVertexInstr * instr)283    void visit(EmitVertexInstr *instr) override {(void)instr;}
visit(GDSInstr * instr)284    void visit(GDSInstr *instr) override {(void)instr;};
visit(WriteTFInstr * instr)285    void visit(WriteTFInstr *instr) override {(void)instr;};
visit(LDSAtomicInstr * instr)286    void visit(LDSAtomicInstr *instr) override {(void)instr;};
visit(LDSReadInstr * instr)287    void visit(LDSReadInstr *instr) override {(void)instr;};
visit(RatInstr * instr)288    void visit(RatInstr *instr) override {(void)instr;};
289 
290    bool progress;
291 };
292 
copy_propagation_fwd(Shader & shader)293 bool copy_propagation_fwd(Shader& shader)
294 {
295    auto& root = shader.func();
296    CopyPropFwdVisitor copy_prop;
297 
298    do {
299       copy_prop.progress = false;
300       for (auto b : root)
301          b->accept(copy_prop);
302    }  while (copy_prop.progress);
303 
304    sfn_log << SfnLog::opt  << "Shader after Copy Prop forward\n";
305    if (sfn_log.has_debug_flag(SfnLog::opt)) {
306       std::stringstream ss;
307       shader.print(ss);
308       sfn_log << ss.str() << "\n\n";
309    }
310 
311 
312    return copy_prop.progress;
313 }
314 
copy_propagation_backward(Shader & shader)315 bool copy_propagation_backward(Shader& shader)
316 {
317    CopyPropBackVisitor copy_prop;
318 
319    do {
320       copy_prop.progress = false;
321       for (auto b: shader.func())
322          b->accept(copy_prop);
323    }  while (copy_prop.progress);
324 
325    sfn_log << SfnLog::opt  << "Shader after Copy Prop backwards\n";
326    if (sfn_log.has_debug_flag(SfnLog::opt)) {
327       std::stringstream ss;
328       shader.print(ss);
329       sfn_log << ss.str() << "\n\n";
330    }
331 
332    return copy_prop.progress;
333 }
334 
CopyPropFwdVisitor()335 CopyPropFwdVisitor::CopyPropFwdVisitor():
336    progress(false)
337 {}
338 
visit(AluInstr * instr)339 void CopyPropFwdVisitor::visit(AluInstr *instr)
340 {
341    sfn_log << SfnLog::opt << "CopyPropFwdVisitor:["
342            << instr->block_id() << ":" << instr->index() << "] " << *instr
343            << " dset=" << instr->dest() << " ";
344 
345 
346 
347    if (instr->dest()) {
348       sfn_log << SfnLog::opt << "has uses; "
349               << instr->dest()->uses().size();
350    }
351 
352    sfn_log << SfnLog::opt << "\n";
353 
354    if (!instr->can_propagate_src()) {
355       return;
356    }
357 
358    auto src = instr->psrc(0);
359    auto dest = instr->dest();
360 
361    for (auto& i : instr->dest()->uses()) {
362       /* SSA can always be propagated, registers only in the same block
363        * and only if they are not assigned to more than once */
364       if (dest->is_ssa() ||
365           (instr->block_id() == i->block_id() &&
366            instr->index() < i->index() &&
367            dest->uses().size() == 1)) {
368          sfn_log << SfnLog::opt << "   Try replace in "
369                  << i->block_id() << ":" << i->index()
370                  << *i<< "\n";
371          progress |= i->replace_source(dest, src);
372       }
373    }
374    if (instr->dest()) {
375       sfn_log << SfnLog::opt << "has uses; "
376               << instr->dest()->uses().size();
377    }
378    sfn_log << SfnLog::opt << "  done\n";
379 }
380 
381 
visit(AluGroup * instr)382 void CopyPropFwdVisitor::visit(AluGroup *instr)
383 {
384    (void)instr;
385 }
386 
visit(TexInstr * instr)387 void CopyPropFwdVisitor::visit(TexInstr *instr)
388 {
389    (void)instr;
390 }
391 
visit(FetchInstr * instr)392 void CopyPropFwdVisitor::visit(FetchInstr *instr)
393 {
394    (void)instr;
395 }
396 
visit(Block * instr)397 void CopyPropFwdVisitor::visit(Block *instr)
398 {
399    for (auto& i: *instr)
400       i->accept(*this);
401 }
402 
CopyPropBackVisitor()403 CopyPropBackVisitor::CopyPropBackVisitor():
404    progress(false)
405 {
406 
407 }
408 
visit(AluInstr * instr)409 void CopyPropBackVisitor::visit(AluInstr *instr)
410 {
411    bool local_progress = false;
412 
413    sfn_log << SfnLog::opt << "CopyPropBackVisitor:["
414            << instr->block_id() << ":" << instr->index() << "] " << *instr << "\n";
415 
416 
417    if (!instr->can_propagate_dest()) {
418       return;
419    }
420 
421    auto src_reg = instr->psrc(0)->as_register();
422    if (!src_reg) {
423       return;
424    }
425 
426    if (src_reg->uses().size() > 1)
427       return;
428 
429    auto dest = instr->dest();
430    if (!dest ||
431        !instr->has_alu_flag(alu_write)) {
432       return;
433    }
434 
435    if (!dest->is_ssa() && dest->parents().size() > 1)
436       return;
437 
438   for (auto& i: src_reg->parents()) {
439      sfn_log << SfnLog::opt << "Try replace dest in "
440              << i->block_id() << ":" << i->index()
441              << *i<< "\n";
442 
443      if (i->replace_dest(dest, instr))  {
444         dest->del_parent(instr);
445         dest->add_parent(i);
446         for (auto d : instr->dependend_instr()) {
447            d->add_required_instr(i);
448         }
449         local_progress = true;
450      }
451   }
452 
453   if (local_progress)
454      instr->set_dead();
455 
456   progress |= local_progress;
457 }
458 
visit(AluGroup * instr)459 void CopyPropBackVisitor::visit(AluGroup *instr)
460 {
461    for (auto& i: *instr) {
462       if (i)
463          i->accept(*this);
464    }
465 }
466 
visit(TexInstr * instr)467 void CopyPropBackVisitor::visit(TexInstr *instr)
468 {
469    (void)instr;
470 }
471 
visit(FetchInstr * instr)472 void CopyPropBackVisitor::visit(FetchInstr *instr)
473 {
474    (void)instr;
475 }
476 
visit(Block * instr)477 void CopyPropBackVisitor::visit(Block *instr)
478 {
479    for (auto i = instr->rbegin(); i != instr->rend(); ++i)
480       if (!(*i)->is_dead())
481          (*i)->accept(*this);
482 }
483 
484 class SimplifySourceVecVisitor : public InstrVisitor {
485 public:
SimplifySourceVecVisitor()486    SimplifySourceVecVisitor():progress(false) {}
487 
visit(AluInstr * instr)488    void visit(AluInstr *instr) override{(void)instr;}
visit(AluGroup * instr)489    void visit(AluGroup *instr) override{(void)instr;}
490    void visit(TexInstr *instr) override;
491    void visit(ExportInstr *instr) override;
492    void visit(FetchInstr *instr) override;
493    void visit(Block *instr) override;
494    void visit(ControlFlowInstr *instr) override;
495    void visit(IfInstr *instr) override;
496    void visit(ScratchIOInstr *instr) override;
497    void visit(StreamOutInstr *instr) override;
498    void visit(MemRingOutInstr *instr) override;
visit(EmitVertexInstr * instr)499    void visit(EmitVertexInstr *instr) override {(void)instr;}
visit(GDSInstr * instr)500    void visit(GDSInstr *instr) override {(void)instr;};
visit(WriteTFInstr * instr)501    void visit(WriteTFInstr *instr) override {(void)instr;};
visit(LDSAtomicInstr * instr)502    void visit(LDSAtomicInstr *instr) override {(void)instr;};
visit(LDSReadInstr * instr)503    void visit(LDSReadInstr *instr) override {(void)instr;};
visit(RatInstr * instr)504    void visit(RatInstr *instr) override {(void)instr;};
505 
506    void replace_src(Instr *instr, RegisterVec4& reg4);
507 
508    bool progress;
509 };
510 
simplify_source_vectors(Shader & sh)511 bool simplify_source_vectors(Shader& sh)
512 {
513    SimplifySourceVecVisitor visitor;
514 
515    for (auto b: sh.func())
516       b->accept(visitor);
517 
518    return visitor.progress;
519 }
520 
visit(TexInstr * instr)521 void SimplifySourceVecVisitor::visit(TexInstr *instr)
522 {
523    if (instr->opcode() != TexInstr::get_resinfo) {
524       replace_src(instr, instr->src());
525    }
526 }
527 
visit(ScratchIOInstr * instr)528 void SimplifySourceVecVisitor::visit(ScratchIOInstr *instr)
529 {
530    (void) instr;
531 }
532 
533 class ReplaceConstSource : public AluInstrVisitor {
534 public:
ReplaceConstSource(Instr * old_use_,RegisterVec4 & vreg_,int i)535    ReplaceConstSource(Instr *old_use_, RegisterVec4& vreg_, int i):
536        old_use(old_use_), vreg(vreg_), index(i),success(false) {}
537 
538    using AluInstrVisitor::visit;
539 
540    void visit(AluInstr *alu) override;
541 
542    Instr *old_use;
543    RegisterVec4& vreg;
544    int index;
545    bool success;
546 };
547 
visit(ExportInstr * instr)548 void SimplifySourceVecVisitor::visit(ExportInstr *instr)
549 {
550    replace_src(instr, instr->value());
551 }
552 
replace_src(Instr * instr,RegisterVec4 & reg4)553 void SimplifySourceVecVisitor::replace_src(Instr *instr, RegisterVec4& reg4)
554 {
555    for (int i = 0; i < 4; ++i) {
556       auto s = reg4[i];
557 
558       if (s->chan() > 3)
559          continue;
560 
561       if (!s->is_ssa())
562          continue;
563 
564       /* Cayman trans ops have more then one parent for
565        * one dest */
566       if (s->parents().size() != 1)
567          continue;
568 
569       auto& op = *s->parents().begin();
570 
571       ReplaceConstSource visitor(instr, reg4, i);
572 
573       op->accept(visitor);
574 
575       progress |= visitor.success;
576    }
577 }
578 
visit(StreamOutInstr * instr)579 void SimplifySourceVecVisitor::visit(StreamOutInstr *instr)
580 {
581    (void)instr;
582 }
583 
visit(MemRingOutInstr * instr)584 void SimplifySourceVecVisitor::visit(MemRingOutInstr *instr)
585 {
586    (void)instr;
587 }
588 
visit(AluInstr * alu)589 void ReplaceConstSource::visit(AluInstr *alu)
590 {
591    if (alu->opcode() != op1_mov)
592       return;
593 
594    if (alu->has_alu_flag(alu_src0_abs) ||
595        alu->has_alu_flag(alu_src0_neg))
596       return;
597 
598    auto src = alu->psrc(0);
599    assert(src);
600 
601    int override_chan = -1;
602 
603    auto ic = src->as_inline_const();
604    if (ic) {
605       if (ic->sel() == ALU_SRC_0)
606          override_chan = 4;
607 
608       if (ic->sel() == ALU_SRC_1)
609          override_chan = 5;
610    }
611 
612    auto literal = src->as_literal();
613    if (literal) {
614 
615       if (literal->value() == 0)
616          override_chan = 4;
617 
618       if (literal->value() == 0x3F800000)
619          override_chan = 5;
620    }
621 
622    if (override_chan >= 0) {
623       vreg[index]->del_use(old_use);
624       auto reg = new Register(vreg.sel(), override_chan, vreg[index]->pin());
625       vreg.set_value(index, reg);
626       success = true;
627    }
628 }
629 
visit(FetchInstr * instr)630 void SimplifySourceVecVisitor::visit(FetchInstr *instr)
631 {
632    (void) instr;
633 }
634 
visit(Block * instr)635 void SimplifySourceVecVisitor::visit(Block *instr)
636 {
637    for (auto i = instr->rbegin(); i != instr->rend(); ++i)
638       if (!(*i)->is_dead())
639          (*i)->accept(*this);
640 }
641 
visit(ControlFlowInstr * instr)642 void SimplifySourceVecVisitor::visit(ControlFlowInstr *instr)
643 {
644    (void) instr;
645 }
646 
visit(IfInstr * instr)647 void SimplifySourceVecVisitor::visit(IfInstr *instr)
648 {
649    (void) instr;
650 }
651 
652 
653 
654 }
655