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