xref: /aosp_15_r20/external/mesa3d/src/gallium/drivers/r600/sfn/sfn_split_address_loads.cpp (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /* -*- mesa-c++  -*-
2  * Copyright 2022 Collabora LTD
3  * Author: Gert Wollny <[email protected]>
4  * SPDX-License-Identifier: MIT
5  */
6 
7 #include "../r600_isa.h"
8 
9 #include "sfn_split_address_loads.h"
10 #include "sfn_alu_defines.h"
11 #include "sfn_defines.h"
12 #include "sfn_instr_alugroup.h"
13 #include "sfn_instr_fetch.h"
14 #include "sfn_instr_mem.h"
15 #include "sfn_instr_tex.h"
16 #include "sfn_instr_export.h"
17 
18 namespace r600 {
19 
20 
21 class AddressSplitVisitor : public InstrVisitor {
22 public:
23    AddressSplitVisitor(Shader& sh);
24 
25 private:
26    void visit(AluInstr *instr) override;
27    void visit(AluGroup *instr) override;
28    void visit(TexInstr *instr) override;
29    void visit(ExportInstr *instr) override;
30    void visit(FetchInstr *instr) override;
31    void visit(Block *instr) override;
32    void visit(ControlFlowInstr *instr) override;
33    void visit(IfInstr *instr) override;
34    void visit(ScratchIOInstr *instr) override;
35    void visit(StreamOutInstr *instr) override;
36    void visit(MemRingOutInstr *instr) override;
37    void visit(EmitVertexInstr *instr) override;
38    void visit(GDSInstr *instr) override;
39    void visit(WriteTFInstr *instr) override;
40    void visit(LDSAtomicInstr *instr) override;
41    void visit(LDSReadInstr *instr) override;
42    void visit(RatInstr *instr) override;
43 
44    void load_ar(Instr *instr, PRegister addr);
45    auto load_index_register(Instr *instr, PRegister index) -> int;
46    auto load_index_register_eg(Instr *instr, PRegister index) -> int;
47    auto load_index_register_ca(PRegister index) -> int;
48    auto reuse_loaded_idx(PRegister index) -> int;
49    auto pick_idx() -> int ;
50 
51    ValueFactory& m_vf;
52    r600_chip_class m_chip_class;
53 
54    Block::iterator m_block_iterator;
55    Block *m_current_block{nullptr};
56    PRegister m_current_addr{nullptr};
57    PRegister m_current_idx[2] {nullptr, nullptr};
58    PRegister m_current_idx_src[2] {nullptr, nullptr};
59 
60 
61    std::list<Instr *> m_last_ar_use;
62    AluInstr *m_last_ar_load{nullptr};
63 
64    unsigned m_linear_index{0};
65    unsigned m_last_idx_load_index[2] {0,0};
66    AluInstr *m_last_idx_load[2] {nullptr, nullptr};
67    std::list<Instr *> m_last_idx_use[2];
68    std::list<Instr *> m_prev_non_alu;
69 
70 };
71 
72 
split_address_loads(Shader & sh)73 bool split_address_loads(Shader& sh)
74 {
75    AddressSplitVisitor visitor(sh);
76    for (auto block : sh.func()) {
77       block->accept(visitor);
78    }
79    return true;
80 }
81 
AddressSplitVisitor(Shader & sh)82 AddressSplitVisitor::AddressSplitVisitor(Shader& sh):
83    m_vf(sh.value_factory()),
84    m_chip_class(sh.chip_class())
85 {
86 }
87 
88 class CollectDeps : public ConstRegisterVisitor {
89 public:
visit(const Register & r)90    void visit(const Register& r) override
91    {
92       for (auto p : r.parents())
93          add_dep(p);
94    }
visit(const LocalArray & value)95    void visit(const LocalArray& value) override {(void)value; unreachable("Array is not a value");}
visit(const LocalArrayValue & r)96    void visit(const LocalArrayValue& r) override
97    {
98       auto& a = r.array();
99       for (auto reg : a) {
100          if (!instr->dest() || !reg->equal_to(*instr->dest())) {
101             for (auto p : reg->parents()) {
102                if ((instr->block_id() == p->block_id()) &&
103                    (instr->index() > p->index()))
104                   add_dep(p);
105             }
106          }
107       }
108    }
visit(const UniformValue & value)109    void visit(const UniformValue& value) override {(void)value;}
visit(const LiteralConstant & value)110    void visit(const LiteralConstant& value) override {(void)value;}
visit(const InlineConstant & value)111    void visit(const InlineConstant& value) override {(void)value;}
112 
add_dep(Instr * p)113    void add_dep(Instr *p) {
114 
115       auto alu = p->as_alu();
116       if (!alu || alu_level > 1) {
117          instr->add_required_instr(p);
118       } else  {
119          ++alu_level;
120          for (auto& s : alu->sources()) {
121             if (!alu->dest() || !alu->dest()->equal_to(*s))
122                s->accept(*this);
123          }
124          --alu_level;
125       }
126    }
127    int alu_level{0};
128 
129    AluInstr *instr;
130 };
131 
132 
visit(AluInstr * instr)133 void AddressSplitVisitor::visit(AluInstr *instr)
134 {
135    auto [addr, is_for_dest, index] = instr->indirect_addr();
136 
137    if (addr) {
138       assert(!index);
139 
140       if (!m_current_addr || !m_current_addr->equal_to(*addr)) {
141          load_ar(instr, addr);
142          for (auto na: m_prev_non_alu)
143             m_last_ar_load->add_required_instr(na);
144       }
145 
146       // Do this with a visitor to catch also local array values
147       CollectDeps collector;
148       collector.instr = m_last_ar_load;
149       for (auto& s : instr->sources()) {
150          s->accept(collector);
151       }
152 
153       instr->update_indirect_addr(addr, m_vf.addr());
154       addr->del_use(instr);
155       m_last_ar_load->inc_ar_uses();
156       m_last_ar_use.push_back(instr);
157    }
158 
159    if (index)
160       load_index_register(instr, index);
161 }
162 
load_index_register(Instr * instr,PRegister index)163 auto AddressSplitVisitor::load_index_register(Instr *instr, PRegister index) -> int
164 {
165    int idx_id = m_chip_class < ISA_CC_CAYMAN ?
166                    load_index_register_eg(instr, index):
167                    load_index_register_ca(index);
168 
169    m_last_idx_use[idx_id].push_back(instr);
170 
171    index->del_use(instr);
172    instr->update_indirect_addr(index, m_current_idx[idx_id]);
173    m_last_idx_load_index[idx_id] = (instr->block_id() << 16) | instr->index();
174    return idx_id == 0 ? bim_zero : bim_one;
175 }
176 
load_index_register_eg(Instr * instr,PRegister index)177 auto AddressSplitVisitor::load_index_register_eg(Instr *instr,
178                                                  PRegister index)  -> int
179 {
180    int idx_id = reuse_loaded_idx(index);
181    if (idx_id < 0) {
182       load_ar(instr, index);
183 
184       idx_id = pick_idx();
185       auto idx = m_vf.idx_reg(idx_id);
186 
187       const EAluOp idx_op[2] = {op1_set_cf_idx0, op1_set_cf_idx1};
188 
189       m_last_idx_load[idx_id] = new AluInstr(idx_op[idx_id], idx, m_vf.addr(), {});
190       m_current_block->insert(m_block_iterator, m_last_idx_load[idx_id]);
191       for (auto&& i : m_last_idx_use[idx_id])
192          m_last_ar_load->add_required_instr(i);
193 
194       m_last_idx_use[idx_id].clear();
195       m_last_idx_load[idx_id]->add_required_instr(m_last_ar_load);
196 
197       m_last_ar_load->inc_ar_uses();
198       m_last_ar_use.push_back(m_last_idx_load[idx_id]);
199       m_current_idx[idx_id] = idx;
200       m_current_idx_src[idx_id] = index;
201 
202    }
203    return idx_id;
204 }
205 
load_index_register_ca(PRegister index)206 auto AddressSplitVisitor::load_index_register_ca(PRegister index)  -> int
207 {
208    int idx_id = reuse_loaded_idx(index);
209    if (idx_id < 0) {
210       idx_id = pick_idx();
211       auto idx = m_vf.idx_reg(idx_id);
212       m_last_idx_load[idx_id] = new AluInstr(op1_mova_int, idx, index, {});
213 
214       m_current_block->insert(m_block_iterator, m_last_idx_load[idx_id]);
215       for (auto&& i : m_last_idx_use[idx_id])
216          m_last_idx_load[idx_id]->add_required_instr(i);
217       m_last_idx_use[idx_id].clear();
218       m_current_idx[idx_id] = idx;
219       m_current_idx_src[idx_id] = index;
220 
221    }
222    return idx_id;
223 }
224 
reuse_loaded_idx(PRegister index)225 auto AddressSplitVisitor::reuse_loaded_idx(PRegister index) -> int
226 {
227    for (int i = 0; i < 2; ++i) {
228       if (m_current_idx_src[i] && m_current_idx_src[i]->equal_to(*index)) {
229          return i;
230       }
231    }
232    return -1;
233 }
234 
pick_idx()235 auto AddressSplitVisitor::pick_idx() -> int
236 {
237    int idx_id = -1;
238    if (!m_current_idx[0]) {
239       idx_id = 0;
240    } else if (!m_current_idx[1]) {
241       idx_id = 1;
242    } else {
243       idx_id = m_last_idx_load_index[0] < m_last_idx_load_index[1] ? 0 : 1;
244    }
245    return idx_id;
246 }
247 
248 
load_ar(Instr * instr,PRegister addr)249 void AddressSplitVisitor::load_ar(Instr *instr, PRegister addr)
250 {
251    auto ar = m_vf.addr();
252 
253    m_last_ar_load = new AluInstr(op1_mova_int, ar, addr, {});
254    m_current_block->insert(m_block_iterator, m_last_ar_load);
255    ar->add_use(instr);
256    m_current_addr = addr;
257    for (auto& i : m_last_ar_use) {
258       m_last_ar_load->add_required_instr(i);
259    }
260    m_last_ar_use.clear();
261 }
262 
263 
visit(AluGroup * instr)264 void AddressSplitVisitor::visit(AluGroup *instr)
265 {
266    for (auto& i : *instr)
267       if (i)
268          this->visit(i);
269 }
270 
visit(TexInstr * instr)271 void AddressSplitVisitor::visit(TexInstr *instr)
272 {
273    if (instr->resource_offset())
274       load_index_register(instr, instr->resource_offset());
275    if (instr->sampler_offset())
276       load_index_register(instr, instr->sampler_offset());
277 
278    m_prev_non_alu.push_back(instr);
279    m_current_addr = nullptr;
280 }
visit(ExportInstr * instr)281 void AddressSplitVisitor::visit(ExportInstr *instr)
282 {
283    (void)instr;
284    m_current_addr = nullptr;
285 }
286 
visit(FetchInstr * instr)287 void AddressSplitVisitor::visit(FetchInstr *instr)
288 {
289    if (instr->resource_offset())
290       load_index_register(instr, instr->resource_offset());
291    m_prev_non_alu.push_back(instr);
292    m_current_addr = nullptr;
293 }
294 
visit(Block * instr)295 void AddressSplitVisitor::visit(Block *instr)
296 {
297    m_current_block = instr;
298    m_block_iterator = instr->begin();
299    m_last_ar_load = nullptr;
300    m_current_addr = nullptr;
301    m_last_ar_use.clear();
302    auto e = instr->end();
303    while (m_block_iterator != e) {
304       (*m_block_iterator)->accept(*this);
305       ++m_block_iterator;
306    }
307 
308    // renumber instructions
309    int new_index = 0;
310    for (auto&& i : *instr)
311       i->set_blockid(m_current_block->id(), new_index++);
312 }
visit(ControlFlowInstr * instr)313 void AddressSplitVisitor::visit(ControlFlowInstr *instr)
314 {
315     (void)instr;
316    m_current_addr = nullptr;
317 }
visit(IfInstr * instr)318 void AddressSplitVisitor::visit(IfInstr *instr)
319 {
320    visit(instr->predicate());
321    m_current_addr = nullptr;
322 }
visit(ScratchIOInstr * instr)323 void AddressSplitVisitor::visit(ScratchIOInstr *instr)
324 {
325     m_prev_non_alu.push_back(instr);
326     m_current_addr = nullptr;
327     (void)instr;
328 }
visit(StreamOutInstr * instr)329 void AddressSplitVisitor::visit(StreamOutInstr *instr)
330 {
331     m_prev_non_alu.push_back(instr);
332     m_current_addr = nullptr;
333     (void)instr;
334 }
visit(MemRingOutInstr * instr)335 void AddressSplitVisitor::visit(MemRingOutInstr *instr)
336 {
337     m_prev_non_alu.push_back(instr);
338     m_current_addr = nullptr;
339     (void)instr;
340 }
visit(EmitVertexInstr * instr)341 void AddressSplitVisitor::visit(EmitVertexInstr *instr)
342 {
343     m_prev_non_alu.push_back(instr);
344     m_current_addr = nullptr;
345     (void)instr;
346 }
visit(GDSInstr * instr)347 void AddressSplitVisitor::visit(GDSInstr *instr)
348 {
349    if (instr->resource_offset())
350       load_index_register(instr, instr->resource_offset());
351    m_prev_non_alu.push_back(instr);
352    m_current_addr = nullptr;
353 }
visit(WriteTFInstr * instr)354 void AddressSplitVisitor::visit(WriteTFInstr *instr)
355 {
356     m_prev_non_alu.push_back(instr);
357     m_current_addr = nullptr;
358     (void)instr;
359 }
360 
visit(LDSAtomicInstr * instr)361 void AddressSplitVisitor::visit(LDSAtomicInstr *instr)
362 {
363    (void)instr;
364 }
365 
visit(LDSReadInstr * instr)366 void AddressSplitVisitor::visit(LDSReadInstr *instr)
367 {
368    (void)instr;
369 }
visit(RatInstr * instr)370 void AddressSplitVisitor::visit(RatInstr *instr)
371 {
372    if (instr->resource_offset())
373       load_index_register(instr, instr->resource_offset());
374    m_prev_non_alu.push_back(instr);
375    m_current_addr = nullptr;
376 }
377 
378 }
379