• 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_fetch.h"
28 #include "sfn_valuefactory.h"
29 #include "sfn_defines.h"
30 
31 #include <sstream>
32 
33 namespace r600 {
34 
35 using std::string;
36 using std::istringstream;
37 
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)38 FetchInstr::FetchInstr(EVFetchInstr opcode,
39                        const RegisterVec4& dst,
40                        const RegisterVec4::Swizzle& dest_swizzle,
41                        PRegister src,
42                        uint32_t src_offset,
43                        EVFetchType fetch_type,
44                        EVTXDataFormat data_format,
45                        EVFetchNumFormat num_format,
46                        EVFetchEndianSwap endian_swap,
47                        uint32_t resource_id,
48                        PRegister resource_offset):
49    InstrWithVectorResult(dst, dest_swizzle),
50    m_opcode(opcode),
51    m_src(src),
52    m_src_offset(src_offset),
53    m_fetch_type(fetch_type),
54    m_data_format(data_format),
55    m_num_format(num_format),
56    m_endian_swap(endian_swap),
57    m_resource_id(resource_id),
58    m_resource_offset(resource_offset),
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("Unknwon fetch instruction");
82    }
83 
84    if (m_src)
85       m_src->add_use(this);
86 
87    if (m_resource_offset && m_resource_offset->as_register())
88       m_resource_offset->as_register()->add_use(this);
89 }
90 
accept(ConstInstrVisitor & visitor) const91 void FetchInstr::accept(ConstInstrVisitor& visitor) const
92 {
93    visitor.visit(*this);
94 }
95 
accept(InstrVisitor & visitor)96 void FetchInstr::accept(InstrVisitor& visitor)
97 {
98    visitor.visit(this);
99 }
100 
is_equal_to(const FetchInstr & rhs) const101 bool 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 (m_resource_offset && rhs.m_resource_offset) {
119       if (!m_resource_offset->equal_to(*rhs.m_resource_offset))
120          return false;
121    } else if (!(!!m_resource_offset == !!rhs.m_resource_offset))
122       return false;
123 
124    return m_opcode == rhs.m_opcode &&
125          m_src_offset == rhs.m_src_offset &&
126          m_fetch_type == rhs.m_fetch_type &&
127          m_data_format == rhs.m_data_format &&
128          m_num_format == rhs.m_num_format &&
129          m_endian_swap == rhs.m_endian_swap &&
130          m_resource_id == rhs.m_resource_id &&
131          m_mega_fetch_count == rhs.m_mega_fetch_count &&
132          m_array_base == rhs.m_array_base &&
133          m_array_size == rhs.m_array_size &&
134          m_elm_size == rhs.m_elm_size;
135 }
136 
propagate_death()137 bool FetchInstr::propagate_death()
138 {
139    auto reg = m_src->as_register();
140    if (reg)
141       reg->del_use(this);
142    return true;
143 }
144 
replace_source(PRegister old_src,PVirtualValue new_src)145 bool FetchInstr::replace_source(PRegister old_src, PVirtualValue new_src)
146 {
147    bool success = false;
148    auto new_reg = new_src->as_register();
149    if (new_reg) {
150       if (old_src->equal_to(*m_src)) {
151          m_src->del_use(this);
152          m_src = new_reg;
153          new_reg->add_use(this);
154          success = true;
155       }
156       if (m_resource_offset && old_src->equal_to(*m_resource_offset)) {
157          m_resource_offset->del_use(this);
158          m_resource_offset = new_reg;
159          new_reg->add_use(this);
160          success = true;
161       }
162    }
163    return success;
164 }
165 
do_ready() const166 bool FetchInstr::do_ready() const
167 {
168    for (auto i: required_instr()) {
169       if (!i->is_scheduled())
170          return false;
171    }
172 
173    bool result = m_src && m_src->ready(block_id(), index());
174    if (m_resource_offset) {
175       auto r = m_resource_offset->as_register();
176       if (r)
177          result &= r->ready(block_id(), index());
178    }
179    return result;
180 }
181 
do_print(std::ostream & os) const182 void FetchInstr::do_print(std::ostream& os) const
183 {
184    os << m_opname << ' ';
185 
186    print_dest(os);
187 
188    os << " :";
189 
190    if (m_opcode != vc_get_buf_resinfo) {
191 
192       if (m_src && m_src->chan() < 7) {
193          os << " " << *m_src;
194          if (m_src_offset)
195             os << " + " << m_src_offset << "b";
196       }
197    }
198 
199    if (m_opcode != vc_read_scratch)
200       os << " RID:" << m_resource_id;
201 
202    if (m_resource_offset) {
203       os << " + ";
204       m_resource_offset->print(os);
205    }
206 
207    if (!m_skip_print.test(ftype)) {
208       switch (m_fetch_type) {
209       case vertex_data : os << " VERTEX"; break;
210       case instance_data : os << " INSTANCE_DATA"; break;
211       case no_index_offset : os << " NO_IDX_OFFSET"; break;
212       default:
213          unreachable("Unknwon fetch instruction type");
214       }
215    }
216 
217    if (!m_skip_print.test(fmt)) {
218       os << " FMT(";
219       auto fmt = s_data_format_map.find(m_data_format);
220       if (fmt != s_data_format_map.end())
221          os << fmt->second << ",";
222       else
223          unreachable("unknwon data format");
224 
225       if (m_tex_flags.test(format_comp_signed))
226          os << "S";
227       else
228          os << "U";
229 
230       switch (m_num_format) {
231       case vtx_nf_norm : os << "NORM"; break;
232       case vtx_nf_int : os << "INT"; break;
233       case vtx_nf_scaled: os << "SCALED"; break;
234       default:
235          unreachable("Unknwon 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)) os << " WQ";
258    if (m_tex_flags.test(use_const_field)) os << " UCF";
259    if (m_tex_flags.test(srf_mode)) os << " SRF";
260    if (m_tex_flags.test(buf_no_stride)) os << " BNS";
261    if (m_tex_flags.test(alt_const)) os << " AC";
262    if (m_tex_flags.test(use_tc)) os << " TC";
263    if (m_tex_flags.test(vpm)) os << " VPM";
264    if (m_tex_flags.test(uncached) && m_opcode != vc_read_scratch) os << " UNCACHED";
265    if (m_tex_flags.test(indexed) && m_opcode != vc_read_scratch) os << " INDEXED";
266 }
267 
from_string(std::istream & is,ValueFactory & vf)268 Instr::Pointer FetchInstr::from_string(std::istream& is, ValueFactory& vf)
269 {
270    return from_string_impl(is, vc_fetch, vf);
271 }
272 
from_string_impl(std::istream & is,EVFetchInstr opcode,ValueFactory & vf)273 Instr::Pointer FetchInstr::from_string_impl(std::istream& is, EVFetchInstr opcode, ValueFactory& vf)
274 {
275    std::string deststr;
276    is >> deststr;
277 
278    RegisterVec4::Swizzle dst_swz;
279    auto dest_reg = vf.dest_vec4_from_string(deststr, dst_swz, pin_group);
280 
281    char help;
282    is >> help;
283    assert(help == ':');
284 
285    string srcstr;
286    is >> srcstr;
287 
288    std::cerr << "Get source "  << srcstr << "\n";
289 
290    auto src_reg = vf.src_from_string(srcstr)->as_register();
291    assert(src_reg);
292 
293    string res_id_str;
294    string next;
295    is >> next;
296 
297    int src_offset_val = 0;
298 
299    if (next == "+") {
300       is >> src_offset_val;
301       is >> help;
302       assert(help == 'b');
303       is >> res_id_str;
304    } else {
305       res_id_str = next;
306    }
307 
308    int res_id = int_from_string_with_prefix(res_id_str, "RID:");
309 
310    string fetch_type_str;
311    is >> fetch_type_str;
312 
313    EVFetchType fetch_type = vertex_data;
314    if (fetch_type_str == "VERTEX") {
315       fetch_type = vertex_data;
316    } else {
317       assert("Fetch type not yet implemented");
318    }
319 
320    string format_str;
321    is >> format_str;
322 
323    assert(!strncmp(format_str.c_str(), "FMT(", 4));
324    string data_format;
325    string num_format_str;
326 
327    istringstream fmt_stream(format_str.substr(4));
328    bool is_num_fmr = false;
329    assert(!fmt_stream.eof());
330 
331    do {
332       char c;
333       fmt_stream >> c;
334 
335       if (c == ',')  {
336          is_num_fmr = true;
337          continue;
338       }
339 
340       if (!is_num_fmr)
341          data_format.append(1, c);
342       else
343          num_format_str.append(1, c);
344    } while (!fmt_stream.eof());
345 
346    EVTXDataFormat fmt = fmt_invalid;
347 
348    for (auto& [f, name] :  s_data_format_map) {
349       if (data_format == name) {
350          fmt = f;
351          break;
352       }
353    }
354 
355    assert(fmt != fmt_invalid);
356 
357    bool fmt_signed = num_format_str[0] == 'S';
358    assert(fmt_signed || num_format_str[0] == 'U');
359 
360    size_t num_format_end = num_format_str.find(')');
361    num_format_str = num_format_str.substr(1, num_format_end - 1) ;
362 
363    EVFetchNumFormat num_fmt;
364    if (num_format_str == "NORM")
365       num_fmt = vtx_nf_norm;
366    else if (num_format_str == "INT")
367       num_fmt = vtx_nf_int;
368    else if (num_format_str == "SCALED")
369       num_fmt = vtx_nf_scaled;
370    else {
371       std::cerr << "Number format: '" << num_format_str << "' : ";
372       unreachable("Unknown number format");
373    }
374 
375    auto fetch = new FetchInstr(opcode, dest_reg, dst_swz,
376                                src_reg, src_offset_val, fetch_type, fmt, num_fmt,
377                                vtx_es_none, res_id, nullptr);
378    if (fmt_signed)
379       fetch->set_fetch_flag(format_comp_signed);
380 
381    while (!is.eof() && is.good()) {
382       std::string next_token;
383       is >> next_token;
384 
385       if (next_token.empty())
386          break;
387 
388       if (next_token.find(':') != string::npos) {
389          fetch->set_param_from_string(next_token);
390       } else {
391          fetch->set_flag_from_string(next_token);
392       }
393    }
394 
395    return fetch;
396 }
397 
set_param_from_string(const std::string & token)398 void 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 
set_flag_from_string(const std::string & token)414 void FetchInstr::set_flag_from_string(const std::string& token)
415 {
416    auto flag = s_flag_map.find(token.c_str());
417    if (flag != s_flag_map.end())
418       set_fetch_flag(flag->second);
419    else {
420       std::cerr << "Token: " << token << " : ";
421       unreachable("Unknown token in fetch flag list");
422    }
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 
505 
QueryBufferSizeInstr(const RegisterVec4 & dst,const RegisterVec4::Swizzle & dst_swz,uint32_t resid)506 QueryBufferSizeInstr::QueryBufferSizeInstr(const RegisterVec4& dst,
507                                            const RegisterVec4::Swizzle& dst_swz,
508                                            uint32_t resid):
509    FetchInstr(vc_get_buf_resinfo,
510               dst, 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 
from_string(std::istream & is,ValueFactory & vf)526 Instr::Pointer QueryBufferSizeInstr::from_string(std::istream& is, ValueFactory& vf)
527 {
528    std::string deststr, res_id_str;
529    is >> deststr;
530 
531    char help;
532    is >> help;
533    assert(help == ':');
534 
535    is >> res_id_str;
536 
537    RegisterVec4::Swizzle dst_swz;
538    auto dst = vf.dest_vec4_from_string(deststr, dst_swz, pin_group);
539    int res_id = int_from_string_with_prefix(res_id_str, "RID:");
540 
541    return new QueryBufferSizeInstr( dst, dst_swz, res_id);
542 }
543 
LoadFromBuffer(const RegisterVec4 & dst,const RegisterVec4::Swizzle & dst_swizzle,PRegister addr,uint32_t addr_offset,uint32_t resid,PRegister res_offset,EVTXDataFormat data_format)544 LoadFromBuffer::LoadFromBuffer(const RegisterVec4& dst, const RegisterVec4::Swizzle& dst_swizzle,
545                                PRegister addr, uint32_t addr_offset,
546                                uint32_t resid, PRegister res_offset, EVTXDataFormat data_format):
547    FetchInstr(vc_fetch, dst,  dst_swizzle, addr, addr_offset, no_index_offset,
548               data_format, vtx_nf_scaled, vtx_es_none, resid, res_offset)
549 {
550    set_fetch_flag(format_comp_signed);
551    set_mfc(16);
552    override_opname("LOAD_BUF");
553    set_print_skip(mfc);
554    set_print_skip(fmt);
555    set_print_skip(ftype);
556 }
557 
from_string(std::istream & is,ValueFactory & vf)558 Instr::Pointer LoadFromBuffer::from_string(std::istream& is, ValueFactory& vf)
559 {
560    std::string deststr;
561    is >> deststr;
562 
563    RegisterVec4::Swizzle dst_swz;
564    auto dst = vf.dest_vec4_from_string(deststr, dst_swz, pin_group);
565 
566    char help;
567    is >> help;
568    assert(help == ':');
569 
570    string addrstr;
571    is >> addrstr;
572    auto addr_reg = vf.src_from_string(addrstr)->as_register();
573 
574    string res_id_str;
575    string next;
576    is >> next;
577 
578    int addr_offset_val = 0;
579 
580    if (next == "+") {
581       is >> addr_offset_val;
582       is >> help;
583       assert(help == 'b');
584       is >> res_id_str;
585    } else {
586       res_id_str = next;
587    }
588 
589    int res_id = int_from_string_with_prefix(res_id_str, "RID:");
590 
591    next.clear();
592    is >> next;
593    PRegister res_offset = nullptr;
594    if (next == "+") {
595       string res_offset_str;
596       is >> res_offset_str;
597       res_offset = vf.src_from_string(res_offset_str)->as_register();
598    }
599 
600    auto fetch = new LoadFromBuffer( dst, dst_swz,
601                                     addr_reg, addr_offset_val,
602                                     res_id, res_offset, fmt_32_32_32_32_float);
603    is >> next;
604    if (next == "SRF")
605       fetch->set_fetch_flag(srf_mode);
606 
607    return fetch;
608 }
609 
610 class AddrResolver: public RegisterVisitor {
611 public:
AddrResolver(LoadFromScratch * lfs)612    AddrResolver(LoadFromScratch *lfs) : m_lfs(lfs) {}
613 
visit(Register & value)614    void visit(Register& value) {
615       m_lfs->set_fetch_flag(FetchInstr::indexed);
616       m_lfs->set_src(&value);
617       value.add_use(m_lfs);
618    }
visit(LocalArray & value)619    void visit(LocalArray& value) {assert(0);(void)value;}
visit(LocalArrayValue & value)620    void visit(LocalArrayValue& value) {assert(0);(void)value;}
visit(UniformValue & value)621    void visit(UniformValue& value) {assert(0);(void)value;}
visit(LiteralConstant & value)622    void visit(LiteralConstant& value) {
623       m_lfs->set_array_base(value.value());
624       m_lfs->set_src(new Register( 0, 7, pin_none));
625    }
visit(InlineConstant & value)626    void visit(InlineConstant& value) {assert(0);(void)value;}
627 
628    LoadFromScratch *m_lfs;
629 };
630 
631 
632 
LoadFromScratch(const RegisterVec4 & dst,const RegisterVec4::Swizzle & dst_swz,PVirtualValue addr,uint32_t scratch_size)633 LoadFromScratch::LoadFromScratch(const RegisterVec4& dst, const RegisterVec4::Swizzle& dst_swz, PVirtualValue addr, uint32_t scratch_size):
634    FetchInstr(vc_read_scratch,
635               dst, dst_swz,
636               nullptr,
637               0,
638               no_index_offset,
639               fmt_32_32_32_32,
640               vtx_nf_int,
641               vtx_es_none,
642               0,
643               nullptr)
644 {
645    set_fetch_flag(uncached);
646    set_fetch_flag(wait_ack);
647 
648    assert(scratch_size >= 1);
649    set_array_size(scratch_size - 1);
650    set_array_base(0);
651    AddrResolver ar(this);
652    addr->accept(ar);
653 
654    set_print_skip(mfc);
655    set_print_skip(fmt);
656    set_print_skip(ftype);
657    set_element_size(3);
658 }
659 
from_string(std::istream & is,ValueFactory & vf)660 Instr::Pointer LoadFromScratch::from_string(std::istream& is, ValueFactory &vf)
661 {
662    std::string deststr;
663    is >> deststr;
664 
665    RegisterVec4::Swizzle dst_swz;
666    auto dest = vf.dest_vec4_from_string(deststr, dst_swz, pin_group);
667 
668    char help;
669    is >> help;
670    assert(help == ':');
671 
672    string addrstr;
673    is >> addrstr;
674    auto addr_reg = vf.src_from_string(addrstr);
675 
676    string offsetstr;
677    is >> offsetstr;
678    int size = int_from_string_with_prefix(offsetstr, "SIZE:");
679    assert(size >= 1);
680 
681    return new LoadFromScratch( dest, dst_swz, addr_reg, size);
682 }
683 
684 }
685 
686