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