blob: 2f05ded2b407f77d0f43b0c2689f8ae633081287 [file] [log] [blame]
Chris Forbesaf4ed532018-12-06 18:33:27 -08001// Copyright 2018 The SwiftShader Authors. All Rights Reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include <spirv/unified1/spirv.hpp>
Chris Forbes9667a5b2019-03-07 09:26:48 -080016#include <spirv/unified1/GLSL.std.450.h>
Chris Forbesaf4ed532018-12-06 18:33:27 -080017#include "SpirvShader.hpp"
18#include "System/Math.hpp"
Ben Claytonefec1b92019-03-05 17:38:16 +000019#include "Vulkan/VkBuffer.hpp"
Chris Forbesebe5f7f2019-01-16 10:38:34 -080020#include "Vulkan/VkDebug.hpp"
Ben Clayton76e9bc02019-02-26 15:02:18 +000021#include "Vulkan/VkPipelineLayout.hpp"
Chris Forbesaf4ed532018-12-06 18:33:27 -080022#include "Device/Config.hpp"
23
24namespace sw
25{
26 volatile int SpirvShader::serialCounter = 1; // Start at 1, 0 is invalid shader.
27
Chris Forbes5839dcf2018-12-10 19:02:58 -080028 SpirvShader::SpirvShader(InsnStore const &insns)
29 : insns{insns}, inputs{MAX_INTERFACE_COMPONENTS},
30 outputs{MAX_INTERFACE_COMPONENTS},
31 serialID{serialCounter++}, modes{}
Chris Forbesaf4ed532018-12-06 18:33:27 -080032 {
Ben Clayton45faa082019-03-05 13:20:40 +000033 ASSERT(insns.size() > 0);
34
Chris Forbesaf4ed532018-12-06 18:33:27 -080035 // Simplifying assumptions (to be satisfied by earlier transformations)
Chris Forbesbde34082018-12-28 12:03:10 -080036 // - There is exactly one entrypoint in the module, and it's the one we want
Chris Forbesaf4ed532018-12-06 18:33:27 -080037 // - The only input/output OpVariables present are those used by the entrypoint
38
Chris Forbese57f10e2019-03-04 10:53:07 -080039 // TODO: Add real support for control flow. For now, track whether we've seen
40 // a label or a return already (if so, the shader does things we will mishandle).
41 // We expect there to be one of each in a simple shader -- the first and last instruction
42 // of the entrypoint function.
43 bool seenLabel = false;
44 bool seenReturn = false;
45
Chris Forbes4a979dc2019-01-17 09:36:46 -080046 for (auto insn : *this)
47 {
48 switch (insn.opcode())
49 {
50 case spv::OpExecutionMode:
51 ProcessExecutionMode(insn);
52 break;
Chris Forbesaf4ed532018-12-06 18:33:27 -080053
Chris Forbesc25b8072018-12-10 15:10:39 -080054 case spv::OpDecorate:
55 {
Ben Claytonab51bbf2019-02-20 14:36:27 +000056 TypeOrObjectID targetId = insn.word(1);
Chris Forbes93f70b32019-02-10 21:26:27 +000057 auto decoration = static_cast<spv::Decoration>(insn.word(2));
Chris Forbesc25b8072018-12-10 15:10:39 -080058 decorations[targetId].Apply(
Chris Forbes93f70b32019-02-10 21:26:27 +000059 decoration,
Chris Forbesc25b8072018-12-10 15:10:39 -080060 insn.wordCount() > 3 ? insn.word(3) : 0);
Chris Forbes93f70b32019-02-10 21:26:27 +000061
62 if (decoration == spv::DecorationCentroid)
63 modes.NeedsCentroid = true;
Chris Forbesc25b8072018-12-10 15:10:39 -080064 break;
65 }
66
67 case spv::OpMemberDecorate:
68 {
Ben Claytonab51bbf2019-02-20 14:36:27 +000069 TypeID targetId = insn.word(1);
Chris Forbesc25b8072018-12-10 15:10:39 -080070 auto memberIndex = insn.word(2);
71 auto &d = memberDecorations[targetId];
72 if (memberIndex >= d.size())
73 d.resize(memberIndex + 1); // on demand; exact size would require another pass...
Chris Forbes93f70b32019-02-10 21:26:27 +000074 auto decoration = static_cast<spv::Decoration>(insn.word(3));
Chris Forbesc25b8072018-12-10 15:10:39 -080075 d[memberIndex].Apply(
Chris Forbes93f70b32019-02-10 21:26:27 +000076 decoration,
Chris Forbesc25b8072018-12-10 15:10:39 -080077 insn.wordCount() > 4 ? insn.word(4) : 0);
Chris Forbes93f70b32019-02-10 21:26:27 +000078
79 if (decoration == spv::DecorationCentroid)
80 modes.NeedsCentroid = true;
Chris Forbesc25b8072018-12-10 15:10:39 -080081 break;
82 }
83
84 case spv::OpDecorationGroup:
85 // Nothing to do here. We don't need to record the definition of the group; we'll just have
86 // the bundle of decorations float around. If we were to ever walk the decorations directly,
87 // we might think about introducing this as a real Object.
88 break;
89
90 case spv::OpGroupDecorate:
91 {
92 auto const &srcDecorations = decorations[insn.word(1)];
93 for (auto i = 2u; i < insn.wordCount(); i++)
94 {
95 // remaining operands are targets to apply the group to.
96 decorations[insn.word(i)].Apply(srcDecorations);
97 }
98 break;
99 }
100
101 case spv::OpGroupMemberDecorate:
102 {
103 auto const &srcDecorations = decorations[insn.word(1)];
104 for (auto i = 2u; i < insn.wordCount(); i += 2)
105 {
106 // remaining operands are pairs of <id>, literal for members to apply to.
107 auto &d = memberDecorations[insn.word(i)];
108 auto memberIndex = insn.word(i + 1);
109 if (memberIndex >= d.size())
110 d.resize(memberIndex + 1); // on demand resize, see above...
111 d[memberIndex].Apply(srcDecorations);
112 }
113 break;
114 }
115
Chris Forbese57f10e2019-03-04 10:53:07 -0800116 case spv::OpLabel:
117 if (seenLabel)
118 UNIMPLEMENTED("Shader contains multiple labels, has control flow");
119 seenLabel = true;
120 break;
121
122 case spv::OpReturn:
123 if (seenReturn)
124 UNIMPLEMENTED("Shader contains multiple returns, has control flow");
125 seenReturn = true;
126 break;
127
Chris Forbes4a979dc2019-01-17 09:36:46 -0800128 case spv::OpTypeVoid:
129 case spv::OpTypeBool:
130 case spv::OpTypeInt:
131 case spv::OpTypeFloat:
132 case spv::OpTypeVector:
133 case spv::OpTypeMatrix:
134 case spv::OpTypeImage:
135 case spv::OpTypeSampler:
136 case spv::OpTypeSampledImage:
137 case spv::OpTypeArray:
138 case spv::OpTypeRuntimeArray:
139 case spv::OpTypeStruct:
140 case spv::OpTypePointer:
141 case spv::OpTypeFunction:
Ben Clayton0bb83b82019-02-26 11:41:07 +0000142 DeclareType(insn);
Chris Forbes4a979dc2019-01-17 09:36:46 -0800143 break;
Chris Forbes296aa252018-12-27 11:48:21 -0800144
Chris Forbes4a979dc2019-01-17 09:36:46 -0800145 case spv::OpVariable:
146 {
Ben Claytonab51bbf2019-02-20 14:36:27 +0000147 TypeID typeId = insn.word(1);
148 ObjectID resultId = insn.word(2);
Chris Forbes4a979dc2019-01-17 09:36:46 -0800149 auto storageClass = static_cast<spv::StorageClass>(insn.word(3));
150 if (insn.wordCount() > 4)
151 UNIMPLEMENTED("Variable initializers not yet supported");
Chris Forbes296aa252018-12-27 11:48:21 -0800152
Chris Forbes4a979dc2019-01-17 09:36:46 -0800153 auto &object = defs[resultId];
154 object.kind = Object::Kind::Variable;
155 object.definition = insn;
Ben Clayton9a162482019-02-25 11:54:43 +0000156 object.type = typeId;
Chris Forbese9f8f5b2019-02-11 00:20:16 +0000157 object.pointerBase = insn.word(2); // base is itself
Chris Forbesc25b8072018-12-10 15:10:39 -0800158
Ben Claytonefec1b92019-03-05 17:38:16 +0000159 ASSERT(getType(typeId).storageClass == storageClass);
160
161 switch (storageClass)
Chris Forbesc25b8072018-12-10 15:10:39 -0800162 {
Ben Claytonefec1b92019-03-05 17:38:16 +0000163 case spv::StorageClassInput:
164 case spv::StorageClassOutput:
Ben Claytona1924732019-02-28 18:42:10 +0000165 ProcessInterfaceVariable(object);
Ben Claytonefec1b92019-03-05 17:38:16 +0000166 break;
167 case spv::StorageClassUniform:
168 case spv::StorageClassStorageBuffer:
169 object.kind = Object::Kind::PhysicalPointer;
170 break;
171
172 case spv::StorageClassPrivate:
173 case spv::StorageClassFunction:
174 break; // Correctly handled.
175
176 case spv::StorageClassUniformConstant:
177 case spv::StorageClassWorkgroup:
178 case spv::StorageClassCrossWorkgroup:
179 case spv::StorageClassGeneric:
180 case spv::StorageClassPushConstant:
181 case spv::StorageClassAtomicCounter:
182 case spv::StorageClassImage:
183 UNIMPLEMENTED("StorageClass %d not yet implemented", (int)storageClass);
184 break;
185
186 default:
187 UNREACHABLE("Unexpected StorageClass"); // See Appendix A of the Vulkan spec.
188 break;
Chris Forbesc25b8072018-12-10 15:10:39 -0800189 }
Chris Forbes4a979dc2019-01-17 09:36:46 -0800190 break;
191 }
Chris Forbes296aa252018-12-27 11:48:21 -0800192
Chris Forbesbc3a0ee2018-12-27 16:02:58 -0800193 case spv::OpConstant:
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800194 CreateConstant(insn).constantValue[0] = insn.word(3);
195 break;
Chris Forbesbc3a0ee2018-12-27 16:02:58 -0800196 case spv::OpConstantFalse:
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800197 CreateConstant(insn).constantValue[0] = 0; // represent boolean false as zero
198 break;
Chris Forbesbc3a0ee2018-12-27 16:02:58 -0800199 case spv::OpConstantTrue:
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800200 CreateConstant(insn).constantValue[0] = ~0u; // represent boolean true as all bits set
201 break;
Chris Forbesbc3a0ee2018-12-27 16:02:58 -0800202 case spv::OpConstantNull:
203 {
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800204 // OpConstantNull forms a constant of arbitrary type, all zeros.
Ben Clayton9a162482019-02-25 11:54:43 +0000205 auto &object = CreateConstant(insn);
206 auto &objectTy = getType(object.type);
207 for (auto i = 0u; i < objectTy.sizeInComponents; i++)
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800208 {
209 object.constantValue[i] = 0;
210 }
211 break;
212 }
213 case spv::OpConstantComposite:
214 {
215 auto &object = CreateConstant(insn);
216 auto offset = 0u;
217 for (auto i = 0u; i < insn.wordCount() - 3; i++)
218 {
Ben Clayton9a162482019-02-25 11:54:43 +0000219 auto &constituent = getObject(insn.word(i + 3));
220 auto &constituentTy = getType(constituent.type);
221 for (auto j = 0u; j < constituentTy.sizeInComponents; j++)
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800222 object.constantValue[offset++] = constituent.constantValue[j];
223 }
Chris Forbesbc3a0ee2018-12-27 16:02:58 -0800224 break;
225 }
226
Chris Forbesbde34082018-12-28 12:03:10 -0800227 case spv::OpCapability:
228 // Various capabilities will be declared, but none affect our code generation at this point.
229 case spv::OpMemoryModel:
230 // Memory model does not affect our code generation until we decide to do Vulkan Memory Model support.
231 case spv::OpEntryPoint:
Chris Forbes7edf5342019-02-10 22:41:21 +0000232 case spv::OpFunction:
233 case spv::OpFunctionEnd:
234 // Due to preprocessing, the entrypoint and its function provide no value.
235 break;
236 case spv::OpExtInstImport:
237 // We will only support the GLSL 450 extended instruction set, so no point in tracking the ID we assign it.
238 // Valid shaders will not attempt to import any other instruction sets.
Chris Forbes9667a5b2019-03-07 09:26:48 -0800239 if (0 != strcmp("GLSL.std.450", reinterpret_cast<char const *>(insn.wordPointer(2))))
240 {
241 UNIMPLEMENTED("Only GLSL extended instruction set is supported");
242 }
243 break;
Chris Forbes1776af72019-02-22 17:39:57 -0800244 case spv::OpName:
245 case spv::OpMemberName:
246 case spv::OpSource:
247 case spv::OpSourceContinued:
248 case spv::OpSourceExtension:
249 // No semantic impact
Chris Forbes7edf5342019-02-10 22:41:21 +0000250 break;
251
252 case spv::OpFunctionParameter:
253 case spv::OpFunctionCall:
254 case spv::OpSpecConstant:
255 case spv::OpSpecConstantComposite:
256 case spv::OpSpecConstantFalse:
257 case spv::OpSpecConstantOp:
258 case spv::OpSpecConstantTrue:
259 // These should have all been removed by preprocessing passes. If we see them here,
260 // our assumptions are wrong and we will probably generate wrong code.
261 UNIMPLEMENTED("These instructions should have already been lowered.");
262 break;
263
Chris Forbes4d503052019-03-01 17:13:57 -0800264 case spv::OpFConvert:
265 case spv::OpSConvert:
266 case spv::OpUConvert:
267 UNIMPLEMENTED("No valid uses for Op*Convert until we support multiple bit widths");
268 break;
269
Chris Forbesa71b8e92019-02-10 22:42:42 +0000270 case spv::OpLoad:
271 case spv::OpAccessChain:
Chris Forbesb97a9572019-02-21 16:51:42 -0800272 case spv::OpCompositeConstruct:
Chris Forbes1bc1acf2019-02-21 18:40:33 -0800273 case spv::OpCompositeInsert:
Chris Forbesb12846d2019-02-21 18:53:58 -0800274 case spv::OpCompositeExtract:
Chris Forbes83fc5442019-02-26 22:16:07 -0800275 case spv::OpVectorShuffle:
Ben Claytondd1e37e2019-02-28 19:59:15 +0000276 case spv::OpNot: // Unary ops
277 case spv::OpSNegate:
278 case spv::OpFNegate:
279 case spv::OpLogicalNot:
280 case spv::OpIAdd: // Binary ops
281 case spv::OpISub:
282 case spv::OpIMul:
283 case spv::OpSDiv:
284 case spv::OpUDiv:
285 case spv::OpFAdd:
286 case spv::OpFSub:
287 case spv::OpFDiv:
Ben Claytonec1aeb82019-03-04 19:33:27 +0000288 case spv::OpFOrdEqual:
289 case spv::OpFUnordEqual:
290 case spv::OpFOrdNotEqual:
291 case spv::OpFUnordNotEqual:
292 case spv::OpFOrdLessThan:
293 case spv::OpFUnordLessThan:
294 case spv::OpFOrdGreaterThan:
295 case spv::OpFUnordGreaterThan:
296 case spv::OpFOrdLessThanEqual:
297 case spv::OpFUnordLessThanEqual:
298 case spv::OpFOrdGreaterThanEqual:
299 case spv::OpFUnordGreaterThanEqual:
Ben Claytondd1e37e2019-02-28 19:59:15 +0000300 case spv::OpUMod:
Ben Claytone95eeb12019-03-04 16:32:09 +0000301 case spv::OpIEqual:
302 case spv::OpINotEqual:
303 case spv::OpUGreaterThan:
304 case spv::OpSGreaterThan:
305 case spv::OpUGreaterThanEqual:
306 case spv::OpSGreaterThanEqual:
307 case spv::OpULessThan:
308 case spv::OpSLessThan:
309 case spv::OpULessThanEqual:
310 case spv::OpSLessThanEqual:
Ben Claytondd1e37e2019-02-28 19:59:15 +0000311 case spv::OpShiftRightLogical:
312 case spv::OpShiftRightArithmetic:
313 case spv::OpShiftLeftLogical:
314 case spv::OpBitwiseOr:
315 case spv::OpBitwiseXor:
316 case spv::OpBitwiseAnd:
317 case spv::OpLogicalOr:
318 case spv::OpLogicalAnd:
Chris Forbese86b6dc2019-03-01 09:08:47 -0800319 case spv::OpUMulExtended:
320 case spv::OpSMulExtended:
Chris Forbes2b287cc2019-03-01 13:24:17 -0800321 case spv::OpDot:
Chris Forbes4d503052019-03-01 17:13:57 -0800322 case spv::OpConvertFToU:
323 case spv::OpConvertFToS:
324 case spv::OpConvertSToF:
325 case spv::OpConvertUToF:
326 case spv::OpBitcast:
Ben Claytonbf943f62019-03-05 12:57:39 +0000327 case spv::OpSelect:
Chris Forbes9667a5b2019-03-07 09:26:48 -0800328 case spv::OpExtInst:
Chris Forbes3ed33ce2019-03-07 13:38:31 -0800329 case spv::OpIsInf:
330 case spv::OpIsNan:
Chris Forbese86b6dc2019-03-01 09:08:47 -0800331 // Instructions that yield an intermediate value
Chris Forbesa71b8e92019-02-10 22:42:42 +0000332 {
Ben Claytonab51bbf2019-02-20 14:36:27 +0000333 TypeID typeId = insn.word(1);
334 ObjectID resultId = insn.word(2);
Chris Forbesa71b8e92019-02-10 22:42:42 +0000335 auto &object = defs[resultId];
Ben Clayton9a162482019-02-25 11:54:43 +0000336 object.type = typeId;
Chris Forbesa71b8e92019-02-10 22:42:42 +0000337 object.kind = Object::Kind::Value;
338 object.definition = insn;
Chris Forbesa71b8e92019-02-10 22:42:42 +0000339
340 if (insn.opcode() == spv::OpAccessChain)
341 {
342 // interior ptr has two parts:
343 // - logical base ptr, common across all lanes and known at compile time
344 // - per-lane offset
Ben Clayton9a162482019-02-25 11:54:43 +0000345 ObjectID baseId = insn.word(3);
346 object.pointerBase = getObject(baseId).pointerBase;
Chris Forbesa71b8e92019-02-10 22:42:42 +0000347 }
348 break;
349 }
350
Chris Forbes7edf5342019-02-10 22:41:21 +0000351 case spv::OpStore:
Chris Forbes7edf5342019-02-10 22:41:21 +0000352 // Don't need to do anything during analysis pass
353 break;
354
355 case spv::OpKill:
356 modes.ContainsKill = true;
Chris Forbesbde34082018-12-28 12:03:10 -0800357 break;
358
Chris Forbes4a979dc2019-01-17 09:36:46 -0800359 default:
Chris Forbese57f10e2019-03-04 10:53:07 -0800360 UNIMPLEMENTED(OpcodeName(insn.opcode()).c_str());
Chris Forbesaf4ed532018-12-06 18:33:27 -0800361 }
362 }
363 }
364
Ben Clayton0bb83b82019-02-26 11:41:07 +0000365 void SpirvShader::DeclareType(InsnIterator insn)
366 {
367 TypeID resultId = insn.word(1);
368
369 auto &type = types[resultId];
370 type.definition = insn;
371 type.sizeInComponents = ComputeTypeSize(insn);
372
373 // A structure is a builtin block if it has a builtin
374 // member. All members of such a structure are builtins.
375 switch (insn.opcode())
376 {
377 case spv::OpTypeStruct:
378 {
379 auto d = memberDecorations.find(resultId);
380 if (d != memberDecorations.end())
381 {
382 for (auto &m : d->second)
383 {
384 if (m.HasBuiltIn)
385 {
386 type.isBuiltInBlock = true;
387 break;
388 }
389 }
390 }
391 break;
392 }
393 case spv::OpTypePointer:
394 {
395 TypeID elementTypeId = insn.word(3);
396 type.element = elementTypeId;
397 type.isBuiltInBlock = getType(elementTypeId).isBuiltInBlock;
398 type.storageClass = static_cast<spv::StorageClass>(insn.word(2));
399 break;
400 }
401 case spv::OpTypeVector:
402 case spv::OpTypeMatrix:
403 case spv::OpTypeArray:
404 case spv::OpTypeRuntimeArray:
405 {
406 TypeID elementTypeId = insn.word(2);
407 type.element = elementTypeId;
408 break;
409 }
410 default:
411 break;
412 }
413 }
414
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800415 SpirvShader::Object& SpirvShader::CreateConstant(InsnIterator insn)
416 {
Ben Claytonab51bbf2019-02-20 14:36:27 +0000417 TypeID typeId = insn.word(1);
418 ObjectID resultId = insn.word(2);
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800419 auto &object = defs[resultId];
Ben Clayton9a162482019-02-25 11:54:43 +0000420 auto &objectTy = getType(typeId);
421 object.type = typeId;
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800422 object.kind = Object::Kind::Constant;
423 object.definition = insn;
Ben Clayton9a162482019-02-25 11:54:43 +0000424 object.constantValue = std::unique_ptr<uint32_t[]>(new uint32_t[objectTy.sizeInComponents]);
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800425 return object;
426 }
427
Chris Forbes049ff382019-02-02 15:16:43 -0800428 void SpirvShader::ProcessInterfaceVariable(Object &object)
Chris Forbesbde34082018-12-28 12:03:10 -0800429 {
Ben Clayton9a162482019-02-25 11:54:43 +0000430 auto &objectTy = getType(object.type);
Ben Clayton6fae32c2019-02-28 20:06:42 +0000431 ASSERT(objectTy.storageClass == spv::StorageClassInput || objectTy.storageClass == spv::StorageClassOutput);
Chris Forbesbde34082018-12-28 12:03:10 -0800432
Ben Clayton6fae32c2019-02-28 20:06:42 +0000433 ASSERT(objectTy.definition.opcode() == spv::OpTypePointer);
Ben Clayton9a162482019-02-25 11:54:43 +0000434 auto pointeeTy = getType(objectTy.element);
Chris Forbesbde34082018-12-28 12:03:10 -0800435
Ben Clayton9a162482019-02-25 11:54:43 +0000436 auto &builtinInterface = (objectTy.storageClass == spv::StorageClassInput) ? inputBuiltins : outputBuiltins;
437 auto &userDefinedInterface = (objectTy.storageClass == spv::StorageClassInput) ? inputs : outputs;
438
Ben Clayton6fae32c2019-02-28 20:06:42 +0000439 ASSERT(object.definition.opcode() == spv::OpVariable);
Ben Claytonab51bbf2019-02-20 14:36:27 +0000440 ObjectID resultId = object.definition.word(2);
Ben Clayton9a162482019-02-25 11:54:43 +0000441
442 if (objectTy.isBuiltInBlock)
Chris Forbesbde34082018-12-28 12:03:10 -0800443 {
444 // walk the builtin block, registering each of its members separately.
Ben Clayton9a162482019-02-25 11:54:43 +0000445 auto m = memberDecorations.find(objectTy.element);
Ben Clayton6fae32c2019-02-28 20:06:42 +0000446 ASSERT(m != memberDecorations.end()); // otherwise we wouldn't have marked the type chain
Ben Clayton9a162482019-02-25 11:54:43 +0000447 auto &structType = pointeeTy.definition;
Chris Forbesbde34082018-12-28 12:03:10 -0800448 auto offset = 0u;
449 auto word = 2u;
450 for (auto &member : m->second)
451 {
Chris Forbes840809a2019-01-14 14:30:20 -0800452 auto &memberType = getType(structType.word(word));
Chris Forbesbde34082018-12-28 12:03:10 -0800453
454 if (member.HasBuiltIn)
455 {
456 builtinInterface[member.BuiltIn] = {resultId, offset, memberType.sizeInComponents};
457 }
458
459 offset += memberType.sizeInComponents;
460 ++word;
461 }
462 return;
463 }
464
465 auto d = decorations.find(resultId);
466 if (d != decorations.end() && d->second.HasBuiltIn)
467 {
Ben Clayton9a162482019-02-25 11:54:43 +0000468 builtinInterface[d->second.BuiltIn] = {resultId, 0, pointeeTy.sizeInComponents};
Chris Forbesbde34082018-12-28 12:03:10 -0800469 }
470 else
471 {
Chris Forbes049ff382019-02-02 15:16:43 -0800472 object.kind = Object::Kind::InterfaceVariable;
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800473 VisitInterface(resultId,
474 [&userDefinedInterface](Decorations const &d, AttribType type) {
475 // Populate a single scalar slot in the interface from a collection of decorations and the intended component type.
476 auto scalarSlot = (d.Location << 2) | d.Component;
Ben Clayton6fae32c2019-02-28 20:06:42 +0000477 ASSERT(scalarSlot >= 0 &&
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800478 scalarSlot < static_cast<int32_t>(userDefinedInterface.size()));
479
480 auto &slot = userDefinedInterface[scalarSlot];
481 slot.Type = type;
482 slot.Flat = d.Flat;
483 slot.NoPerspective = d.NoPerspective;
484 slot.Centroid = d.Centroid;
485 });
Chris Forbesbde34082018-12-28 12:03:10 -0800486 }
487 }
488
Chris Forbesaf4ed532018-12-06 18:33:27 -0800489 void SpirvShader::ProcessExecutionMode(InsnIterator insn)
490 {
491 auto mode = static_cast<spv::ExecutionMode>(insn.word(2));
Chris Forbes4a979dc2019-01-17 09:36:46 -0800492 switch (mode)
493 {
494 case spv::ExecutionModeEarlyFragmentTests:
495 modes.EarlyFragmentTests = true;
496 break;
497 case spv::ExecutionModeDepthReplacing:
498 modes.DepthReplacing = true;
499 break;
500 case spv::ExecutionModeDepthGreater:
501 modes.DepthGreater = true;
502 break;
503 case spv::ExecutionModeDepthLess:
504 modes.DepthLess = true;
505 break;
506 case spv::ExecutionModeDepthUnchanged:
507 modes.DepthUnchanged = true;
508 break;
509 case spv::ExecutionModeLocalSize:
510 modes.LocalSizeX = insn.word(3);
511 modes.LocalSizeZ = insn.word(5);
512 modes.LocalSizeY = insn.word(4);
513 break;
514 case spv::ExecutionModeOriginUpperLeft:
515 // This is always the case for a Vulkan shader. Do nothing.
516 break;
517 default:
518 UNIMPLEMENTED("No other execution modes are permitted");
Chris Forbesaf4ed532018-12-06 18:33:27 -0800519 }
520 }
Chris Forbes739a7fb2018-12-08 13:09:40 -0800521
522 uint32_t SpirvShader::ComputeTypeSize(sw::SpirvShader::InsnIterator insn)
523 {
524 // Types are always built from the bottom up (with the exception of forward ptrs, which
525 // don't appear in Vulkan shaders. Therefore, we can always assume our component parts have
526 // already been described (and so their sizes determined)
527 switch (insn.opcode())
528 {
529 case spv::OpTypeVoid:
530 case spv::OpTypeSampler:
531 case spv::OpTypeImage:
532 case spv::OpTypeSampledImage:
533 case spv::OpTypeFunction:
534 case spv::OpTypeRuntimeArray:
535 // Objects that don't consume any space.
536 // Descriptor-backed objects currently only need exist at compile-time.
537 // Runtime arrays don't appear in places where their size would be interesting
538 return 0;
539
540 case spv::OpTypeBool:
541 case spv::OpTypeFloat:
542 case spv::OpTypeInt:
543 // All the fundamental types are 1 component. If we ever add support for 8/16/64-bit components,
544 // we might need to change this, but only 32 bit components are required for Vulkan 1.1.
545 return 1;
546
547 case spv::OpTypeVector:
548 case spv::OpTypeMatrix:
549 // Vectors and matrices both consume element count * element size.
Chris Forbes840809a2019-01-14 14:30:20 -0800550 return getType(insn.word(2)).sizeInComponents * insn.word(3);
Chris Forbes739a7fb2018-12-08 13:09:40 -0800551
552 case spv::OpTypeArray:
Chris Forbes5be4d702018-12-27 16:12:31 -0800553 {
554 // Element count * element size. Array sizes come from constant ids.
555 auto arraySize = GetConstantInt(insn.word(3));
Chris Forbes840809a2019-01-14 14:30:20 -0800556 return getType(insn.word(2)).sizeInComponents * arraySize;
Chris Forbes5be4d702018-12-27 16:12:31 -0800557 }
Chris Forbes739a7fb2018-12-08 13:09:40 -0800558
559 case spv::OpTypeStruct:
560 {
561 uint32_t size = 0;
562 for (uint32_t i = 2u; i < insn.wordCount(); i++)
563 {
Chris Forbes840809a2019-01-14 14:30:20 -0800564 size += getType(insn.word(i)).sizeInComponents;
Chris Forbes739a7fb2018-12-08 13:09:40 -0800565 }
566 return size;
567 }
568
569 case spv::OpTypePointer:
Chris Forbes0f59a2c2019-02-10 23:03:12 +0000570 // Runtime representation of a pointer is a per-lane index.
571 // Note: clients are expected to look through the pointer if they want the pointee size instead.
572 return 1;
Chris Forbes739a7fb2018-12-08 13:09:40 -0800573
574 default:
575 // Some other random insn.
576 UNIMPLEMENTED("Only types are supported");
Ben Clayton60a3d6f2019-02-26 17:24:46 +0000577 return 0;
Chris Forbes739a7fb2018-12-08 13:09:40 -0800578 }
579 }
Chris Forbesc25b8072018-12-10 15:10:39 -0800580
Ben Clayton831db962019-02-27 14:57:18 +0000581 bool SpirvShader::IsStorageInterleavedByLane(spv::StorageClass storageClass)
582 {
583 switch (storageClass)
584 {
585 case spv::StorageClassUniform:
586 case spv::StorageClassStorageBuffer:
587 return false;
588 default:
589 return true;
590 }
591 }
592
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800593 template<typename F>
Ben Claytonab51bbf2019-02-20 14:36:27 +0000594 int SpirvShader::VisitInterfaceInner(TypeID id, Decorations d, F f) const
Chris Forbes5839dcf2018-12-10 19:02:58 -0800595 {
596 // Recursively walks variable definition and its type tree, taking into account
597 // any explicit Location or Component decorations encountered; where explicit
598 // Locations or Components are not specified, assigns them sequentially.
599 // Collected decorations are carried down toward the leaves and across
600 // siblings; Effect of decorations intentionally does not flow back up the tree.
601 //
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800602 // F is a functor to be called with the effective decoration set for every component.
603 //
604 // Returns the next available location, and calls f().
Chris Forbes5839dcf2018-12-10 19:02:58 -0800605
606 // This covers the rules in Vulkan 1.1 spec, 14.1.4 Location Assignment.
607
Chris Forbes49d664d2019-02-12 19:24:50 +0000608 ApplyDecorationsForId(&d, id);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800609
Chris Forbes840809a2019-01-14 14:30:20 -0800610 auto const &obj = getType(id);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800611 switch (obj.definition.opcode())
612 {
Chris Forbes5839dcf2018-12-10 19:02:58 -0800613 case spv::OpTypePointer:
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800614 return VisitInterfaceInner<F>(obj.definition.word(3), d, f);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800615 case spv::OpTypeMatrix:
616 for (auto i = 0u; i < obj.definition.word(3); i++, d.Location++)
617 {
618 // consumes same components of N consecutive locations
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800619 VisitInterfaceInner<F>(obj.definition.word(2), d, f);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800620 }
621 return d.Location;
622 case spv::OpTypeVector:
623 for (auto i = 0u; i < obj.definition.word(3); i++, d.Component++)
624 {
625 // consumes N consecutive components in the same location
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800626 VisitInterfaceInner<F>(obj.definition.word(2), d, f);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800627 }
628 return d.Location + 1;
629 case spv::OpTypeFloat:
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800630 f(d, ATTRIBTYPE_FLOAT);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800631 return d.Location + 1;
632 case spv::OpTypeInt:
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800633 f(d, obj.definition.word(3) ? ATTRIBTYPE_INT : ATTRIBTYPE_UINT);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800634 return d.Location + 1;
635 case spv::OpTypeBool:
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800636 f(d, ATTRIBTYPE_UINT);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800637 return d.Location + 1;
638 case spv::OpTypeStruct:
639 {
Chris Forbes5839dcf2018-12-10 19:02:58 -0800640 // iterate over members, which may themselves have Location/Component decorations
641 for (auto i = 0u; i < obj.definition.wordCount() - 2; i++)
642 {
Chris Forbes49d664d2019-02-12 19:24:50 +0000643 ApplyDecorationsForIdMember(&d, id, i);
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800644 d.Location = VisitInterfaceInner<F>(obj.definition.word(i + 2), d, f);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800645 d.Component = 0; // Implicit locations always have component=0
646 }
647 return d.Location;
648 }
Chris Forbes5be4d702018-12-27 16:12:31 -0800649 case spv::OpTypeArray:
650 {
651 auto arraySize = GetConstantInt(obj.definition.word(3));
652 for (auto i = 0u; i < arraySize; i++)
653 {
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800654 d.Location = VisitInterfaceInner<F>(obj.definition.word(2), d, f);
Chris Forbes5be4d702018-12-27 16:12:31 -0800655 }
656 return d.Location;
657 }
Chris Forbes5839dcf2018-12-10 19:02:58 -0800658 default:
659 // Intentionally partial; most opcodes do not participate in type hierarchies
660 return 0;
661 }
662 }
663
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800664 template<typename F>
Ben Claytonab51bbf2019-02-20 14:36:27 +0000665 void SpirvShader::VisitInterface(ObjectID id, F f) const
Chris Forbes5839dcf2018-12-10 19:02:58 -0800666 {
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800667 // Walk a variable definition and call f for each component in it.
Chris Forbes5839dcf2018-12-10 19:02:58 -0800668 Decorations d{};
Chris Forbes49d664d2019-02-12 19:24:50 +0000669 ApplyDecorationsForId(&d, id);
Chris Forbes1c658232019-02-01 17:12:25 -0800670
671 auto def = getObject(id).definition;
Ben Clayton6fae32c2019-02-28 20:06:42 +0000672 ASSERT(def.opcode() == spv::OpVariable);
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800673 VisitInterfaceInner<F>(def.word(1), d, f);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800674 }
675
Ben Clayton24ea5152019-02-26 11:02:42 +0000676 SIMD::Int SpirvShader::WalkAccessChain(ObjectID id, uint32_t numIndexes, uint32_t const *indexIds, SpirvRoutine *routine) const
Chris Forbes38f85b32019-02-12 20:10:05 +0000677 {
Chris Forbes38f85b32019-02-12 20:10:05 +0000678 // TODO: think about explicit layout (UBO/SSBO) storage classes
679 // TODO: avoid doing per-lane work in some cases if we can?
680
Chris Forbes6397ed02019-02-15 16:39:17 -0800681 int constantOffset = 0;
Ben Clayton24ea5152019-02-26 11:02:42 +0000682 SIMD::Int dynamicOffset = SIMD::Int(0);
Ben Clayton9a162482019-02-25 11:54:43 +0000683 auto &baseObject = getObject(id);
684 TypeID typeId = getType(baseObject.type).element;
Chris Forbes38f85b32019-02-12 20:10:05 +0000685
Chris Forbese4ef5f72019-02-15 16:00:08 -0800686 // The <base> operand is an intermediate value itself, ie produced by a previous OpAccessChain.
687 // Start with its offset and build from there.
Chris Forbes38f85b32019-02-12 20:10:05 +0000688 if (baseObject.kind == Object::Kind::Value)
Ben Clayton24ea5152019-02-26 11:02:42 +0000689 dynamicOffset += As<SIMD::Int>(routine->getIntermediate(id)[0]);
Chris Forbes38f85b32019-02-12 20:10:05 +0000690
691 for (auto i = 0u; i < numIndexes; i++)
692 {
693 auto & type = getType(typeId);
694 switch (type.definition.opcode())
695 {
696 case spv::OpTypeStruct:
697 {
698 int memberIndex = GetConstantInt(indexIds[i]);
699 int offsetIntoStruct = 0;
700 for (auto j = 0; j < memberIndex; j++) {
Chris Forbes58bee562019-02-19 17:41:41 -0800701 auto memberType = type.definition.word(2u + j);
702 offsetIntoStruct += getType(memberType).sizeInComponents;
Chris Forbes38f85b32019-02-12 20:10:05 +0000703 }
Chris Forbes6397ed02019-02-15 16:39:17 -0800704 constantOffset += offsetIntoStruct;
Chris Forbes58bee562019-02-19 17:41:41 -0800705 typeId = type.definition.word(2u + memberIndex);
Chris Forbes38f85b32019-02-12 20:10:05 +0000706 break;
707 }
708
709 case spv::OpTypeVector:
710 case spv::OpTypeMatrix:
711 case spv::OpTypeArray:
712 {
Ben Clayton9a162482019-02-25 11:54:43 +0000713 auto stride = getType(type.element).sizeInComponents;
Chris Forbes38f85b32019-02-12 20:10:05 +0000714 auto & obj = getObject(indexIds[i]);
715 if (obj.kind == Object::Kind::Constant)
Chris Forbes6397ed02019-02-15 16:39:17 -0800716 constantOffset += stride * GetConstantInt(indexIds[i]);
Chris Forbes38f85b32019-02-12 20:10:05 +0000717 else
Ben Clayton24ea5152019-02-26 11:02:42 +0000718 dynamicOffset += SIMD::Int(stride) * As<SIMD::Int>(routine->getIntermediate(indexIds[i])[0]);
Ben Clayton9a162482019-02-25 11:54:43 +0000719 typeId = type.element;
Chris Forbes38f85b32019-02-12 20:10:05 +0000720 break;
721 }
722
723 default:
Ben Claytond4e4c662019-02-26 11:54:34 +0000724 UNIMPLEMENTED("Unexpected type '%s' in WalkAccessChain", OpcodeName(type.definition.opcode()).c_str());
Chris Forbes38f85b32019-02-12 20:10:05 +0000725 }
726 }
727
Ben Clayton24ea5152019-02-26 11:02:42 +0000728 return dynamicOffset + SIMD::Int(constantOffset);
Chris Forbes38f85b32019-02-12 20:10:05 +0000729 }
730
Chris Forbes9638b942019-02-21 18:39:31 -0800731 uint32_t SpirvShader::WalkLiteralAccessChain(TypeID typeId, uint32_t numIndexes, uint32_t const *indexes) const
732 {
733 uint32_t constantOffset = 0;
734
735 for (auto i = 0u; i < numIndexes; i++)
736 {
737 auto & type = getType(typeId);
738 switch (type.definition.opcode())
739 {
740 case spv::OpTypeStruct:
741 {
742 int memberIndex = indexes[i];
743 int offsetIntoStruct = 0;
744 for (auto j = 0; j < memberIndex; j++) {
745 auto memberType = type.definition.word(2u + j);
746 offsetIntoStruct += getType(memberType).sizeInComponents;
747 }
748 constantOffset += offsetIntoStruct;
749 typeId = type.definition.word(2u + memberIndex);
750 break;
751 }
752
753 case spv::OpTypeVector:
754 case spv::OpTypeMatrix:
755 case spv::OpTypeArray:
756 {
757 auto elementType = type.definition.word(2);
758 auto stride = getType(elementType).sizeInComponents;
759 constantOffset += stride * indexes[i];
760 typeId = elementType;
761 break;
762 }
763
764 default:
765 UNIMPLEMENTED("Unexpected type in WalkLiteralAccessChain");
766 }
767 }
768
769 return constantOffset;
770 }
771
Chris Forbesc25b8072018-12-10 15:10:39 -0800772 void SpirvShader::Decorations::Apply(spv::Decoration decoration, uint32_t arg)
773 {
774 switch (decoration)
775 {
776 case spv::DecorationLocation:
777 HasLocation = true;
778 Location = static_cast<int32_t>(arg);
779 break;
780 case spv::DecorationComponent:
781 HasComponent = true;
782 Component = arg;
783 break;
Ben Claytond073d8e2019-02-26 11:06:50 +0000784 case spv::DecorationDescriptorSet:
785 HasDescriptorSet = true;
786 DescriptorSet = arg;
787 break;
788 case spv::DecorationBinding:
789 HasBinding = true;
790 Binding = arg;
791 break;
Chris Forbesc25b8072018-12-10 15:10:39 -0800792 case spv::DecorationBuiltIn:
793 HasBuiltIn = true;
794 BuiltIn = static_cast<spv::BuiltIn>(arg);
795 break;
796 case spv::DecorationFlat:
797 Flat = true;
798 break;
799 case spv::DecorationNoPerspective:
Chris Forbes5839dcf2018-12-10 19:02:58 -0800800 NoPerspective = true;
Chris Forbesc25b8072018-12-10 15:10:39 -0800801 break;
802 case spv::DecorationCentroid:
803 Centroid = true;
804 break;
805 case spv::DecorationBlock:
806 Block = true;
807 break;
808 case spv::DecorationBufferBlock:
809 BufferBlock = true;
810 break;
811 default:
812 // Intentionally partial, there are many decorations we just don't care about.
813 break;
814 }
815 }
816
817 void SpirvShader::Decorations::Apply(const sw::SpirvShader::Decorations &src)
818 {
819 // Apply a decoration group to this set of decorations
820 if (src.HasBuiltIn)
821 {
822 HasBuiltIn = true;
823 BuiltIn = src.BuiltIn;
824 }
825
826 if (src.HasLocation)
827 {
828 HasLocation = true;
829 Location = src.Location;
830 }
831
832 if (src.HasComponent)
833 {
834 HasComponent = true;
835 Component = src.Component;
836 }
837
Ben Claytond073d8e2019-02-26 11:06:50 +0000838 if (src.HasDescriptorSet)
839 {
840 HasDescriptorSet = true;
841 DescriptorSet = src.DescriptorSet;
842 }
843
844 if (src.HasBinding)
845 {
846 HasBinding = true;
847 Binding = src.Binding;
848 }
849
Chris Forbesc25b8072018-12-10 15:10:39 -0800850 Flat |= src.Flat;
Chris Forbes5839dcf2018-12-10 19:02:58 -0800851 NoPerspective |= src.NoPerspective;
Chris Forbesc25b8072018-12-10 15:10:39 -0800852 Centroid |= src.Centroid;
853 Block |= src.Block;
854 BufferBlock |= src.BufferBlock;
855 }
Chris Forbesbc3a0ee2018-12-27 16:02:58 -0800856
Ben Claytonab51bbf2019-02-20 14:36:27 +0000857 void SpirvShader::ApplyDecorationsForId(Decorations *d, TypeOrObjectID id) const
Chris Forbes49d664d2019-02-12 19:24:50 +0000858 {
859 auto it = decorations.find(id);
860 if (it != decorations.end())
861 d->Apply(it->second);
862 }
863
Ben Claytonab51bbf2019-02-20 14:36:27 +0000864 void SpirvShader::ApplyDecorationsForIdMember(Decorations *d, TypeID id, uint32_t member) const
Chris Forbes49d664d2019-02-12 19:24:50 +0000865 {
866 auto it = memberDecorations.find(id);
867 if (it != memberDecorations.end() && member < it->second.size())
868 {
869 d->Apply(it->second[member]);
870 }
871 }
872
Ben Claytonab51bbf2019-02-20 14:36:27 +0000873 uint32_t SpirvShader::GetConstantInt(ObjectID id) const
Chris Forbesbc3a0ee2018-12-27 16:02:58 -0800874 {
875 // Slightly hackish access to constants very early in translation.
876 // General consumption of constants by other instructions should
877 // probably be just lowered to Reactor.
878
879 // TODO: not encountered yet since we only use this for array sizes etc,
880 // but is possible to construct integer constant 0 via OpConstantNull.
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800881 auto insn = getObject(id).definition;
Ben Clayton6fae32c2019-02-28 20:06:42 +0000882 ASSERT(insn.opcode() == spv::OpConstant);
883 ASSERT(getType(insn.word(1)).definition.opcode() == spv::OpTypeInt);
Chris Forbesbc3a0ee2018-12-27 16:02:58 -0800884 return insn.word(3);
885 }
Chris Forbesd5aed492019-02-02 15:18:52 -0800886
887 // emit-time
888
Chris Forbesc61271e2019-02-19 17:01:28 -0800889 void SpirvShader::emitProlog(SpirvRoutine *routine) const
Chris Forbesd5aed492019-02-02 15:18:52 -0800890 {
891 for (auto insn : *this)
892 {
893 switch (insn.opcode())
894 {
895 case spv::OpVariable:
896 {
Ben Claytonab51bbf2019-02-20 14:36:27 +0000897 ObjectID resultId = insn.word(2);
Chris Forbes0eba65b2019-02-13 12:24:35 -0800898 auto &object = getObject(resultId);
Ben Clayton9a162482019-02-25 11:54:43 +0000899 auto &objectTy = getType(object.type);
900 auto &pointeeTy = getType(objectTy.element);
Chris Forbesd5aed492019-02-02 15:18:52 -0800901 // TODO: what to do about zero-slot objects?
Ben Clayton9a162482019-02-25 11:54:43 +0000902 if (pointeeTy.sizeInComponents > 0)
Chris Forbesd5aed492019-02-02 15:18:52 -0800903 {
Ben Clayton9a162482019-02-25 11:54:43 +0000904 routine->createLvalue(insn.word(2), pointeeTy.sizeInComponents);
Chris Forbesd5aed492019-02-02 15:18:52 -0800905 }
906 break;
907 }
908 default:
Chris Forbese9f8f5b2019-02-11 00:20:16 +0000909 // Nothing else produces interface variables, so can all be safely ignored.
Chris Forbesd5aed492019-02-02 15:18:52 -0800910 break;
911 }
912 }
913 }
914
915 void SpirvShader::emit(SpirvRoutine *routine) const
916 {
Chris Forbesd5aed492019-02-02 15:18:52 -0800917 for (auto insn : *this)
918 {
919 switch (insn.opcode())
920 {
Chris Forbese53533d2019-02-21 16:49:51 -0800921 case spv::OpTypeVoid:
922 case spv::OpTypeInt:
923 case spv::OpTypeFloat:
924 case spv::OpTypeBool:
925 case spv::OpTypeVector:
926 case spv::OpTypeArray:
927 case spv::OpTypeRuntimeArray:
928 case spv::OpTypeMatrix:
929 case spv::OpTypeStruct:
930 case spv::OpTypePointer:
931 case spv::OpTypeFunction:
932 case spv::OpExecutionMode:
933 case spv::OpMemoryModel:
934 case spv::OpFunction:
935 case spv::OpFunctionEnd:
936 case spv::OpConstant:
937 case spv::OpConstantNull:
938 case spv::OpConstantTrue:
939 case spv::OpConstantFalse:
940 case spv::OpConstantComposite:
941 case spv::OpExtension:
942 case spv::OpCapability:
943 case spv::OpEntryPoint:
944 case spv::OpExtInstImport:
945 case spv::OpDecorate:
946 case spv::OpMemberDecorate:
947 case spv::OpGroupDecorate:
948 case spv::OpGroupMemberDecorate:
949 case spv::OpDecorationGroup:
Chris Forbes1776af72019-02-22 17:39:57 -0800950 case spv::OpName:
951 case spv::OpMemberName:
952 case spv::OpSource:
953 case spv::OpSourceContinued:
954 case spv::OpSourceExtension:
Chris Forbese53533d2019-02-21 16:49:51 -0800955 // Nothing to do at emit time. These are either fully handled at analysis time,
956 // or don't require any work at all.
957 break;
958
Chris Forbese57f10e2019-03-04 10:53:07 -0800959 case spv::OpLabel:
960 case spv::OpReturn:
961 // TODO: when we do control flow, will need to do some work here.
962 // Until then, there is nothing to do -- we expect there to be an initial OpLabel
963 // in the entrypoint function, for which we do nothing; and a final OpReturn at the
964 // end of the entrypoint function, for which we do nothing.
965 break;
966
Chris Forbes0eba65b2019-02-13 12:24:35 -0800967 case spv::OpVariable:
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000968 EmitVariable(insn, routine);
Chris Forbes0eba65b2019-02-13 12:24:35 -0800969 break;
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000970
Chris Forbese9f8f5b2019-02-11 00:20:16 +0000971 case spv::OpLoad:
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000972 EmitLoad(insn, routine);
Chris Forbese9f8f5b2019-02-11 00:20:16 +0000973 break;
Chris Forbes38f85b32019-02-12 20:10:05 +0000974
Chris Forbes1c588002019-02-12 18:56:38 +0000975 case spv::OpStore:
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000976 EmitStore(insn, routine);
Chris Forbes1c588002019-02-12 18:56:38 +0000977 break;
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000978
979 case spv::OpAccessChain:
980 EmitAccessChain(insn, routine);
981 break;
982
Chris Forbesb97a9572019-02-21 16:51:42 -0800983 case spv::OpCompositeConstruct:
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000984 EmitCompositeConstruct(insn, routine);
Chris Forbesb97a9572019-02-21 16:51:42 -0800985 break;
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000986
Chris Forbes1bc1acf2019-02-21 18:40:33 -0800987 case spv::OpCompositeInsert:
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000988 EmitCompositeInsert(insn, routine);
Chris Forbes1bc1acf2019-02-21 18:40:33 -0800989 break;
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000990
Chris Forbesb12846d2019-02-21 18:53:58 -0800991 case spv::OpCompositeExtract:
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000992 EmitCompositeExtract(insn, routine);
Chris Forbesb12846d2019-02-21 18:53:58 -0800993 break;
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000994
Chris Forbes83fc5442019-02-26 22:16:07 -0800995 case spv::OpVectorShuffle:
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000996 EmitVectorShuffle(insn, routine);
Chris Forbes83fc5442019-02-26 22:16:07 -0800997 break;
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000998
Ben Claytondd1e37e2019-02-28 19:59:15 +0000999 case spv::OpNot:
1000 case spv::OpSNegate:
1001 case spv::OpFNegate:
1002 case spv::OpLogicalNot:
Chris Forbes4d503052019-03-01 17:13:57 -08001003 case spv::OpConvertFToU:
1004 case spv::OpConvertFToS:
1005 case spv::OpConvertSToF:
1006 case spv::OpConvertUToF:
1007 case spv::OpBitcast:
Chris Forbes3ed33ce2019-03-07 13:38:31 -08001008 case spv::OpIsInf:
1009 case spv::OpIsNan:
Ben Claytondd1e37e2019-02-28 19:59:15 +00001010 EmitUnaryOp(insn, routine);
1011 break;
1012
1013 case spv::OpIAdd:
1014 case spv::OpISub:
1015 case spv::OpIMul:
1016 case spv::OpSDiv:
1017 case spv::OpUDiv:
1018 case spv::OpFAdd:
1019 case spv::OpFSub:
1020 case spv::OpFDiv:
Ben Claytonec1aeb82019-03-04 19:33:27 +00001021 case spv::OpFOrdEqual:
1022 case spv::OpFUnordEqual:
1023 case spv::OpFOrdNotEqual:
1024 case spv::OpFUnordNotEqual:
1025 case spv::OpFOrdLessThan:
1026 case spv::OpFUnordLessThan:
1027 case spv::OpFOrdGreaterThan:
1028 case spv::OpFUnordGreaterThan:
1029 case spv::OpFOrdLessThanEqual:
1030 case spv::OpFUnordLessThanEqual:
1031 case spv::OpFOrdGreaterThanEqual:
1032 case spv::OpFUnordGreaterThanEqual:
Ben Claytondd1e37e2019-02-28 19:59:15 +00001033 case spv::OpUMod:
Ben Claytone95eeb12019-03-04 16:32:09 +00001034 case spv::OpIEqual:
1035 case spv::OpINotEqual:
1036 case spv::OpUGreaterThan:
1037 case spv::OpSGreaterThan:
1038 case spv::OpUGreaterThanEqual:
1039 case spv::OpSGreaterThanEqual:
1040 case spv::OpULessThan:
1041 case spv::OpSLessThan:
1042 case spv::OpULessThanEqual:
1043 case spv::OpSLessThanEqual:
Ben Claytondd1e37e2019-02-28 19:59:15 +00001044 case spv::OpShiftRightLogical:
1045 case spv::OpShiftRightArithmetic:
1046 case spv::OpShiftLeftLogical:
1047 case spv::OpBitwiseOr:
1048 case spv::OpBitwiseXor:
1049 case spv::OpBitwiseAnd:
1050 case spv::OpLogicalOr:
1051 case spv::OpLogicalAnd:
Chris Forbese86b6dc2019-03-01 09:08:47 -08001052 case spv::OpUMulExtended:
1053 case spv::OpSMulExtended:
Ben Claytondd1e37e2019-02-28 19:59:15 +00001054 EmitBinaryOp(insn, routine);
1055 break;
1056
Chris Forbes2b287cc2019-03-01 13:24:17 -08001057 case spv::OpDot:
1058 EmitDot(insn, routine);
1059 break;
1060
Ben Claytonbf943f62019-03-05 12:57:39 +00001061 case spv::OpSelect:
1062 EmitSelect(insn, routine);
1063 break;
1064
Chris Forbes9667a5b2019-03-07 09:26:48 -08001065 case spv::OpExtInst:
1066 EmitExtendedInstruction(insn, routine);
1067 break;
1068
Chris Forbesd5aed492019-02-02 15:18:52 -08001069 default:
Chris Forbese57f10e2019-03-04 10:53:07 -08001070 UNIMPLEMENTED(OpcodeName(insn.opcode()).c_str());
Chris Forbesd5aed492019-02-02 15:18:52 -08001071 break;
1072 }
1073 }
1074 }
Chris Forbesc61271e2019-02-19 17:01:28 -08001075
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001076 void SpirvShader::EmitVariable(InsnIterator insn, SpirvRoutine *routine) const
1077 {
1078 ObjectID resultId = insn.word(2);
1079 auto &object = getObject(resultId);
1080 auto &objectTy = getType(object.type);
Ben Claytonefec1b92019-03-05 17:38:16 +00001081 switch (objectTy.storageClass)
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001082 {
Ben Claytonefec1b92019-03-05 17:38:16 +00001083 case spv::StorageClassInput:
1084 {
1085 if (object.kind == Object::Kind::InterfaceVariable)
1086 {
1087 auto &dst = routine->getValue(resultId);
1088 int offset = 0;
1089 VisitInterface(resultId,
1090 [&](Decorations const &d, AttribType type) {
1091 auto scalarSlot = d.Location << 2 | d.Component;
1092 dst[offset++] = routine->inputs[scalarSlot];
1093 });
1094 }
1095 break;
1096 }
1097 case spv::StorageClassUniform:
1098 case spv::StorageClassStorageBuffer:
1099 {
1100 Decorations d{};
1101 ApplyDecorationsForId(&d, resultId);
1102 ASSERT(d.DescriptorSet >= 0);
1103 ASSERT(d.Binding >= 0);
1104
1105 size_t bindingOffset = routine->pipelineLayout->getBindingOffset(d.DescriptorSet, d.Binding);
1106
1107 Pointer<Byte> set = routine->descriptorSets[d.DescriptorSet]; // DescriptorSet*
1108 Pointer<Byte> binding = Pointer<Byte>(set + bindingOffset); // VkDescriptorBufferInfo*
1109 Pointer<Byte> buffer = *Pointer<Pointer<Byte>>(binding + OFFSET(VkDescriptorBufferInfo, buffer)); // vk::Buffer*
1110 Pointer<Byte> data = *Pointer<Pointer<Byte>>(buffer + vk::Buffer::DataOffset); // void*
1111 Int offset = *Pointer<Int>(binding + OFFSET(VkDescriptorBufferInfo, offset));
1112 Pointer<Byte> address = data + offset;
1113 routine->physicalPointers[resultId] = address;
1114 break;
1115 }
1116 default:
1117 break;
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001118 }
1119 }
1120
1121 void SpirvShader::EmitLoad(InsnIterator insn, SpirvRoutine *routine) const
1122 {
1123 ObjectID objectId = insn.word(2);
1124 ObjectID pointerId = insn.word(3);
1125 auto &object = getObject(objectId);
1126 auto &objectTy = getType(object.type);
1127 auto &pointer = getObject(pointerId);
1128 auto &pointerBase = getObject(pointer.pointerBase);
1129 auto &pointerBaseTy = getType(pointerBase.type);
1130
1131 ASSERT(getType(pointer.type).element == object.type);
1132 ASSERT(TypeID(insn.word(1)) == object.type);
1133
Ben Claytonefec1b92019-03-05 17:38:16 +00001134 if (pointerBaseTy.storageClass == spv::StorageClassImage)
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001135 {
Ben Claytonefec1b92019-03-05 17:38:16 +00001136 UNIMPLEMENTED("StorageClassImage load not yet implemented");
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001137 }
1138
Ben Clayton831db962019-02-27 14:57:18 +00001139 Pointer<Float> ptrBase;
1140 if (pointerBase.kind == Object::Kind::PhysicalPointer)
1141 {
1142 ptrBase = routine->getPhysicalPointer(pointer.pointerBase);
1143 }
1144 else
1145 {
1146 ptrBase = &routine->getValue(pointer.pointerBase)[0];
1147 }
1148
1149 bool interleavedByLane = IsStorageInterleavedByLane(pointerBaseTy.storageClass);
1150
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001151 auto &dst = routine->createIntermediate(objectId, objectTy.sizeInComponents);
1152
1153 if (pointer.kind == Object::Kind::Value)
1154 {
Ben Clayton831db962019-02-27 14:57:18 +00001155 // Divergent offsets.
1156 auto offsets = As<SIMD::Int>(routine->getIntermediate(pointerId)[0]);
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001157 for (auto i = 0u; i < objectTy.sizeInComponents; i++)
1158 {
1159 // i wish i had a Float,Float,Float,Float constructor here..
1160 SIMD::Float v;
1161 for (int j = 0; j < SIMD::Width; j++)
1162 {
1163 Int offset = Int(i) + Extract(offsets, j);
Ben Clayton831db962019-02-27 14:57:18 +00001164 if (interleavedByLane) { offset = offset * SIMD::Width + j; }
1165 v = Insert(v, ptrBase[offset], j);
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001166 }
1167 dst.emplace(i, v);
1168 }
1169 }
Ben Clayton831db962019-02-27 14:57:18 +00001170 else if (interleavedByLane)
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001171 {
Ben Clayton831db962019-02-27 14:57:18 +00001172 // Lane-interleaved data. No divergent offsets.
1173 Pointer<SIMD::Float> src = ptrBase;
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001174 for (auto i = 0u; i < objectTy.sizeInComponents; i++)
1175 {
Ben Clayton831db962019-02-27 14:57:18 +00001176 dst.emplace(i, src[i]);
1177 }
1178 }
1179 else
1180 {
1181 // Non-interleaved data. No divergent offsets.
1182 for (auto i = 0u; i < objectTy.sizeInComponents; i++)
1183 {
1184 dst.emplace(i, RValue<SIMD::Float>(ptrBase[i]));
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001185 }
1186 }
1187 }
1188
1189 void SpirvShader::EmitAccessChain(InsnIterator insn, SpirvRoutine *routine) const
1190 {
1191 TypeID typeId = insn.word(1);
1192 ObjectID objectId = insn.word(2);
1193 ObjectID baseId = insn.word(3);
1194 auto &object = getObject(objectId);
1195 auto &type = getType(typeId);
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001196 ASSERT(type.sizeInComponents == 1);
1197 ASSERT(getObject(baseId).pointerBase == object.pointerBase);
1198
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001199 auto &dst = routine->createIntermediate(objectId, type.sizeInComponents);
1200 dst.emplace(0, As<SIMD::Float>(WalkAccessChain(baseId, insn.wordCount() - 4, insn.wordPointer(4), routine)));
1201 }
1202
1203 void SpirvShader::EmitStore(InsnIterator insn, SpirvRoutine *routine) const
1204 {
1205 ObjectID pointerId = insn.word(1);
1206 ObjectID objectId = insn.word(2);
1207 auto &object = getObject(objectId);
1208 auto &pointer = getObject(pointerId);
1209 auto &pointerTy = getType(pointer.type);
1210 auto &elementTy = getType(pointerTy.element);
1211 auto &pointerBase = getObject(pointer.pointerBase);
1212 auto &pointerBaseTy = getType(pointerBase.type);
1213
Ben Claytonefec1b92019-03-05 17:38:16 +00001214 if (pointerBaseTy.storageClass == spv::StorageClassImage)
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001215 {
Ben Claytonefec1b92019-03-05 17:38:16 +00001216 UNIMPLEMENTED("StorageClassImage store not yet implemented");
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001217 }
1218
Ben Clayton831db962019-02-27 14:57:18 +00001219 Pointer<Float> ptrBase;
1220 if (pointerBase.kind == Object::Kind::PhysicalPointer)
1221 {
1222 ptrBase = routine->getPhysicalPointer(pointer.pointerBase);
1223 }
1224 else
1225 {
1226 ptrBase = &routine->getValue(pointer.pointerBase)[0];
1227 }
1228
1229 bool interleavedByLane = IsStorageInterleavedByLane(pointerBaseTy.storageClass);
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001230
1231 if (object.kind == Object::Kind::Constant)
1232 {
1233 auto src = reinterpret_cast<float *>(object.constantValue.get());
1234
1235 if (pointer.kind == Object::Kind::Value)
1236 {
Ben Clayton831db962019-02-27 14:57:18 +00001237 // Constant source data. Divergent offsets.
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001238 auto offsets = As<SIMD::Int>(routine->getIntermediate(pointerId)[0]);
1239 for (auto i = 0u; i < elementTy.sizeInComponents; i++)
1240 {
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001241 for (int j = 0; j < SIMD::Width; j++)
1242 {
Ben Clayton831db962019-02-27 14:57:18 +00001243 Int offset = Int(i) + Extract(offsets, j);
1244 if (interleavedByLane) { offset = offset * SIMD::Width + j; }
1245 ptrBase[offset] = RValue<Float>(src[i]);
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001246 }
1247 }
1248 }
1249 else
1250 {
Ben Clayton831db962019-02-27 14:57:18 +00001251 // Constant source data. No divergent offsets.
1252 Pointer<SIMD::Float> dst = ptrBase;
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001253 for (auto i = 0u; i < elementTy.sizeInComponents; i++)
1254 {
Ben Clayton831db962019-02-27 14:57:18 +00001255 dst[i] = RValue<SIMD::Float>(src[i]);
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001256 }
1257 }
1258 }
1259 else
1260 {
1261 auto &src = routine->getIntermediate(objectId);
1262
1263 if (pointer.kind == Object::Kind::Value)
1264 {
Ben Clayton831db962019-02-27 14:57:18 +00001265 // Intermediate source data. Divergent offsets.
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001266 auto offsets = As<SIMD::Int>(routine->getIntermediate(pointerId)[0]);
1267 for (auto i = 0u; i < elementTy.sizeInComponents; i++)
1268 {
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001269 for (int j = 0; j < SIMD::Width; j++)
1270 {
Ben Clayton831db962019-02-27 14:57:18 +00001271 Int offset = Int(i) + Extract(offsets, j);
1272 if (interleavedByLane) { offset = offset * SIMD::Width + j; }
1273 ptrBase[offset] = Extract(src[i], j);
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001274 }
1275 }
1276 }
Ben Clayton831db962019-02-27 14:57:18 +00001277 else if (interleavedByLane)
1278 {
1279 // Intermediate source data. Lane-interleaved data. No divergent offsets.
1280 Pointer<SIMD::Float> dst = ptrBase;
1281 for (auto i = 0u; i < elementTy.sizeInComponents; i++)
1282 {
1283 dst[i] = src[i];
1284 }
1285 }
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001286 else
1287 {
Ben Clayton831db962019-02-27 14:57:18 +00001288 // Intermediate source data. Non-interleaved data. No divergent offsets.
1289 Pointer<SIMD::Float> dst = ptrBase;
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001290 for (auto i = 0u; i < elementTy.sizeInComponents; i++)
1291 {
Ben Clayton831db962019-02-27 14:57:18 +00001292 dst[i] = SIMD::Float(src[i]);
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001293 }
1294 }
1295 }
1296 }
1297
1298 void SpirvShader::EmitCompositeConstruct(InsnIterator insn, SpirvRoutine *routine) const
1299 {
1300 auto &type = getType(insn.word(1));
1301 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
1302 auto offset = 0u;
1303
1304 for (auto i = 0u; i < insn.wordCount() - 3; i++)
1305 {
1306 ObjectID srcObjectId = insn.word(3u + i);
1307 auto & srcObject = getObject(srcObjectId);
1308 auto & srcObjectTy = getType(srcObject.type);
1309 GenericValue srcObjectAccess(this, routine, srcObjectId);
1310
1311 for (auto j = 0u; j < srcObjectTy.sizeInComponents; j++)
1312 dst.emplace(offset++, srcObjectAccess[j]);
1313 }
1314 }
1315
1316 void SpirvShader::EmitCompositeInsert(InsnIterator insn, SpirvRoutine *routine) const
1317 {
1318 TypeID resultTypeId = insn.word(1);
1319 auto &type = getType(resultTypeId);
1320 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
1321 auto &newPartObject = getObject(insn.word(3));
1322 auto &newPartObjectTy = getType(newPartObject.type);
1323 auto firstNewComponent = WalkLiteralAccessChain(resultTypeId, insn.wordCount() - 5, insn.wordPointer(5));
1324
1325 GenericValue srcObjectAccess(this, routine, insn.word(4));
1326 GenericValue newPartObjectAccess(this, routine, insn.word(3));
1327
1328 // old components before
1329 for (auto i = 0u; i < firstNewComponent; i++)
1330 {
1331 dst.emplace(i, srcObjectAccess[i]);
1332 }
1333 // new part
1334 for (auto i = 0u; i < newPartObjectTy.sizeInComponents; i++)
1335 {
1336 dst.emplace(firstNewComponent + i, newPartObjectAccess[i]);
1337 }
1338 // old components after
1339 for (auto i = firstNewComponent + newPartObjectTy.sizeInComponents; i < type.sizeInComponents; i++)
1340 {
1341 dst.emplace(i, srcObjectAccess[i]);
1342 }
1343 }
1344
1345 void SpirvShader::EmitCompositeExtract(InsnIterator insn, SpirvRoutine *routine) const
1346 {
1347 auto &type = getType(insn.word(1));
1348 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
1349 auto &compositeObject = getObject(insn.word(3));
1350 TypeID compositeTypeId = compositeObject.definition.word(1);
1351 auto firstComponent = WalkLiteralAccessChain(compositeTypeId, insn.wordCount() - 4, insn.wordPointer(4));
1352
1353 GenericValue compositeObjectAccess(this, routine, insn.word(3));
1354 for (auto i = 0u; i < type.sizeInComponents; i++)
1355 {
1356 dst.emplace(i, compositeObjectAccess[firstComponent + i]);
1357 }
1358 }
1359
1360 void SpirvShader::EmitVectorShuffle(InsnIterator insn, SpirvRoutine *routine) const
1361 {
1362 auto &type = getType(insn.word(1));
1363 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
1364
1365 GenericValue firstHalfAccess(this, routine, insn.word(3));
1366 GenericValue secondHalfAccess(this, routine, insn.word(4));
1367
1368 for (auto i = 0u; i < type.sizeInComponents; i++)
1369 {
1370 auto selector = insn.word(5 + i);
1371 if (selector == static_cast<uint32_t>(-1))
1372 {
1373 // Undefined value. Until we decide to do real undef values, zero is as good
1374 // a value as any
1375 dst.emplace(i, RValue<SIMD::Float>(0.0f));
1376 }
1377 else if (selector < type.sizeInComponents)
1378 {
1379 dst.emplace(i, firstHalfAccess[selector]);
1380 }
1381 else
1382 {
1383 dst.emplace(i, secondHalfAccess[selector - type.sizeInComponents]);
1384 }
1385 }
1386 }
1387
Ben Claytondd1e37e2019-02-28 19:59:15 +00001388 void SpirvShader::EmitUnaryOp(InsnIterator insn, SpirvRoutine *routine) const
1389 {
1390 auto &type = getType(insn.word(1));
1391 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
1392 auto src = GenericValue(this, routine, insn.word(3));
1393
1394 for (auto i = 0u; i < type.sizeInComponents; i++)
1395 {
1396 auto val = src[i];
1397
1398 switch (insn.opcode())
1399 {
1400 case spv::OpNot:
1401 case spv::OpLogicalNot: // logical not == bitwise not due to all-bits boolean representation
1402 dst.emplace(i, As<SIMD::Float>(~As<SIMD::UInt>(val)));
1403 break;
1404 case spv::OpSNegate:
1405 dst.emplace(i, As<SIMD::Float>(-As<SIMD::Int>(val)));
1406 break;
1407 case spv::OpFNegate:
1408 dst.emplace(i, -val);
1409 break;
Chris Forbes4d503052019-03-01 17:13:57 -08001410 case spv::OpConvertFToU:
1411 dst.emplace(i, As<SIMD::Float>(SIMD::UInt(val)));
1412 break;
1413 case spv::OpConvertFToS:
1414 dst.emplace(i, As<SIMD::Float>(SIMD::Int(val)));
1415 break;
1416 case spv::OpConvertSToF:
1417 dst.emplace(i, SIMD::Float(As<SIMD::Int>(val)));
1418 break;
1419 case spv::OpConvertUToF:
1420 dst.emplace(i, SIMD::Float(As<SIMD::UInt>(val)));
1421 break;
1422 case spv::OpBitcast:
1423 dst.emplace(i, val);
1424 break;
Chris Forbes3ed33ce2019-03-07 13:38:31 -08001425 case spv::OpIsInf:
1426 dst.emplace(i, As<SIMD::Float>(IsInf(val)));
1427 break;
1428 case spv::OpIsNan:
1429 dst.emplace(i, As<SIMD::Float>(IsNan(val)));
1430 break;
Ben Claytondd1e37e2019-02-28 19:59:15 +00001431 default:
1432 UNIMPLEMENTED("Unhandled unary operator %s", OpcodeName(insn.opcode()).c_str());
1433 }
1434 }
1435 }
1436
1437 void SpirvShader::EmitBinaryOp(InsnIterator insn, SpirvRoutine *routine) const
1438 {
1439 auto &type = getType(insn.word(1));
1440 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
Chris Forbese86b6dc2019-03-01 09:08:47 -08001441 auto &lhsType = getType(getObject(insn.word(3)).type);
Ben Claytondd1e37e2019-02-28 19:59:15 +00001442 auto srcLHS = GenericValue(this, routine, insn.word(3));
1443 auto srcRHS = GenericValue(this, routine, insn.word(4));
1444
Chris Forbese86b6dc2019-03-01 09:08:47 -08001445 for (auto i = 0u; i < lhsType.sizeInComponents; i++)
Ben Claytondd1e37e2019-02-28 19:59:15 +00001446 {
1447 auto lhs = srcLHS[i];
1448 auto rhs = srcRHS[i];
1449
1450 switch (insn.opcode())
1451 {
1452 case spv::OpIAdd:
1453 dst.emplace(i, As<SIMD::Float>(As<SIMD::Int>(lhs) + As<SIMD::Int>(rhs)));
1454 break;
1455 case spv::OpISub:
1456 dst.emplace(i, As<SIMD::Float>(As<SIMD::Int>(lhs) - As<SIMD::Int>(rhs)));
1457 break;
1458 case spv::OpIMul:
1459 dst.emplace(i, As<SIMD::Float>(As<SIMD::Int>(lhs) * As<SIMD::Int>(rhs)));
1460 break;
1461 case spv::OpSDiv:
1462 dst.emplace(i, As<SIMD::Float>(As<SIMD::Int>(lhs) / As<SIMD::Int>(rhs)));
1463 break;
1464 case spv::OpUDiv:
1465 dst.emplace(i, As<SIMD::Float>(As<SIMD::UInt>(lhs) / As<SIMD::UInt>(rhs)));
1466 break;
1467 case spv::OpUMod:
1468 dst.emplace(i, As<SIMD::Float>(As<SIMD::UInt>(lhs) % As<SIMD::UInt>(rhs)));
1469 break;
Ben Claytone95eeb12019-03-04 16:32:09 +00001470 case spv::OpIEqual:
1471 dst.emplace(i, As<SIMD::Float>(CmpEQ(As<SIMD::Int>(lhs), As<SIMD::Int>(rhs))));
1472 break;
1473 case spv::OpINotEqual:
1474 dst.emplace(i, As<SIMD::Float>(CmpNEQ(As<SIMD::Int>(lhs), As<SIMD::Int>(rhs))));
1475 break;
1476 case spv::OpUGreaterThan:
1477 dst.emplace(i, As<SIMD::Float>(CmpGT(As<SIMD::UInt>(lhs), As<SIMD::UInt>(rhs))));
1478 break;
1479 case spv::OpSGreaterThan:
1480 dst.emplace(i, As<SIMD::Float>(CmpGT(As<SIMD::Int>(lhs), As<SIMD::Int>(rhs))));
1481 break;
1482 case spv::OpUGreaterThanEqual:
1483 dst.emplace(i, As<SIMD::Float>(CmpGE(As<SIMD::UInt>(lhs), As<SIMD::UInt>(rhs))));
1484 break;
1485 case spv::OpSGreaterThanEqual:
1486 dst.emplace(i, As<SIMD::Float>(CmpGE(As<SIMD::Int>(lhs), As<SIMD::Int>(rhs))));
1487 break;
1488 case spv::OpULessThan:
1489 dst.emplace(i, As<SIMD::Float>(CmpLT(As<SIMD::UInt>(lhs), As<SIMD::UInt>(rhs))));
1490 break;
1491 case spv::OpSLessThan:
1492 dst.emplace(i, As<SIMD::Float>(CmpLT(As<SIMD::Int>(lhs), As<SIMD::Int>(rhs))));
1493 break;
1494 case spv::OpULessThanEqual:
1495 dst.emplace(i, As<SIMD::Float>(CmpLE(As<SIMD::UInt>(lhs), As<SIMD::UInt>(rhs))));
1496 break;
1497 case spv::OpSLessThanEqual:
1498 dst.emplace(i, As<SIMD::Float>(CmpLE(As<SIMD::Int>(lhs), As<SIMD::Int>(rhs))));
1499 break;
Ben Claytondd1e37e2019-02-28 19:59:15 +00001500 case spv::OpFAdd:
1501 dst.emplace(i, lhs + rhs);
1502 break;
1503 case spv::OpFSub:
1504 dst.emplace(i, lhs - rhs);
1505 break;
1506 case spv::OpFDiv:
1507 dst.emplace(i, lhs / rhs);
1508 break;
Ben Claytonec1aeb82019-03-04 19:33:27 +00001509 case spv::OpFOrdEqual:
1510 dst.emplace(i, As<SIMD::Float>(CmpEQ(lhs, rhs)));
1511 break;
1512 case spv::OpFUnordEqual:
1513 dst.emplace(i, As<SIMD::Float>(CmpUEQ(lhs, rhs)));
1514 break;
1515 case spv::OpFOrdNotEqual:
1516 dst.emplace(i, As<SIMD::Float>(CmpNEQ(lhs, rhs)));
1517 break;
1518 case spv::OpFUnordNotEqual:
1519 dst.emplace(i, As<SIMD::Float>(CmpUNEQ(lhs, rhs)));
1520 break;
1521 case spv::OpFOrdLessThan:
1522 dst.emplace(i, As<SIMD::Float>(CmpLT(lhs, rhs)));
1523 break;
1524 case spv::OpFUnordLessThan:
1525 dst.emplace(i, As<SIMD::Float>(CmpULT(lhs, rhs)));
1526 break;
1527 case spv::OpFOrdGreaterThan:
1528 dst.emplace(i, As<SIMD::Float>(CmpGT(lhs, rhs)));
1529 break;
1530 case spv::OpFUnordGreaterThan:
1531 dst.emplace(i, As<SIMD::Float>(CmpUGT(lhs, rhs)));
1532 break;
1533 case spv::OpFOrdLessThanEqual:
1534 dst.emplace(i, As<SIMD::Float>(CmpLE(lhs, rhs)));
1535 break;
1536 case spv::OpFUnordLessThanEqual:
1537 dst.emplace(i, As<SIMD::Float>(CmpULE(lhs, rhs)));
1538 break;
1539 case spv::OpFOrdGreaterThanEqual:
1540 dst.emplace(i, As<SIMD::Float>(CmpGE(lhs, rhs)));
1541 break;
1542 case spv::OpFUnordGreaterThanEqual:
1543 dst.emplace(i, As<SIMD::Float>(CmpUGE(lhs, rhs)));
1544 break;
Ben Claytondd1e37e2019-02-28 19:59:15 +00001545 case spv::OpShiftRightLogical:
1546 dst.emplace(i, As<SIMD::Float>(As<SIMD::UInt>(lhs) >> As<SIMD::UInt>(rhs)));
1547 break;
1548 case spv::OpShiftRightArithmetic:
1549 dst.emplace(i, As<SIMD::Float>(As<SIMD::Int>(lhs) >> As<SIMD::Int>(rhs)));
1550 break;
1551 case spv::OpShiftLeftLogical:
1552 dst.emplace(i, As<SIMD::Float>(As<SIMD::UInt>(lhs) << As<SIMD::UInt>(rhs)));
1553 break;
1554 case spv::OpBitwiseOr:
1555 case spv::OpLogicalOr:
1556 dst.emplace(i, As<SIMD::Float>(As<SIMD::UInt>(lhs) | As<SIMD::UInt>(rhs)));
1557 break;
1558 case spv::OpBitwiseXor:
1559 dst.emplace(i, As<SIMD::Float>(As<SIMD::UInt>(lhs) ^ As<SIMD::UInt>(rhs)));
1560 break;
1561 case spv::OpBitwiseAnd:
1562 case spv::OpLogicalAnd:
1563 dst.emplace(i, As<SIMD::Float>(As<SIMD::UInt>(lhs) & As<SIMD::UInt>(rhs)));
1564 break;
Chris Forbese86b6dc2019-03-01 09:08:47 -08001565 case spv::OpSMulExtended:
1566 // Extended ops: result is a structure containing two members of the same type as lhs & rhs.
1567 // In our flat view then, component i is the i'th component of the first member;
1568 // component i + N is the i'th component of the second member.
1569 dst.emplace(i, As<SIMD::Float>(As<SIMD::Int>(lhs) * As<SIMD::Int>(rhs)));
1570 dst.emplace(i + lhsType.sizeInComponents, As<SIMD::Float>(MulHigh(As<SIMD::Int>(lhs), As<SIMD::Int>(rhs))));
1571 break;
1572 case spv::OpUMulExtended:
1573 dst.emplace(i, As<SIMD::Float>(As<SIMD::UInt>(lhs) * As<SIMD::UInt>(rhs)));
1574 dst.emplace(i + lhsType.sizeInComponents, As<SIMD::Float>(MulHigh(As<SIMD::UInt>(lhs), As<SIMD::UInt>(rhs))));
1575 break;
Ben Claytondd1e37e2019-02-28 19:59:15 +00001576 default:
1577 UNIMPLEMENTED("Unhandled binary operator %s", OpcodeName(insn.opcode()).c_str());
1578 }
1579 }
1580 }
1581
Chris Forbes2b287cc2019-03-01 13:24:17 -08001582 void SpirvShader::EmitDot(InsnIterator insn, SpirvRoutine *routine) const
1583 {
1584 auto &type = getType(insn.word(1));
1585 assert(type.sizeInComponents == 1);
1586 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
1587 auto &lhsType = getType(getObject(insn.word(3)).type);
1588 auto srcLHS = GenericValue(this, routine, insn.word(3));
1589 auto srcRHS = GenericValue(this, routine, insn.word(4));
1590
1591 SIMD::Float result = srcLHS[0] * srcRHS[0];
1592
1593 for (auto i = 1u; i < lhsType.sizeInComponents; i++)
1594 {
1595 result += srcLHS[i] * srcRHS[i];
1596 }
1597
1598 dst.emplace(0, result);
1599 }
1600
Ben Claytonbf943f62019-03-05 12:57:39 +00001601 void SpirvShader::EmitSelect(InsnIterator insn, SpirvRoutine *routine) const
1602 {
1603 auto &type = getType(insn.word(1));
1604 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
1605 auto srcCond = GenericValue(this, routine, insn.word(3));
1606 auto srcLHS = GenericValue(this, routine, insn.word(4));
1607 auto srcRHS = GenericValue(this, routine, insn.word(5));
1608
1609 for (auto i = 0u; i < type.sizeInComponents; i++)
1610 {
1611 auto cond = As<SIMD::Int>(srcCond[i]);
1612 auto lhs = srcLHS[i];
1613 auto rhs = srcRHS[i];
1614 auto out = (cond & As<Int4>(lhs)) | (~cond & As<Int4>(rhs)); // FIXME: IfThenElse()
1615 dst.emplace(i, As<SIMD::Float>(out));
1616 }
1617 }
1618
Chris Forbes9667a5b2019-03-07 09:26:48 -08001619 void SpirvShader::EmitExtendedInstruction(InsnIterator insn, SpirvRoutine *routine) const
1620 {
1621 auto &type = getType(insn.word(1));
1622 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
1623 auto extInstIndex = static_cast<GLSLstd450>(insn.word(4));
1624
1625 switch (extInstIndex)
1626 {
1627 case GLSLstd450FAbs:
1628 {
1629 auto src = GenericValue(this, routine, insn.word(5));
1630 for (auto i = 0u; i < type.sizeInComponents; i++)
1631 {
1632 dst.emplace(i, Abs(src[i]));
1633 }
1634 break;
1635 }
1636 case GLSLstd450SAbs:
1637 {
1638 auto src = GenericValue(this, routine, insn.word(5));
1639 for (auto i = 0u; i < type.sizeInComponents; i++)
1640 {
1641 dst.emplace(i, As<SIMD::Float>(Abs(As<SIMD::Int>(src[i]))));
1642 }
1643 break;
1644 }
1645 default:
1646 UNIMPLEMENTED("Unhandled ExtInst %d", extInstIndex);
1647 }
1648 }
1649
Chris Forbesc61271e2019-02-19 17:01:28 -08001650 void SpirvShader::emitEpilog(SpirvRoutine *routine) const
1651 {
1652 for (auto insn : *this)
1653 {
1654 switch (insn.opcode())
1655 {
1656 case spv::OpVariable:
1657 {
Ben Claytonab51bbf2019-02-20 14:36:27 +00001658 ObjectID resultId = insn.word(2);
Chris Forbesc61271e2019-02-19 17:01:28 -08001659 auto &object = getObject(resultId);
Ben Clayton9a162482019-02-25 11:54:43 +00001660 auto &objectTy = getType(object.type);
1661 if (object.kind == Object::Kind::InterfaceVariable && objectTy.storageClass == spv::StorageClassOutput)
Chris Forbesc61271e2019-02-19 17:01:28 -08001662 {
1663 auto &dst = routine->getValue(resultId);
1664 int offset = 0;
1665 VisitInterface(resultId,
1666 [&](Decorations const &d, AttribType type) {
1667 auto scalarSlot = d.Location << 2 | d.Component;
1668 routine->outputs[scalarSlot] = dst[offset++];
1669 });
1670 }
1671 break;
1672 }
1673 default:
1674 break;
1675 }
1676 }
1677 }
Ben Clayton76e9bc02019-02-26 15:02:18 +00001678
1679 SpirvRoutine::SpirvRoutine(vk::PipelineLayout const *pipelineLayout) :
1680 pipelineLayout(pipelineLayout)
1681 {
1682 }
1683
Chris Forbesc25b8072018-12-10 15:10:39 -08001684}