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