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