3
* Copyright (c) 2022 Collabora LTD
5
* Author: Gert Wollny <gert.wollny@collabora.com>
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:
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
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.
27
#include "sfn_split_address_loads.h"
29
#include "sfn_alu_defines.h"
30
#include "sfn_defines.h"
31
#include "sfn_instr_alugroup.h"
32
#include "sfn_instr_fetch.h"
33
#include "sfn_instr_mem.h"
34
#include "sfn_instr_tex.h"
35
#include "sfn_instr_export.h"
40
class AddressSplitVisitor : public InstrVisitor {
42
AddressSplitVisitor(Shader& sh);
45
void visit(AluInstr *instr) override;
46
void visit(AluGroup *instr) override;
47
void visit(TexInstr *instr) override;
48
void visit(ExportInstr *instr) override;
49
void visit(FetchInstr *instr) override;
50
void visit(Block *instr) override;
51
void visit(ControlFlowInstr *instr) override;
52
void visit(IfInstr *instr) override;
53
void visit(ScratchIOInstr *instr) override;
54
void visit(StreamOutInstr *instr) override;
55
void visit(MemRingOutInstr *instr) override;
56
void visit(EmitVertexInstr *instr) override;
57
void visit(GDSInstr *instr) override;
58
void visit(WriteTFInstr *instr) override;
59
void visit(LDSAtomicInstr *instr) override;
60
void visit(LDSReadInstr *instr) override;
61
void visit(RatInstr *instr) override;
63
void load_ar(Instr *instr, PRegister addr);
64
auto load_index_register(Instr *instr, PRegister index) -> int;
65
auto load_index_register_eg(Instr *instr, PRegister index) -> int;
66
auto load_index_register_ca(PRegister index) -> int;
67
auto reuse_loaded_idx(PRegister index) -> int;
68
auto pick_idx() -> int ;
71
r600_chip_class m_chip_class;
73
Block::iterator m_block_iterator;
74
Block *m_current_block{nullptr};
75
PRegister m_current_addr{nullptr};
76
PRegister m_current_idx[2] {nullptr, nullptr};
77
PRegister m_current_idx_src[2] {nullptr, nullptr};
80
std::list<Instr *> m_last_ar_use;
81
AluInstr *m_last_ar_load{nullptr};
83
unsigned m_linear_index{0};
84
unsigned m_last_idx_load_index[2] {0,0};
85
AluInstr *m_last_idx_load[2] {nullptr, nullptr};
86
std::list<Instr *> m_last_idx_use[2];
87
std::list<Instr *> m_prev_non_alu;
92
bool split_address_loads(Shader& sh)
94
AddressSplitVisitor visitor(sh);
95
for (auto block : sh.func()) {
96
block->accept(visitor);
101
AddressSplitVisitor::AddressSplitVisitor(Shader& sh):
102
m_vf(sh.value_factory()),
103
m_chip_class(sh.chip_class())
107
class CollectDeps : public ConstRegisterVisitor {
109
void visit(const Register& r) override
111
for (auto p : r.parents())
114
void visit(const LocalArray& value) override {(void)value; unreachable("Array is not a value");}
115
void visit(const LocalArrayValue& r) override
119
if (!instr->dest() || !reg->equal_to(*instr->dest())) {
120
for (auto p : reg->parents()) {
121
if ((instr->block_id() == p->block_id()) &&
122
(instr->index() > p->index()))
128
void visit(const UniformValue& value) override {(void)value;}
129
void visit(const LiteralConstant& value) override {(void)value;}
130
void visit(const InlineConstant& value) override {(void)value;}
132
void add_dep(Instr *p) {
134
auto alu = p->as_alu();
135
if (!alu || alu_level > 1) {
136
instr->add_required_instr(p);
139
for (auto& s : alu->sources()) {
140
if (!alu->dest() || !alu->dest()->equal_to(*s))
152
void AddressSplitVisitor::visit(AluInstr *instr)
154
auto [addr, is_for_dest, index] = instr->indirect_addr();
159
if (!m_current_addr || !m_current_addr->equal_to(*addr))
160
load_ar(instr, addr);
162
// Do this with a visitor to catch also local array values
163
CollectDeps collector;
164
collector.instr = m_last_ar_load;
165
for (auto& s : instr->sources()) {
166
s->accept(collector);
169
instr->update_indirect_addr(m_vf.addr());
170
addr->del_use(instr);
171
m_last_ar_load->inc_ar_uses();
172
m_last_ar_use.push_back(instr);
176
load_index_register(instr, index);
179
auto AddressSplitVisitor::load_index_register(Instr *instr, PRegister index) -> int
181
int idx_id = m_chip_class < ISA_CC_CAYMAN ?
182
load_index_register_eg(instr, index):
183
load_index_register_ca(index);
185
m_last_idx_use[idx_id].push_back(instr);
187
index->del_use(instr);
188
instr->update_indirect_addr(m_current_idx[idx_id]);
189
m_last_idx_load_index[idx_id] = (instr->block_id() << 16) | instr->index();
190
return idx_id == 0 ? bim_zero : bim_one;
193
auto AddressSplitVisitor::load_index_register_eg(Instr *instr,
194
PRegister index) -> int
196
int idx_id = reuse_loaded_idx(index);
198
load_ar(instr, index);
201
auto idx = m_vf.idx_reg(idx_id);
203
const EAluOp idx_op[2] = {op1_set_cf_idx0, op1_set_cf_idx1};
205
m_last_idx_load[idx_id] = new AluInstr(idx_op[idx_id], idx, m_vf.addr(), {});
206
m_current_block->insert(m_block_iterator, m_last_idx_load[idx_id]);
207
for (auto&& i : m_last_idx_use[idx_id])
208
m_last_idx_load[idx_id]->add_required_instr(i);
209
m_last_idx_use[idx_id].clear();
211
m_last_ar_load->inc_ar_uses();
212
m_last_ar_use.push_back(m_last_idx_load[idx_id]);
213
m_current_idx[idx_id] = idx;
214
m_current_idx_src[idx_id] = index;
220
auto AddressSplitVisitor::load_index_register_ca(PRegister index) -> int
222
int idx_id = reuse_loaded_idx(index);
225
auto idx = m_vf.idx_reg(idx_id);
226
m_last_idx_load[idx_id] = new AluInstr(op1_mova_int, idx, index, {});
228
m_current_block->insert(m_block_iterator, m_last_idx_load[idx_id]);
229
for (auto&& i : m_last_idx_use[idx_id])
230
m_last_idx_load[idx_id]->add_required_instr(i);
231
m_last_idx_use[idx_id].clear();
232
m_current_idx[idx_id] = idx;
233
m_current_idx_src[idx_id] = index;
239
auto AddressSplitVisitor::reuse_loaded_idx(PRegister index) -> int
241
for (int i = 0; i < 2; ++i) {
242
if (m_current_idx_src[i] && m_current_idx_src[i]->equal_to(*index)) {
249
auto AddressSplitVisitor::pick_idx() -> int
252
if (!m_current_idx[0]) {
254
} else if (!m_current_idx[1]) {
257
idx_id = m_last_idx_load_index[0] < m_last_idx_load_index[1] ? 0 : 1;
263
void AddressSplitVisitor::load_ar(Instr *instr, PRegister addr)
265
auto ar = m_vf.addr();
267
m_last_ar_load = new AluInstr(op1_mova_int, ar, addr, {});
268
m_current_block->insert(m_block_iterator, m_last_ar_load);
270
m_current_addr = addr;
271
for (auto& i : m_last_ar_use) {
272
m_last_ar_load->add_required_instr(i);
274
for (auto na: m_prev_non_alu) {
275
m_last_ar_load->add_required_instr(na);
277
m_last_ar_use.clear();
281
void AddressSplitVisitor::visit(AluGroup *instr)
283
for (auto& i : *instr)
288
void AddressSplitVisitor::visit(TexInstr *instr)
290
if (instr->resource_offset())
291
load_index_register(instr, instr->resource_offset());
292
m_prev_non_alu.push_back(instr);
293
m_current_addr = nullptr;
295
void AddressSplitVisitor::visit(ExportInstr *instr)
298
m_current_addr = nullptr;
301
void AddressSplitVisitor::visit(FetchInstr *instr)
303
if (instr->resource_offset())
304
load_index_register(instr, instr->resource_offset());
305
m_prev_non_alu.push_back(instr);
306
m_current_addr = nullptr;
309
void AddressSplitVisitor::visit(Block *instr)
311
m_current_block = instr;
312
m_block_iterator = instr->begin();
313
m_last_ar_load = nullptr;
314
m_current_addr = nullptr;
315
m_last_ar_use.clear();
316
auto e = instr->end();
317
while (m_block_iterator != e) {
318
(*m_block_iterator)->accept(*this);
322
// renumber instructions
324
for (auto&& i : *instr)
325
i->set_blockid(m_current_block->id(), new_index++);
327
void AddressSplitVisitor::visit(ControlFlowInstr *instr)
330
m_current_addr = nullptr;
332
void AddressSplitVisitor::visit(IfInstr *instr)
334
visit(instr->predicate());
335
m_current_addr = nullptr;
337
void AddressSplitVisitor::visit(ScratchIOInstr *instr)
339
m_prev_non_alu.push_back(instr);
340
m_current_addr = nullptr;
343
void AddressSplitVisitor::visit(StreamOutInstr *instr)
345
m_prev_non_alu.push_back(instr);
346
m_current_addr = nullptr;
349
void AddressSplitVisitor::visit(MemRingOutInstr *instr)
351
m_prev_non_alu.push_back(instr);
352
m_current_addr = nullptr;
355
void AddressSplitVisitor::visit(EmitVertexInstr *instr)
357
m_prev_non_alu.push_back(instr);
358
m_current_addr = nullptr;
361
void AddressSplitVisitor::visit(GDSInstr *instr)
363
if (instr->resource_offset())
364
load_index_register(instr, instr->resource_offset());
365
m_prev_non_alu.push_back(instr);
366
m_current_addr = nullptr;
368
void AddressSplitVisitor::visit(WriteTFInstr *instr)
370
m_prev_non_alu.push_back(instr);
371
m_current_addr = nullptr;
375
void AddressSplitVisitor::visit(LDSAtomicInstr *instr)
380
void AddressSplitVisitor::visit(LDSReadInstr *instr)
384
void AddressSplitVisitor::visit(RatInstr *instr)
386
if (instr->resource_offset())
387
load_index_register(instr, instr->resource_offset());
388
m_prev_non_alu.push_back(instr);
389
m_current_addr = nullptr;