1 /* -*- mesa-c++ -*-
2 * Copyright 2022 Collabora LTD
3 * Author: Gert Wollny <[email protected]>
4 * SPDX-License-Identifier: MIT
5 */
6
7 #include "sfn_alu_readport_validation.h"
8
9 #include <cstring>
10
11 namespace r600 {
12
13 class ReserveReadport : public ConstRegisterVisitor {
14 public:
15 ReserveReadport(AluReadportReservation& reserv);
16
17 using ConstRegisterVisitor::visit;
18
19 void visit(const LocalArray& value) override;
20 void visit(const LiteralConstant& value) override;
21 void visit(const InlineConstant& value) override;
22
23 void reserve_gpr(int sel, int chan);
24
25 AluReadportReservation& reserver;
26 int cycle = -1;
27 int isrc = -1;
28 int src0_sel = -1;
29 int src0_chan = -1;
30 bool success = true;
31
32 static const int max_const_readports = 2;
33 };
34
35 class ReserveReadportVec : public ReserveReadport {
36 public:
37 using ReserveReadport::ReserveReadport;
38 using ReserveReadport::visit;
39
40 void visit(const Register& value) override;
41 void visit(const LocalArrayValue& value) override;
42 void visit(const UniformValue& value) override;
43 };
44
45 class ReserveReadportTrans : public ReserveReadport {
46 public:
47 ReserveReadportTrans(AluReadportReservation& reserv);
48
49 int n_consts;
50 };
51
52 class ReserveReadportTransPass1 : public ReserveReadportTrans {
53 public:
54 using ReserveReadportTrans::ReserveReadportTrans;
55 using ReserveReadportTrans::visit;
56
57 void visit(const Register& value) override;
58 void visit(const LocalArrayValue& value) override;
59 void visit(const UniformValue& value) override;
60 void visit(const InlineConstant& value) override;
61 void visit(const LiteralConstant& value) override;
62 };
63
64 class ReserveReadportTransPass2 : public ReserveReadportTrans {
65 public:
66 using ReserveReadportTrans::ReserveReadportTrans;
67 using ReserveReadportTrans::visit;
68
69 void visit(const Register& value) override;
70 void visit(const LocalArrayValue& value) override;
71 void visit(const UniformValue& value) override;
72 };
73
74 bool
schedule_vec_src(PVirtualValue src[3],int nsrc,AluBankSwizzle swz)75 AluReadportReservation::schedule_vec_src(PVirtualValue src[3],
76 int nsrc,
77 AluBankSwizzle swz)
78 {
79 ReserveReadportVec visitor(*this);
80
81 if (src[0]->as_register()) {
82 visitor.src0_sel = src[0]->sel();
83 visitor.src0_chan = src[0]->chan();
84 } else {
85 visitor.src0_sel = 0xffff;
86 visitor.src0_chan = 8;
87 }
88
89 for (int i = 0; i < nsrc; ++i) {
90 visitor.cycle = cycle_vec(swz, i);
91 visitor.isrc = i;
92 src[i]->accept(visitor);
93 }
94
95 return visitor.success;
96 }
97
98 bool
schedule_vec_instruction(const AluInstr & alu,AluBankSwizzle swz)99 AluReadportReservation::schedule_vec_instruction(const AluInstr& alu, AluBankSwizzle swz)
100 {
101 ReserveReadportVec visitor(*this);
102
103 for (unsigned i = 0; i < alu.n_sources() && visitor.success; ++i) {
104 visitor.cycle = cycle_vec(swz, i);
105 visitor.isrc = i;
106 if (i == 1 && alu.src(i).equal_to(alu.src(0)))
107 continue;
108 alu.src(i).accept(visitor);
109 }
110 return visitor.success;
111 }
112
113 bool
schedule_trans_instruction(const AluInstr & alu,AluBankSwizzle swz)114 AluReadportReservation::schedule_trans_instruction(const AluInstr& alu,
115 AluBankSwizzle swz)
116 {
117
118 ReserveReadportTransPass1 visitor1(*this);
119
120 for (unsigned i = 0; i < alu.n_sources(); ++i) {
121 visitor1.cycle = cycle_trans(swz, i);
122 alu.src(i).accept(visitor1);
123 }
124 if (!visitor1.success)
125 return false;
126
127 ReserveReadportTransPass2 visitor2(*this);
128 visitor2.n_consts = visitor1.n_consts;
129
130 for (unsigned i = 0; i < alu.n_sources(); ++i) {
131 visitor2.cycle = cycle_trans(swz, i);
132
133 alu.src(i).accept(visitor2);
134 }
135 return visitor2.success;
136 }
137
print(std::ostream & os) const138 void AluReadportReservation::print(std::ostream& os) const
139 {
140 os << "AluReadportReservation\n";
141 for (int i = 0; i < max_chan_channels; ++i) {
142 os << " chan " << i << ":";
143 for (int j = 0; j < max_gpr_readports; ++j) {
144 os << m_hw_gpr[j][i] << " ";
145 }
146 os << "\n";
147 }
148 os << "\n";
149
150 }
151
AluReadportReservation()152 AluReadportReservation::AluReadportReservation()
153 {
154 for (int i = 0; i < max_chan_channels; ++i) {
155 for (int j = 0; j < max_gpr_readports; ++j)
156 m_hw_gpr[j][i] = -1;
157 m_hw_const_addr[i] = -1;
158 m_hw_const_chan[i] = -1;
159 m_hw_const_bank[i] = -1;
160 }
161 }
162
163 bool
reserve_gpr(int sel,int chan,int cycle)164 AluReadportReservation::reserve_gpr(int sel, int chan, int cycle)
165 {
166 if (m_hw_gpr[cycle][chan] == -1) {
167 m_hw_gpr[cycle][chan] = sel;
168 } else if (m_hw_gpr[cycle][chan] != sel) {
169 return false;
170 }
171 return true;
172 }
173
174 bool
reserve_const(const UniformValue & value)175 AluReadportReservation::reserve_const(const UniformValue& value)
176 {
177 int match = -1;
178 int empty = -1;
179
180 for (int res = 0; res < ReserveReadport::max_const_readports; ++res) {
181 if (m_hw_const_addr[res] == -1)
182 empty = res;
183 else if ((m_hw_const_addr[res] == value.sel()) &&
184 (m_hw_const_bank[res] == value.kcache_bank()) &&
185 (m_hw_const_chan[res] == (value.chan() >> 1)))
186 match = res;
187 }
188
189 if (match < 0) {
190 if (empty >= 0) {
191 m_hw_const_addr[empty] = value.sel();
192 (m_hw_const_bank[empty] = value.kcache_bank());
193 m_hw_const_chan[empty] = value.chan() >> 1;
194 } else {
195 return false;
196 }
197 }
198 return true;
199 }
200
201 bool
add_literal(uint32_t value)202 AluReadportReservation::add_literal(uint32_t value)
203 {
204 for (unsigned i = 0; i < m_nliterals; ++i) {
205 if (m_literals[i] == value)
206 return true;
207 }
208 if (m_nliterals < m_literals.size()) {
209 m_literals[m_nliterals++] = value;
210 return true;
211 }
212 return false;
213 }
214
215 int
cycle_vec(AluBankSwizzle swz,int src)216 AluReadportReservation::cycle_vec(AluBankSwizzle swz, int src)
217 {
218 static const int mapping[AluBankSwizzle::alu_vec_unknown][max_gpr_readports] = {
219 {0, 1, 2},
220 {0, 2, 1},
221 {1, 2, 0},
222 {1, 0, 2},
223 {2, 0, 1},
224 {2, 1, 0}
225 };
226 return mapping[swz][src];
227 }
228
229 int
cycle_trans(AluBankSwizzle swz,int src)230 AluReadportReservation::cycle_trans(AluBankSwizzle swz, int src)
231 {
232 static const int mapping[AluBankSwizzle::sq_alu_scl_unknown][max_gpr_readports] = {
233 {2, 1, 0},
234 {1, 2, 2},
235 {2, 1, 2},
236 {2, 2, 1},
237 };
238 return mapping[swz][src];
239 }
240
ReserveReadport(AluReadportReservation & reserv)241 ReserveReadport::ReserveReadport(AluReadportReservation& reserv):
242 reserver(reserv)
243 {
244 }
245
246 void
visit(const LocalArray & value)247 ReserveReadport::visit(const LocalArray& value)
248 {
249 (void)value;
250 unreachable("a full array is not available here");
251 }
252
253 void
visit(const LiteralConstant & value)254 ReserveReadport::visit(const LiteralConstant& value)
255 {
256 success &= reserver.add_literal(value.value());
257 }
258
259 void
visit(const InlineConstant & value)260 ReserveReadport::visit(const InlineConstant& value)
261 {
262 (void)value;
263 }
264
265 void
visit(const Register & value)266 ReserveReadportVec::visit(const Register& value)
267 {
268 reserve_gpr(value.sel(), value.chan());
269 }
270
271 void
visit(const LocalArrayValue & value)272 ReserveReadportVec::visit(const LocalArrayValue& value)
273 {
274 // Set the highest non-sign bit to indicated that we use the
275 // AR register
276 reserve_gpr(0x4000000 | value.sel(), value.chan());
277 }
278
279 void
reserve_gpr(int sel,int chan)280 ReserveReadport::reserve_gpr(int sel, int chan)
281 {
282 if (isrc == 1 && src0_sel == sel && src0_chan == chan)
283 return;
284 success &= reserver.reserve_gpr(sel, chan, cycle);
285 }
286
287 void
visit(const UniformValue & value)288 ReserveReadportVec::visit(const UniformValue& value)
289 {
290 // kcache bank?
291 success &= reserver.reserve_const(value);
292 }
293
ReserveReadportTrans(AluReadportReservation & reserv)294 ReserveReadportTrans::ReserveReadportTrans(AluReadportReservation& reserv):
295 ReserveReadport(reserv),
296 n_consts(0)
297 {
298 }
299
300 void
visit(const Register & value)301 ReserveReadportTransPass1::visit(const Register& value)
302 {
303 (void)value;
304 }
305
306 void
visit(const LocalArrayValue & value)307 ReserveReadportTransPass1::visit(const LocalArrayValue& value)
308 {
309 (void)value;
310 }
311
312 void
visit(const UniformValue & value)313 ReserveReadportTransPass1::visit(const UniformValue& value)
314 {
315 if (n_consts >= max_const_readports) {
316 success = false;
317 return;
318 }
319 n_consts++;
320 success &= reserver.reserve_const(value);
321 }
322
323 void
visit(const InlineConstant & value)324 ReserveReadportTransPass1::visit(const InlineConstant& value)
325 {
326 (void)value;
327 if (n_consts >= max_const_readports) {
328 success = false;
329 return;
330 }
331 n_consts++;
332 }
333
334 void
visit(const LiteralConstant & value)335 ReserveReadportTransPass1::visit(const LiteralConstant& value)
336 {
337 if (n_consts >= max_const_readports) {
338 success = false;
339 return;
340 }
341 n_consts++;
342 success &= reserver.add_literal(value.value());
343 }
344
345 void
visit(const Register & value)346 ReserveReadportTransPass2::visit(const Register& value)
347 {
348 if (cycle < n_consts) {
349 success = false;
350 return;
351 }
352 reserve_gpr(value.sel(), value.chan());
353 }
354
355 void
visit(const LocalArrayValue & value)356 ReserveReadportTransPass2::visit(const LocalArrayValue& value)
357 {
358 if (cycle < n_consts) {
359 success = false;
360 return;
361 }
362 reserve_gpr(0x4000000 | value.sel(), value.chan());
363 }
364
365 void
visit(const UniformValue & value)366 ReserveReadportTransPass2::visit(const UniformValue& value)
367 {
368 (void)value;
369 }
370
371 } // namespace r600
372