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