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