• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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