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_instrfactory.h"
28
29 #include "sfn_alu_defines.h"
30 #include "sfn_debug.h"
31 #include "sfn_instr_alugroup.h"
32 #include "sfn_instr_controlflow.h"
33 #include "sfn_instr_export.h"
34 #include "sfn_instr_fetch.h"
35 #include "sfn_instr_lds.h"
36 #include "sfn_instr_mem.h"
37 #include "sfn_instr_tex.h"
38 #include "sfn_shader.h"
39
40 #include <sstream>
41 #include <string>
42 #include <vector>
43
44 namespace r600 {
45
46 using std::string;
47 using std::vector;
48
InstrFactory()49 InstrFactory::InstrFactory():
50 group(nullptr)
51 {
52 }
53
54 PInst
from_string(const std::string & s,int nesting_depth,bool is_cayman)55 InstrFactory::from_string(const std::string& s, int nesting_depth, bool is_cayman)
56 {
57 string type;
58 std::istringstream is(s);
59
60 PInst result = nullptr;
61
62 do {
63 is >> type;
64 } while (type.empty() && is.good());
65
66 if (type == "ALU_GROUP_BEGIN") {
67 group = new AluGroup();
68 group->set_nesting_depth(nesting_depth);
69 return nullptr;
70 } else if (type == "ALU_GROUP_END") {
71 AluGroup *retval = group;
72 group = nullptr;
73 return retval;
74 } else if (type == "ALU") {
75 result = AluInstr::from_string(is, m_value_factory, group, is_cayman);
76 } else if (type == "TEX") {
77 result = TexInstr::from_string(is, m_value_factory);
78 } else if (type == "EXPORT") {
79 result = ExportInstr::from_string(is, m_value_factory);
80 } else if (type == "EXPORT_DONE") {
81 result = ExportInstr::last_from_string(is, m_value_factory);
82 } else if (type == "VFETCH") {
83 result = FetchInstr::from_string(is, m_value_factory);
84 } else if (type == "GET_BUF_RESINFO") {
85 result = QueryBufferSizeInstr::from_string(is, m_value_factory);
86 } else if (type == "LOAD_BUF") {
87 result = LoadFromBuffer::from_string(is, m_value_factory);
88 } else if (type == "READ_SCRATCH") {
89 result = LoadFromScratch::from_string(is, m_value_factory);
90 } else if (type == "IF") {
91 result = IfInstr::from_string(is, m_value_factory, is_cayman);
92 } else if (type == "WRITE_SCRATCH") {
93 result = ScratchIOInstr::from_string(is, m_value_factory);
94 } else if (type == "MEM_RING") {
95 result = MemRingOutInstr::from_string(is, m_value_factory);
96 } else if (type == "EMIT_VERTEX") {
97 result = EmitVertexInstr::from_string(is, false);
98 } else if (type == "EMIT_CUT_VERTEX") {
99 result = EmitVertexInstr::from_string(is, true);
100 } else if (type == "LDS_READ") {
101 result = LDSReadInstr::from_string(is, m_value_factory);
102 } else if (type == "LDS") {
103 result = LDSAtomicInstr::from_string(is, m_value_factory);
104 } else if (type == "WRITE_TF") {
105 result = WriteTFInstr::from_string(is, m_value_factory);
106 } else
107 result = ControlFlowInstr::from_string(type);
108
109 if (!result && !group) {
110 std::cerr << "Error translating '" << s << "'\n";
111 }
112
113 return result;
114 }
115
116 bool
from_nir(nir_instr * instr,Shader & shader)117 InstrFactory::from_nir(nir_instr *instr, Shader& shader)
118 {
119 switch (instr->type) {
120 case nir_instr_type_alu:
121 return AluInstr::from_nir(nir_instr_as_alu(instr), shader);
122 case nir_instr_type_intrinsic:
123 return shader.process_intrinsic(nir_instr_as_intrinsic(instr));
124 case nir_instr_type_load_const:
125 return load_const(nir_instr_as_load_const(instr), shader);
126 case nir_instr_type_tex:
127 return TexInstr::from_nir(nir_instr_as_tex(instr), shader);
128 case nir_instr_type_jump:
129 return process_jump(nir_instr_as_jump(instr), shader);
130 case nir_instr_type_undef:
131 return process_undef(nir_instr_as_undef(instr), shader);
132 default:
133 fprintf(stderr, "Instruction type %d not supported\n", instr->type);
134 return false;
135 }
136 }
137
138 bool
load_const(nir_load_const_instr * literal,Shader & shader)139 InstrFactory::load_const(nir_load_const_instr *literal, Shader& shader)
140 {
141 AluInstr *ir = nullptr;
142
143 if (literal->def.bit_size == 64) {
144 for (int i = 0; i < literal->def.num_components; ++i) {
145 auto dest0 = m_value_factory.dest(literal->def, 2 * i, pin_none);
146 auto src0 = m_value_factory.literal(literal->value[i].u64 & 0xffffffff);
147 shader.emit_instruction(new AluInstr(op1_mov, dest0, src0, {alu_write}));
148
149 auto dest1 = m_value_factory.dest(literal->def, 2 * i + 1, pin_none);
150 auto src1 = m_value_factory.literal((literal->value[i].u64 >> 32) & 0xffffffff);
151 shader.emit_instruction(new AluInstr(op1_mov, dest1, src1, AluInstr::last_write));
152 }
153 } else {
154 Pin pin = literal->def.num_components == 1 ? pin_free : pin_none;
155 for (int i = 0; i < literal->def.num_components; ++i) {
156 auto dest = m_value_factory.dest(literal->def, i, pin);
157 uint32_t v = literal->value[i].i32;
158 PVirtualValue src = nullptr;
159 switch (v) {
160 case 0:
161 src = m_value_factory.zero();
162 break;
163 case 1:
164 src = m_value_factory.one_i();
165 break;
166 case 0xffffffff:
167 src = m_value_factory.inline_const(ALU_SRC_M_1_INT, 0);
168 break;
169 case 0x3f800000:
170 src = m_value_factory.inline_const(ALU_SRC_1, 0);
171 break;
172 case 0x3f000000:
173 src = m_value_factory.inline_const(ALU_SRC_0_5, 0);
174 break;
175 default:
176 src = m_value_factory.literal(v);
177 }
178
179 ir = new AluInstr(op1_mov, dest, src, {alu_write});
180 shader.emit_instruction(ir);
181 }
182 if (ir)
183 ir->set_alu_flag(alu_last_instr);
184 }
185 return true;
186 }
187
188 bool
process_jump(nir_jump_instr * instr,Shader & shader)189 InstrFactory::process_jump(nir_jump_instr *instr, Shader& shader)
190 {
191 ControlFlowInstr::CFType type;
192 switch (instr->type) {
193 case nir_jump_break:
194 type = ControlFlowInstr::cf_loop_break;
195 break;
196
197 case nir_jump_continue:
198 type = ControlFlowInstr::cf_loop_continue;
199 break;
200
201 default: {
202 nir_instr *i = reinterpret_cast<nir_instr *>(instr);
203 sfn_log << SfnLog::err << "Jump instrunction " << *i << " not supported\n";
204 return false;
205 }
206 }
207 shader.emit_instruction(new ControlFlowInstr(type));
208 shader.start_new_block(0);
209
210 return true;
211 }
212
213 bool
process_undef(nir_undef_instr * undef,Shader & shader)214 InstrFactory::process_undef(nir_undef_instr *undef, Shader& shader)
215 {
216 for (int i = 0; i < undef->def.num_components; ++i) {
217 auto dest = shader.value_factory().undef(undef->def.index, i);
218 shader.emit_instruction(
219 new AluInstr(op1_mov, dest, value_factory().zero(), AluInstr::last_write));
220 }
221 return true;
222 }
223
224 } // namespace r600
225