xref: /aosp_15_r20/external/mesa3d/src/gallium/drivers/r600/sfn/sfn_instr_export.cpp (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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