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