1 /* -*- mesa-c++ -*-
2 * Copyright 2022 Collabora LTD
3 * Author: Gert Wollny <[email protected]>
4 * SPDX-License-Identifier: MIT
5 */
6
7 #include "sfn_instr_export.h"
8
9 #include "sfn_valuefactory.h"
10
11 #include <sstream>
12
13 namespace r600 {
14
15 using std::string;
16
17 static char *
writemask_to_swizzle(int writemask,char * buf)18 writemask_to_swizzle(int writemask, char *buf)
19 {
20 const char *swz = "xyzw";
21 for (int i = 0; i < 4; ++i) {
22 buf[i] = (writemask & (1 << i)) ? swz[i] : '_';
23 }
24 return buf;
25 }
26
WriteOutInstr(const RegisterVec4 & value)27 WriteOutInstr::WriteOutInstr(const RegisterVec4& value):
28 m_value(value)
29 {
30 m_value.add_use(this);
31 set_always_keep();
32 }
33
34 void
override_chan(int i,int chan)35 WriteOutInstr::override_chan(int i, int chan)
36 {
37 m_value.set_value(i, new Register(m_value[i]->sel(), chan, m_value[i]->pin()));
38 }
39
ExportInstr(ExportType type,unsigned loc,const RegisterVec4 & value)40 ExportInstr::ExportInstr(ExportType type, unsigned loc, const RegisterVec4& value):
41 WriteOutInstr(value),
42 m_type(type),
43 m_loc(loc),
44 m_is_last(false)
45 {
46 }
47
48 void
accept(ConstInstrVisitor & visitor) const49 ExportInstr::accept(ConstInstrVisitor& visitor) const
50 {
51 visitor.visit(*this);
52 }
53
54 void
accept(InstrVisitor & visitor)55 ExportInstr::accept(InstrVisitor& visitor)
56 {
57 visitor.visit(this);
58 }
59
60 bool
is_equal_to(const ExportInstr & lhs) const61 ExportInstr::is_equal_to(const ExportInstr& lhs) const
62 {
63 return
64
65 (m_type == lhs.m_type && m_loc == lhs.m_loc && value() == lhs.value() &&
66 m_is_last == lhs.m_is_last);
67 }
68
69 ExportInstr::ExportType
type_from_string(const std::string & s)70 ExportInstr::type_from_string(const std::string& s)
71 {
72 (void)s;
73 return param;
74 }
75
76 void
do_print(std::ostream & os) const77 ExportInstr::do_print(std::ostream& os) const
78 {
79 os << "EXPORT";
80 if (m_is_last)
81 os << "_DONE";
82
83 switch (m_type) {
84 case param:
85 os << " PARAM ";
86 break;
87 case pos:
88 os << " POS ";
89 break;
90 case pixel:
91 os << " PIXEL ";
92 break;
93 }
94 os << m_loc << " ";
95 value().print(os);
96 }
97
98 bool
do_ready() const99 ExportInstr::do_ready() const
100 {
101 return value().ready(block_id(), index());
102 }
103
104 Instr::Pointer
from_string(std::istream & is,ValueFactory & vf)105 ExportInstr::from_string(std::istream& is, ValueFactory& vf)
106 {
107 return from_string_impl(is, vf);
108 }
109
110 Instr::Pointer
last_from_string(std::istream & is,ValueFactory & vf)111 ExportInstr::last_from_string(std::istream& is, ValueFactory& vf)
112 {
113 auto result = from_string_impl(is, vf);
114 result->set_is_last_export(true);
115 return result;
116 }
117
118 ExportInstr::Pointer
from_string_impl(std::istream & is,ValueFactory & vf)119 ExportInstr::from_string_impl(std::istream& is, ValueFactory& vf)
120 {
121 string typestr;
122 int pos;
123 string value_str;
124
125 is >> typestr >> pos >> value_str;
126
127 ExportInstr::ExportType type;
128
129 if (typestr == "PARAM")
130 type = ExportInstr::param;
131 else if (typestr == "POS")
132 type = ExportInstr::pos;
133 else if (typestr == "PIXEL")
134 type = ExportInstr::pixel;
135 else
136 unreachable("Unknown export type");
137
138 RegisterVec4 value = vf.src_vec4_from_string(value_str);
139
140 return new ExportInstr(type, pos, value);
141 }
142
143 uint8_t
allowed_src_chan_mask() const144 ExportInstr::allowed_src_chan_mask() const
145 {
146 return value().free_chan_mask();
147 }
148
ScratchIOInstr(const RegisterVec4 & value,PRegister addr,int align,int align_offset,int writemask,int array_size,bool is_read)149 ScratchIOInstr::ScratchIOInstr(const RegisterVec4& value,
150 PRegister addr,
151 int align,
152 int align_offset,
153 int writemask,
154 int array_size,
155 bool is_read):
156 WriteOutInstr(value),
157 m_address(addr),
158 m_align(align),
159 m_align_offset(align_offset),
160 m_writemask(writemask),
161 m_array_size(array_size - 1),
162 m_read(is_read)
163 {
164 addr->add_use(this);
165 if (m_read) {
166 for (int i = 0; i < 4; ++i)
167 value[i]->add_parent(this);
168 }
169 }
170
ScratchIOInstr(const RegisterVec4 & value,int loc,int align,int align_offset,int writemask,bool is_read)171 ScratchIOInstr::ScratchIOInstr(const RegisterVec4& value,
172 int loc,
173 int align,
174 int align_offset,
175 int writemask,
176 bool is_read):
177 WriteOutInstr(value),
178 m_loc(loc),
179 m_align(align),
180 m_align_offset(align_offset),
181 m_writemask(writemask),
182 m_read(is_read)
183 {
184 if (m_read) {
185
186 for (int i = 0; i < 4; ++i)
187 value[i]->add_parent(this);
188 }
189 }
190
191 void
accept(ConstInstrVisitor & visitor) const192 ScratchIOInstr::accept(ConstInstrVisitor& visitor) const
193 {
194 visitor.visit(*this);
195 }
196
197 void
accept(InstrVisitor & visitor)198 ScratchIOInstr::accept(InstrVisitor& visitor)
199 {
200 visitor.visit(this);
201 }
202
203 bool
is_equal_to(const ScratchIOInstr & lhs) const204 ScratchIOInstr::is_equal_to(const ScratchIOInstr& lhs) const
205 {
206 if (m_address) {
207 if (!lhs.m_address)
208 return false;
209 if (!m_address->equal_to(*lhs.m_address))
210 return false;
211 } else if (lhs.m_address)
212 return false;
213
214 return m_loc == lhs.m_loc && m_align == lhs.m_align &&
215 m_align_offset == lhs.m_align_offset && m_writemask == lhs.m_writemask &&
216 m_array_size == lhs.m_array_size && value().sel() == lhs.value().sel();
217 }
218
219 bool
do_ready() const220 ScratchIOInstr::do_ready() const
221 {
222 bool address_ready = !m_address || m_address->ready(block_id(), index());
223 if (is_read())
224 return address_ready;
225 else
226 return address_ready && value().ready(block_id(), index());
227 }
228
229 void
do_print(std::ostream & os) const230 ScratchIOInstr::do_print(std::ostream& os) const
231 {
232 char buf[6] = {0};
233
234 os << (is_read() ? "READ_SCRATCH " : "WRITE_SCRATCH ");
235
236 if (is_read()) {
237 os << (value()[0]->has_flag(Register::ssa) ? " S" : " R") << value().sel() << "."
238 << writemask_to_swizzle(m_writemask, buf) << " ";
239 }
240
241 if (m_address)
242 os << "@" << *m_address << "[" << m_array_size + 1 << "]";
243 else
244 os << m_loc;
245
246 if (!is_read())
247 os << (value()[0]->has_flag(Register::ssa) ? " S" : " R") << value().sel() << "."
248 << writemask_to_swizzle(m_writemask, buf);
249
250 os << " "
251 << "AL:" << m_align << " ALO:" << m_align_offset;
252 }
253
254 auto
from_string(std::istream & is,ValueFactory & vf)255 ScratchIOInstr::from_string(std::istream& is, ValueFactory& vf) -> Pointer
256 {
257 string loc_str;
258 string value_str;
259 string align_str;
260 string align_offset_str;
261 int offset;
262
263 int array_size = 0;
264 PVirtualValue addr_reg = nullptr;
265
266 is >> loc_str >> value_str >> align_str >> align_offset_str;
267
268 std::istringstream loc_ss(loc_str);
269
270 auto align = int_from_string_with_prefix(align_str, "AL:");
271 auto align_offset = int_from_string_with_prefix(align_offset_str, "ALO:");
272 auto value = vf.src_vec4_from_string(value_str);
273
274 int writemask = 0;
275 for (int i = 0; i < 4; ++i) {
276 if (value[i]->chan() == i)
277 writemask |= 1 << i;
278 }
279
280 if (loc_str[0] == '@') {
281
282 string addr_str;
283 char c;
284 loc_ss >> c;
285 loc_ss >> c;
286
287 while (!loc_ss.eof() && c != '[') {
288 addr_str.append(1, c);
289 loc_ss >> c;
290 }
291 addr_reg = vf.src_from_string(addr_str);
292 assert(addr_reg && addr_reg->as_register());
293
294 loc_ss >> array_size;
295 loc_ss >> c;
296 assert(c == ']');
297 return new ScratchIOInstr(
298 value, addr_reg->as_register(), align, align_offset, writemask, array_size);
299 } else {
300 loc_ss >> offset;
301 return new ScratchIOInstr(value, offset, align, align_offset, writemask);
302 }
303 }
304
StreamOutInstr(const RegisterVec4 & value,int num_components,int array_base,int comp_mask,int out_buffer,int stream)305 StreamOutInstr::StreamOutInstr(const RegisterVec4& value,
306 int num_components,
307 int array_base,
308 int comp_mask,
309 int out_buffer,
310 int stream):
311 WriteOutInstr(value),
312 m_element_size(num_components == 3 ? 3 : num_components - 1),
313 m_array_base(array_base),
314 m_writemask(comp_mask),
315 m_output_buffer(out_buffer),
316 m_stream(stream)
317 {
318 }
319
320 unsigned
op(amd_gfx_level gfx_level) const321 StreamOutInstr::op(amd_gfx_level gfx_level) const
322 {
323 int op = 0;
324 if (gfx_level >= EVERGREEN) {
325 switch (m_output_buffer) {
326 case 0:
327 op = CF_OP_MEM_STREAM0_BUF0;
328 break;
329 case 1:
330 op = CF_OP_MEM_STREAM0_BUF1;
331 break;
332 case 2:
333 op = CF_OP_MEM_STREAM0_BUF2;
334 break;
335 case 3:
336 op = CF_OP_MEM_STREAM0_BUF3;
337 break;
338 }
339 return 4 * m_stream + op;
340 } else {
341 assert(m_stream == 0);
342 return CF_OP_MEM_STREAM0 + m_output_buffer;
343 }
344 }
345
346 bool
is_equal_to(const StreamOutInstr & oth) const347 StreamOutInstr::is_equal_to(const StreamOutInstr& oth) const
348 {
349
350 return value() == oth.value() && m_element_size == oth.m_element_size &&
351 m_burst_count == oth.m_burst_count && m_array_base == oth.m_array_base &&
352 m_array_size == oth.m_array_size && m_writemask == oth.m_writemask &&
353 m_output_buffer == oth.m_output_buffer && m_stream == oth.m_stream;
354 }
355
356 void
do_print(std::ostream & os) const357 StreamOutInstr::do_print(std::ostream& os) const
358 {
359 os << "WRITE STREAM(" << m_stream << ") " << value() << " ES:" << m_element_size
360 << " BC:" << m_burst_count << " BUF:" << m_output_buffer
361 << " ARRAY:" << m_array_base;
362 if (m_array_size != 0xfff)
363 os << "+" << m_array_size;
364 }
365
366 bool
do_ready() const367 StreamOutInstr::do_ready() const
368 {
369 return value().ready(block_id(), index());
370 }
371
372 void
accept(ConstInstrVisitor & visitor) const373 StreamOutInstr::accept(ConstInstrVisitor& visitor) const
374 {
375 visitor.visit(*this);
376 }
377
378 void
accept(InstrVisitor & visitor)379 StreamOutInstr::accept(InstrVisitor& visitor)
380 {
381 visitor.visit(this);
382 }
383
MemRingOutInstr(ECFOpCode ring,EMemWriteType type,const RegisterVec4 & value,unsigned base_addr,unsigned ncomp,PRegister index)384 MemRingOutInstr::MemRingOutInstr(ECFOpCode ring,
385 EMemWriteType type,
386 const RegisterVec4& value,
387 unsigned base_addr,
388 unsigned ncomp,
389 PRegister index):
390 WriteOutInstr(value),
391 m_ring_op(ring),
392 m_type(type),
393 m_base_address(base_addr),
394 m_num_comp(ncomp),
395 m_export_index(index)
396 {
397 assert(m_ring_op == cf_mem_ring || m_ring_op == cf_mem_ring1 ||
398 m_ring_op == cf_mem_ring2 || m_ring_op == cf_mem_ring3);
399 assert(m_num_comp <= 4);
400
401 if (m_export_index)
402 m_export_index->add_use(this);
403 }
404
405 unsigned
ncomp() const406 MemRingOutInstr::ncomp() const
407 {
408 switch (m_num_comp) {
409 case 1:
410 return 0;
411 case 2:
412 return 1;
413 case 3:
414 case 4:
415 return 3;
416 default:
417 assert(0);
418 }
419 return 3;
420 }
421
422 bool
is_equal_to(const MemRingOutInstr & oth) const423 MemRingOutInstr::is_equal_to(const MemRingOutInstr& oth) const
424 {
425
426 bool equal = value() == oth.value() && m_ring_op == oth.m_ring_op &&
427 m_type == oth.m_type && m_num_comp == oth.m_num_comp &&
428 m_base_address == oth.m_base_address;
429
430 if (m_type == mem_write_ind || m_type == mem_write_ind_ack)
431 equal &= (*m_export_index == *oth.m_export_index);
432 return equal;
433 }
434
435 static const char *write_type_str[4] = {
436 "WRITE", "WRITE_IDX", "WRITE_ACK", "WRITE_IDX_ACK"};
437 void
do_print(std::ostream & os) const438 MemRingOutInstr::do_print(std::ostream& os) const
439 {
440
441 os << "MEM_RING " << (m_ring_op == cf_mem_ring ? 0 : m_ring_op - cf_mem_ring1 + 1);
442 os << " " << write_type_str[m_type] << " " << m_base_address;
443 os << " " << value();
444 if (m_type == mem_write_ind || m_type == mem_write_ind_ack)
445 os << " @" << *m_export_index;
446 os << " ES:" << m_num_comp;
447 }
448
449 void
patch_ring(int stream,PRegister index)450 MemRingOutInstr::patch_ring(int stream, PRegister index)
451 {
452 const ECFOpCode ring_op[4] = {cf_mem_ring, cf_mem_ring1, cf_mem_ring2, cf_mem_ring3};
453
454 assert(stream < 4);
455 m_ring_op = ring_op[stream];
456 m_export_index = index;
457 }
458
459 bool
do_ready() const460 MemRingOutInstr::do_ready() const
461 {
462 if (m_export_index && !m_export_index->ready(block_id(), index()))
463 return false;
464
465 return value().ready(block_id(), index());
466 }
467
468 void
accept(ConstInstrVisitor & visitor) const469 MemRingOutInstr::accept(ConstInstrVisitor& visitor) const
470 {
471 visitor.visit(*this);
472 }
473
474 void
accept(InstrVisitor & visitor)475 MemRingOutInstr::accept(InstrVisitor& visitor)
476 {
477 visitor.visit(this);
478 }
479
480 static const std::map<string, MemRingOutInstr::EMemWriteType> type_lookop = {
481 {"WRITE", MemRingOutInstr::mem_write },
482 {"WRITE_IDX", MemRingOutInstr::mem_write_ind },
483 {"WRITE_ACK", MemRingOutInstr::mem_write_ack },
484 {"WRITE_IDX_ACK", MemRingOutInstr::mem_write_ind_ack}
485 };
486
487 auto
from_string(std::istream & is,ValueFactory & vf)488 MemRingOutInstr::from_string(std::istream& is, ValueFactory& vf) -> Pointer
489 {
490 string type_str;
491
492 int ring;
493
494 int base_address;
495 string value_str;
496
497 is >> ring >> type_str >> base_address >> value_str;
498 assert(ring < 4);
499
500 auto itype = type_lookop.find(type_str);
501 assert(itype != type_lookop.end());
502
503 auto type = itype->second;
504
505 PVirtualValue index{nullptr};
506 if (type == mem_write_ind || type == mem_write_ind_ack) {
507 char c;
508 string index_str;
509 is >> c >> index_str;
510 assert('@' == c);
511 index = vf.src_from_string(index_str);
512 }
513
514 string elm_size_str;
515 is >> elm_size_str;
516
517 int num_comp = int_from_string_with_prefix(elm_size_str, "ES:");
518
519 auto value = vf.src_vec4_from_string(value_str);
520
521 ECFOpCode opcodes[4] = {cf_mem_ring, cf_mem_ring1, cf_mem_ring2, cf_mem_ring3};
522 assert(ring < 4);
523
524 return new MemRingOutInstr(
525 opcodes[ring], type, value, base_address, num_comp, index->as_register());
526 }
527
EmitVertexInstr(int stream,bool cut)528 EmitVertexInstr::EmitVertexInstr(int stream, bool cut):
529 m_stream(stream),
530 m_cut(cut)
531 {
532 }
533
534 bool
is_equal_to(const EmitVertexInstr & oth) const535 EmitVertexInstr::is_equal_to(const EmitVertexInstr& oth) const
536 {
537 return oth.m_stream == m_stream && oth.m_cut == m_cut;
538 }
539
540 void
accept(ConstInstrVisitor & visitor) const541 EmitVertexInstr::accept(ConstInstrVisitor& visitor) const
542 {
543 visitor.visit(*this);
544 }
545
546 void
accept(InstrVisitor & visitor)547 EmitVertexInstr::accept(InstrVisitor& visitor)
548 {
549 visitor.visit(this);
550 }
551
552 bool
do_ready() const553 EmitVertexInstr::do_ready() const
554 {
555 return true;
556 }
557
558 void
do_print(std::ostream & os) const559 EmitVertexInstr::do_print(std::ostream& os) const
560 {
561 os << (m_cut ? "EMIT_CUT_VERTEX @" : "EMIT_VERTEX @") << m_stream;
562 }
563
564 auto
from_string(std::istream & is,bool cut)565 EmitVertexInstr::from_string(std::istream& is, bool cut) -> Pointer
566 {
567 char c;
568 is >> c;
569 assert(c == '@');
570
571 int stream;
572 is >> stream;
573
574 return new EmitVertexInstr(stream, cut);
575 }
576
577 void
accept(ConstInstrVisitor & visitor) const578 WriteTFInstr::accept(ConstInstrVisitor& visitor) const
579 {
580 visitor.visit(*this);
581 }
582
583 void
accept(InstrVisitor & visitor)584 WriteTFInstr::accept(InstrVisitor& visitor)
585 {
586 visitor.visit(this);
587 }
588
589 bool
is_equal_to(const WriteTFInstr & rhs) const590 WriteTFInstr::is_equal_to(const WriteTFInstr& rhs) const
591 {
592 return value() == rhs.value();
593 }
594
595 auto
from_string(std::istream & is,ValueFactory & vf)596 WriteTFInstr::from_string(std::istream& is, ValueFactory& vf) -> Pointer
597 {
598 string value_str;
599 is >> value_str;
600
601 auto value = vf.src_vec4_from_string(value_str);
602
603 return new WriteTFInstr(value);
604 }
605
606 uint8_t
allowed_src_chan_mask() const607 WriteTFInstr::allowed_src_chan_mask() const
608 {
609 return value().free_chan_mask();
610 }
611
612
613 bool
do_ready() const614 WriteTFInstr::do_ready() const
615 {
616 return value().ready(block_id(), index());
617 }
618
619 void
do_print(std::ostream & os) const620 WriteTFInstr::do_print(std::ostream& os) const
621 {
622 os << "WRITE_TF " << value();
623 }
624
625 } // namespace r600
626