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_fetch.h"
8
9 #include "sfn_alu_defines.h"
10 #include "sfn_defines.h"
11 #include "sfn_valuefactory.h"
12
13 #include <sstream>
14
15 namespace r600 {
16
17 using std::istringstream;
18 using std::string;
19
FetchInstr(EVFetchInstr opcode,const RegisterVec4 & dst,const RegisterVec4::Swizzle & dest_swizzle,PRegister src,uint32_t src_offset,EVFetchType fetch_type,EVTXDataFormat data_format,EVFetchNumFormat num_format,EVFetchEndianSwap endian_swap,uint32_t resource_id,PRegister resource_offset)20 FetchInstr::FetchInstr(EVFetchInstr opcode,
21 const RegisterVec4& dst,
22 const RegisterVec4::Swizzle& dest_swizzle,
23 PRegister src,
24 uint32_t src_offset,
25 EVFetchType fetch_type,
26 EVTXDataFormat data_format,
27 EVFetchNumFormat num_format,
28 EVFetchEndianSwap endian_swap,
29 uint32_t resource_id,
30 PRegister resource_offset):
31 InstrWithVectorResult(dst, dest_swizzle, resource_id, resource_offset),
32 m_opcode(opcode),
33 m_src(src),
34 m_src_offset(src_offset),
35 m_fetch_type(fetch_type),
36 m_data_format(data_format),
37 m_num_format(num_format),
38 m_endian_swap(endian_swap),
39 m_mega_fetch_count(0),
40 m_array_base(0),
41 m_array_size(0),
42 m_elm_size(0)
43 {
44 switch (m_opcode) {
45 case vc_fetch:
46 m_opname = "VFETCH";
47 break;
48 case vc_semantic:
49 m_opname = "FETCH_SEMANTIC";
50 break;
51 case vc_get_buf_resinfo:
52 set_print_skip(mfc);
53 set_print_skip(fmt);
54 set_print_skip(ftype);
55 m_opname = "GET_BUF_RESINFO";
56 break;
57 case vc_read_scratch:
58 m_opname = "READ_SCRATCH";
59 break;
60 default:
61 unreachable("Unknown fetch instruction");
62 }
63
64 if (m_src)
65 m_src->add_use(this);
66 }
67
68 void
accept(ConstInstrVisitor & visitor) const69 FetchInstr::accept(ConstInstrVisitor& visitor) const
70 {
71 visitor.visit(*this);
72 }
73
74 void
accept(InstrVisitor & visitor)75 FetchInstr::accept(InstrVisitor& visitor)
76 {
77 visitor.visit(this);
78 }
79
80 bool
is_equal_to(const FetchInstr & rhs) const81 FetchInstr::is_equal_to(const FetchInstr& rhs) const
82 {
83 if (m_src) {
84 if (rhs.m_src) {
85 if (!m_src->equal_to(*rhs.m_src))
86 return false;
87 } else
88 return false;
89 } else if (rhs.m_src)
90 return false;
91
92 if (!comp_dest(rhs.dst(), rhs.all_dest_swizzle()))
93 return false;
94
95 if (m_tex_flags != rhs.m_tex_flags)
96 return false;
97
98 if (resource_offset() && rhs.resource_offset()) {
99 if (!resource_offset()->equal_to(*rhs.resource_offset()))
100 return false;
101 } else if (!(!!resource_offset() == !!rhs.resource_offset()))
102 return false;
103
104 return m_opcode == rhs.m_opcode && m_src_offset == rhs.m_src_offset &&
105 m_fetch_type == rhs.m_fetch_type && m_data_format == rhs.m_data_format &&
106 m_num_format == rhs.m_num_format && m_endian_swap == rhs.m_endian_swap &&
107 m_mega_fetch_count == rhs.m_mega_fetch_count &&
108 m_array_base == rhs.m_array_base && m_array_size == rhs.m_array_size &&
109 m_elm_size == rhs.m_elm_size && resource_id() == rhs.resource_id();
110 }
111
112 bool
propagate_death()113 FetchInstr::propagate_death()
114 {
115 auto reg = m_src->as_register();
116 if (reg)
117 reg->del_use(this);
118 return true;
119 }
120
121 bool
replace_source(PRegister old_src,PVirtualValue new_src)122 FetchInstr::replace_source(PRegister old_src, PVirtualValue new_src)
123 {
124 bool success = false;
125 auto new_reg = new_src->as_register();
126 if (new_reg) {
127 if (old_src->equal_to(*m_src)) {
128 m_src->del_use(this);
129 m_src = new_reg;
130 new_reg->add_use(this);
131 success = true;
132 }
133 success |= replace_resource_offset(old_src, new_reg);
134 }
135 return success;
136 }
137
138 bool
do_ready() const139 FetchInstr::do_ready() const
140 {
141 for (auto i : required_instr()) {
142 if (!i->is_scheduled())
143 return false;
144 }
145
146 bool result = m_src && m_src->ready(block_id(), index());
147 if (resource_offset())
148 result &= resource_offset()->ready(block_id(), index());
149 return result;
150 }
151
152 void
do_print(std::ostream & os) const153 FetchInstr::do_print(std::ostream& os) const
154 {
155 os << m_opname << ' ';
156
157 print_dest(os);
158
159 os << " :";
160
161 if (m_opcode != vc_get_buf_resinfo) {
162
163 if (m_src && m_src->chan() < 7) {
164 os << " " << *m_src;
165 if (m_src_offset)
166 os << " + " << m_src_offset << "b";
167 }
168 }
169
170 if (m_opcode != vc_read_scratch)
171 os << " RID:" << resource_id();
172
173 print_resource_offset(os);
174
175 if (!m_skip_print.test(ftype)) {
176 switch (m_fetch_type) {
177 case vertex_data:
178 os << " VERTEX";
179 break;
180 case instance_data:
181 os << " INSTANCE_DATA";
182 break;
183 case no_index_offset:
184 os << " NO_IDX_OFFSET";
185 break;
186 default:
187 unreachable("Unknown fetch instruction type");
188 }
189 }
190
191 if (!m_skip_print.test(fmt)) {
192 os << " FMT(";
193 auto fmt = s_data_format_map.find(m_data_format);
194 if (fmt != s_data_format_map.end())
195 os << fmt->second << ",";
196 else
197 unreachable("unknown data format");
198
199 if (m_tex_flags.test(format_comp_signed))
200 os << "S";
201 else
202 os << "U";
203
204 switch (m_num_format) {
205 case vtx_nf_norm:
206 os << "NORM";
207 break;
208 case vtx_nf_int:
209 os << "INT";
210 break;
211 case vtx_nf_scaled:
212 os << "SCALED";
213 break;
214 default:
215 unreachable("Unknown number format");
216 }
217
218 os << ")";
219 }
220
221 if (m_array_base) {
222 if (m_opcode != vc_read_scratch)
223 os << " BASE:" << m_array_base;
224 else
225 os << " L[0x" << std::uppercase << std::hex << m_array_base << std::dec << "]";
226 }
227
228 if (m_array_size)
229 os << " SIZE:" << m_array_size + 1;
230
231 if (m_tex_flags.test(is_mega_fetch) && !m_skip_print.test(mfc))
232 os << " MFC:" << m_mega_fetch_count;
233
234 if (m_elm_size)
235 os << " ES:" << m_elm_size;
236
237 if (m_tex_flags.test(fetch_whole_quad))
238 os << " WQ";
239 if (m_tex_flags.test(use_const_field))
240 os << " UCF";
241 if (m_tex_flags.test(srf_mode))
242 os << " SRF";
243 if (m_tex_flags.test(buf_no_stride))
244 os << " BNS";
245 if (m_tex_flags.test(alt_const))
246 os << " AC";
247 if (m_tex_flags.test(use_tc))
248 os << " TC";
249 if (m_tex_flags.test(vpm))
250 os << " VPM";
251 if (m_tex_flags.test(uncached) && m_opcode != vc_read_scratch)
252 os << " UNCACHED";
253 if (m_tex_flags.test(indexed) && m_opcode != vc_read_scratch)
254 os << " INDEXED";
255 }
256
257 Instr::Pointer
from_string(std::istream & is,ValueFactory & vf)258 FetchInstr::from_string(std::istream& is, ValueFactory& vf)
259 {
260 return from_string_impl(is, vc_fetch, vf);
261 }
262
263 Instr::Pointer
from_string_impl(std::istream & is,EVFetchInstr opcode,ValueFactory & vf)264 FetchInstr::from_string_impl(std::istream& is, EVFetchInstr opcode, ValueFactory& vf)
265 {
266 std::string deststr;
267 is >> deststr;
268
269 RegisterVec4::Swizzle dst_swz;
270 auto dest_reg = vf.dest_vec4_from_string(deststr, dst_swz, pin_group);
271
272 char help;
273 is >> help;
274 assert(help == ':');
275
276 string srcstr;
277 is >> srcstr;
278
279 std::cerr << "Get source " << srcstr << "\n";
280
281 auto src_reg = vf.src_from_string(srcstr)->as_register();
282 assert(src_reg);
283
284 string res_id_str;
285 string next;
286 is >> next;
287
288 int src_offset_val = 0;
289
290 if (next == "+") {
291 is >> src_offset_val;
292 is >> help;
293 assert(help == 'b');
294 is >> res_id_str;
295 } else {
296 res_id_str = next;
297 }
298
299 int res_id = int_from_string_with_prefix(res_id_str, "RID:");
300
301 string fetch_type_str;
302 is >> fetch_type_str;
303
304 EVFetchType fetch_type = vertex_data;
305 if (fetch_type_str == "VERTEX") {
306 fetch_type = vertex_data;
307 } else {
308 assert("Fetch type not yet implemented");
309 }
310
311 string format_str;
312 is >> format_str;
313
314 assert(!strncmp(format_str.c_str(), "FMT(", 4));
315 string data_format;
316 string num_format_str;
317
318 istringstream fmt_stream(format_str.substr(4));
319 bool is_num_fmr = false;
320 assert(!fmt_stream.eof());
321
322 do {
323 char c;
324 fmt_stream >> c;
325
326 if (c == ',') {
327 is_num_fmr = true;
328 continue;
329 }
330
331 if (!is_num_fmr)
332 data_format.append(1, c);
333 else
334 num_format_str.append(1, c);
335 } while (!fmt_stream.eof());
336
337 EVTXDataFormat fmt = fmt_invalid;
338
339 for (auto& [f, name] : s_data_format_map) {
340 if (data_format == name) {
341 fmt = f;
342 break;
343 }
344 }
345
346 assert(fmt != fmt_invalid);
347
348 bool fmt_signed = num_format_str[0] == 'S';
349 assert(fmt_signed || num_format_str[0] == 'U');
350
351 size_t num_format_end = num_format_str.find(')');
352 num_format_str = num_format_str.substr(1, num_format_end - 1);
353
354 EVFetchNumFormat num_fmt;
355 if (num_format_str == "NORM")
356 num_fmt = vtx_nf_norm;
357 else if (num_format_str == "INT")
358 num_fmt = vtx_nf_int;
359 else if (num_format_str == "SCALED")
360 num_fmt = vtx_nf_scaled;
361 else {
362 std::cerr << "Number format: '" << num_format_str << "' : ";
363 unreachable("Unknown number format");
364 }
365
366 auto fetch = new FetchInstr(opcode,
367 dest_reg,
368 dst_swz,
369 src_reg,
370 src_offset_val,
371 fetch_type,
372 fmt,
373 num_fmt,
374 vtx_es_none,
375 res_id,
376 nullptr);
377 if (fmt_signed)
378 fetch->set_fetch_flag(format_comp_signed);
379
380 while (!is.eof() && is.good()) {
381 std::string next_token;
382 is >> next_token;
383
384 if (next_token.empty())
385 break;
386
387 if (next_token.find(':') != string::npos) {
388 fetch->set_param_from_string(next_token);
389 } else {
390 fetch->set_flag_from_string(next_token);
391 }
392 }
393
394 return fetch;
395 }
396
397 void
set_param_from_string(const std::string & token)398 FetchInstr::set_param_from_string(const std::string& token)
399 {
400 if (token.substr(0, 4) == "MFC:")
401 set_mfc(int_from_string_with_prefix(token, "MFC:"));
402 else if (token.substr(0, 5) == "ARRB:")
403 set_array_base(int_from_string_with_prefix(token, "ARRB:"));
404 else if (token.substr(0, 5) == "ARRS:")
405 set_array_size(int_from_string_with_prefix(token, "ARRS:"));
406 else if (token.substr(0, 3) == "ES:")
407 set_element_size(int_from_string_with_prefix(token, "ES:"));
408 else {
409 std::cerr << "Token '" << token << "': ";
410 unreachable("Unknown token in fetch param list");
411 }
412 }
413
414 void
set_flag_from_string(const std::string & token)415 FetchInstr::set_flag_from_string(const std::string& token)
416 {
417 auto flag = s_flag_map.find(token.c_str());
418 if (flag != s_flag_map.end())
419 set_fetch_flag(flag->second);
420 else {
421 std::cerr << "Token: " << token << " : ";
422 unreachable("Unknown token in fetch flag list");
423 }
424 }
425
426 const std::map<const char *, FetchInstr::EFlags> FetchInstr::s_flag_map = {
427 {"WQ", fetch_whole_quad},
428 {"UCF", use_const_field },
429 {"SRF", srf_mode },
430 {"BNS", buf_no_stride },
431 {"AC", alt_const },
432 {"TC", use_tc },
433 {"VPM", vpm },
434 {"UNCACHED", uncached },
435 {"INDEXED", indexed }
436 };
437
438 const std::map<EVTXDataFormat, const char *> FetchInstr::s_data_format_map = {
439 {fmt_invalid, "INVALID" },
440 {fmt_8, "8" },
441 {fmt_4_4, "4_4" },
442 {fmt_3_3_2, "3_3_2" },
443 {fmt_reserved_4, "RESERVED_4" },
444 {fmt_16, "16" },
445 {fmt_16_float, "16F" },
446 {fmt_8_8, "8_8" },
447 {fmt_5_6_5, "5_6_5" },
448 {fmt_6_5_5, "6_5_5" },
449 {fmt_1_5_5_5, "1_5_5_5" },
450 {fmt_4_4_4_4, "4_4_4_4" },
451 {fmt_5_5_5_1, "5_5_5_1" },
452 {fmt_32, "32" },
453 {fmt_32_float, "32F" },
454 {fmt_16_16, "16_16" },
455 {fmt_16_16_float, "16_16F" },
456 {fmt_8_24, "8_24" },
457 {fmt_8_24_float, "8_24F" },
458 {fmt_24_8, "24_8" },
459 {fmt_24_8_float, "24_8F" },
460 {fmt_10_11_11, "10_11_11" },
461 {fmt_10_11_11_float, "10_11_11F" },
462 {fmt_11_11_10, "11_11_10" },
463 {fmt_10_11_11_float, "11_11_10F" },
464 {fmt_2_10_10_10, "2_10_10_10" },
465 {fmt_8_8_8_8, "8_8_8_8" },
466 {fmt_10_10_10_2, "10_10_10_2" },
467 {fmt_x24_8_32_float, "X24_8_32F" },
468 {fmt_32_32, "32_32" },
469 {fmt_32_32_float, "32_32F" },
470 {fmt_16_16_16_16, "16_16_16_16" },
471 {fmt_16_16_16_16_float, "16_16_16_16F" },
472 {fmt_reserved_33, "RESERVED_33" },
473 {fmt_32_32_32_32, "32_32_32_32" },
474 {fmt_32_32_32_32_float, "32_32_32_32F" },
475 {fmt_reserved_36, "RESERVED_36" },
476 {fmt_1, "1" },
477 {fmt_1_reversed, "1_REVERSED" },
478 {fmt_gb_gr, "GB_GR" },
479 {fmt_bg_rg, "BG_RG" },
480 {fmt_32_as_8, "32_AS_8" },
481 {fmt_32_as_8_8, "32_AS_8_8" },
482 {fmt_5_9_9_9_sharedexp, "5_9_9_9_SHAREDEXP"},
483 {fmt_8_8_8, "8_8_8" },
484 {fmt_16_16_16, "16_16_16" },
485 {fmt_16_16_16_float, "16_16_16F" },
486 {fmt_32_32_32, "32_32_32" },
487 {fmt_32_32_32_float, "32_32_32F" },
488 {fmt_bc1, "BC1" },
489 {fmt_bc2, "BC2" },
490 {fmt_bc3, "BC3" },
491 {fmt_bc4, "BC4" },
492 {fmt_bc5, "BC5" },
493 {fmt_apc0, "APC0" },
494 {fmt_apc1, "APC1" },
495 {fmt_apc2, "APC2" },
496 {fmt_apc3, "APC3" },
497 {fmt_apc4, "APC4" },
498 {fmt_apc5, "APC5" },
499 {fmt_apc6, "APC6" },
500 {fmt_apc7, "APC7" },
501 {fmt_ctx1, "CTX1" },
502 {fmt_reserved_63, "RESERVED_63" }
503 };
504
QueryBufferSizeInstr(const RegisterVec4 & dst,const RegisterVec4::Swizzle & dst_swz,uint32_t resid)505 QueryBufferSizeInstr::QueryBufferSizeInstr(const RegisterVec4& dst,
506 const RegisterVec4::Swizzle& dst_swz,
507 uint32_t resid):
508 FetchInstr(vc_get_buf_resinfo,
509 dst,
510 dst_swz,
511 new Register(0, 7, pin_fully),
512 0,
513 no_index_offset,
514 fmt_32_32_32_32,
515 vtx_nf_norm,
516 vtx_es_none,
517 resid,
518 nullptr)
519 {
520 set_fetch_flag(format_comp_signed);
521 set_print_skip(mfc);
522 set_print_skip(fmt);
523 set_print_skip(ftype);
524 }
525
526 Instr::Pointer
from_string(std::istream & is,ValueFactory & vf)527 QueryBufferSizeInstr::from_string(std::istream& is, ValueFactory& vf)
528 {
529 std::string deststr, res_id_str;
530 is >> deststr;
531
532 char help;
533 is >> help;
534 assert(help == ':');
535
536 is >> res_id_str;
537
538 RegisterVec4::Swizzle dst_swz;
539 auto dst = vf.dest_vec4_from_string(deststr, dst_swz, pin_group);
540 int res_id = int_from_string_with_prefix(res_id_str, "RID:");
541
542 return new QueryBufferSizeInstr(dst, dst_swz, res_id);
543 }
544
LoadFromBuffer(const RegisterVec4 & dst,const RegisterVec4::Swizzle & dst_swizzle,PRegister addr,uint32_t addr_offset,uint32_t resid,PRegister res_offset,EVTXDataFormat data_format)545 LoadFromBuffer::LoadFromBuffer(const RegisterVec4& dst,
546 const RegisterVec4::Swizzle& dst_swizzle,
547 PRegister addr,
548 uint32_t addr_offset,
549 uint32_t resid,
550 PRegister res_offset,
551 EVTXDataFormat data_format):
552 FetchInstr(vc_fetch,
553 dst,
554 dst_swizzle,
555 addr,
556 addr_offset,
557 no_index_offset,
558 data_format,
559 vtx_nf_scaled,
560 vtx_es_none,
561 resid,
562 res_offset)
563 {
564 set_fetch_flag(format_comp_signed);
565 set_mfc(16);
566 override_opname("LOAD_BUF");
567 set_print_skip(mfc);
568 set_print_skip(fmt);
569 set_print_skip(ftype);
570 }
571
572 Instr::Pointer
from_string(std::istream & is,ValueFactory & vf)573 LoadFromBuffer::from_string(std::istream& is, ValueFactory& vf)
574 {
575 std::string deststr;
576 is >> deststr;
577
578 RegisterVec4::Swizzle dst_swz;
579 auto dst = vf.dest_vec4_from_string(deststr, dst_swz, pin_group);
580
581 char help;
582 is >> help;
583 assert(help == ':');
584
585 string addrstr;
586 is >> addrstr;
587 auto addr_reg = vf.src_from_string(addrstr)->as_register();
588
589 string res_id_str;
590 string next;
591 is >> next;
592
593 int addr_offset_val = 0;
594
595 if (next == "+") {
596 is >> addr_offset_val;
597 is >> help;
598 assert(help == 'b');
599 is >> res_id_str;
600 } else {
601 res_id_str = next;
602 }
603
604 int res_id = int_from_string_with_prefix(res_id_str, "RID:");
605
606 next.clear();
607 is >> next;
608 PRegister res_offset = nullptr;
609 if (next == "+") {
610 string res_offset_str;
611 is >> res_offset_str;
612 res_offset = vf.src_from_string(res_offset_str)->as_register();
613 }
614
615 auto fetch = new LoadFromBuffer(
616 dst, dst_swz, addr_reg, addr_offset_val, res_id, res_offset, fmt_32_32_32_32_float);
617 is >> next;
618 if (next == "SRF")
619 fetch->set_fetch_flag(srf_mode);
620
621 return fetch;
622 }
623
624 class AddrResolver : public RegisterVisitor {
625 public:
AddrResolver(LoadFromScratch * lfs)626 AddrResolver(LoadFromScratch *lfs):
627 m_lfs(lfs)
628 {
629 }
630
visit(Register & value)631 void visit(Register& value)
632 {
633 m_lfs->set_fetch_flag(FetchInstr::indexed);
634 m_lfs->set_src(&value);
635 value.add_use(m_lfs);
636 }
visit(LocalArray & value)637 void visit(LocalArray& value)
638 {
639 unreachable("An array can't be a direct source for scratch reads");
640 (void)value;
641 }
visit(LocalArrayValue & value)642 void visit(LocalArrayValue& value)
643 {
644 unreachable("An array value can't be a direct source for scratch reads");
645 // TODO: an array element with constant offset could be used here
646 (void)value;
647 }
visit(UniformValue & value)648 void visit(UniformValue& value)
649 {
650 unreachable("A uniform can't be a direct source for scratch reads");
651 (void)value;
652 }
visit(LiteralConstant & value)653 void visit(LiteralConstant& value)
654 {
655 m_lfs->set_array_base(value.value());
656 m_lfs->set_src(new Register(0, 7, pin_none));
657 }
visit(InlineConstant & value)658 void visit(InlineConstant& value)
659 {
660 if (value.sel() == ALU_SRC_1_INT)
661 m_lfs->set_array_base(1);
662 else if (value.sel() != ALU_SRC_0)
663 unreachable("Scratch array base is an impossible inline constant");
664
665 m_lfs->set_src(new Register(0, 7, pin_none));
666 }
667
668 LoadFromScratch *m_lfs;
669 };
670
LoadFromScratch(const RegisterVec4 & dst,const RegisterVec4::Swizzle & dst_swz,PVirtualValue addr,uint32_t scratch_size)671 LoadFromScratch::LoadFromScratch(const RegisterVec4& dst,
672 const RegisterVec4::Swizzle& dst_swz,
673 PVirtualValue addr,
674 uint32_t scratch_size):
675 FetchInstr(vc_read_scratch,
676 dst,
677 dst_swz,
678 nullptr,
679 0,
680 no_index_offset,
681 fmt_32_32_32_32,
682 vtx_nf_int,
683 vtx_es_none,
684 0,
685 nullptr)
686 {
687 set_fetch_flag(uncached);
688 set_fetch_flag(wait_ack);
689
690 assert(scratch_size >= 1);
691 set_array_size(scratch_size - 1);
692 set_array_base(0);
693 AddrResolver ar(this);
694 addr->accept(ar);
695
696 set_print_skip(mfc);
697 set_print_skip(fmt);
698 set_print_skip(ftype);
699 set_element_size(3);
700 }
701
702 Instr::Pointer
from_string(std::istream & is,ValueFactory & vf)703 LoadFromScratch::from_string(std::istream& is, ValueFactory& vf)
704 {
705 std::string deststr;
706 is >> deststr;
707
708 RegisterVec4::Swizzle dst_swz;
709 auto dest = vf.dest_vec4_from_string(deststr, dst_swz, pin_group);
710
711 char help;
712 is >> help;
713 assert(help == ':');
714
715 string addrstr;
716 is >> addrstr;
717 auto addr_reg = vf.src_from_string(addrstr);
718
719 string offsetstr;
720 is >> offsetstr;
721 int size = int_from_string_with_prefix(offsetstr, "SIZE:");
722 assert(size >= 1);
723
724 return new LoadFromScratch(dest, dst_swz, addr_reg, size);
725 }
726
727 } // namespace r600
728