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