blob: f63c9fe1d2b46735a14ba16992c499c5741da102 [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:
Chris Forbesf3a430d2019-03-08 07:51:39 -0800249 case spv::OpLine:
250 case spv::OpNoLine:
251 case spv::OpModuleProcessed:
252 case spv::OpString:
Chris Forbes1776af72019-02-22 17:39:57 -0800253 // No semantic impact
Chris Forbes7edf5342019-02-10 22:41:21 +0000254 break;
255
256 case spv::OpFunctionParameter:
257 case spv::OpFunctionCall:
258 case spv::OpSpecConstant:
259 case spv::OpSpecConstantComposite:
260 case spv::OpSpecConstantFalse:
261 case spv::OpSpecConstantOp:
262 case spv::OpSpecConstantTrue:
263 // These should have all been removed by preprocessing passes. If we see them here,
264 // our assumptions are wrong and we will probably generate wrong code.
265 UNIMPLEMENTED("These instructions should have already been lowered.");
266 break;
267
Chris Forbes4d503052019-03-01 17:13:57 -0800268 case spv::OpFConvert:
269 case spv::OpSConvert:
270 case spv::OpUConvert:
271 UNIMPLEMENTED("No valid uses for Op*Convert until we support multiple bit widths");
272 break;
273
Chris Forbesa71b8e92019-02-10 22:42:42 +0000274 case spv::OpLoad:
275 case spv::OpAccessChain:
Chris Forbesb97a9572019-02-21 16:51:42 -0800276 case spv::OpCompositeConstruct:
Chris Forbes1bc1acf2019-02-21 18:40:33 -0800277 case spv::OpCompositeInsert:
Chris Forbesb12846d2019-02-21 18:53:58 -0800278 case spv::OpCompositeExtract:
Chris Forbes83fc5442019-02-26 22:16:07 -0800279 case spv::OpVectorShuffle:
Ben Claytondd1e37e2019-02-28 19:59:15 +0000280 case spv::OpNot: // Unary ops
281 case spv::OpSNegate:
282 case spv::OpFNegate:
283 case spv::OpLogicalNot:
284 case spv::OpIAdd: // Binary ops
285 case spv::OpISub:
286 case spv::OpIMul:
287 case spv::OpSDiv:
288 case spv::OpUDiv:
289 case spv::OpFAdd:
290 case spv::OpFSub:
Chris Forbes9d931532019-03-08 09:53:03 -0800291 case spv::OpFMul:
Ben Claytondd1e37e2019-02-28 19:59:15 +0000292 case spv::OpFDiv:
Ben Claytonec1aeb82019-03-04 19:33:27 +0000293 case spv::OpFOrdEqual:
294 case spv::OpFUnordEqual:
295 case spv::OpFOrdNotEqual:
296 case spv::OpFUnordNotEqual:
297 case spv::OpFOrdLessThan:
298 case spv::OpFUnordLessThan:
299 case spv::OpFOrdGreaterThan:
300 case spv::OpFUnordGreaterThan:
301 case spv::OpFOrdLessThanEqual:
302 case spv::OpFUnordLessThanEqual:
303 case spv::OpFOrdGreaterThanEqual:
304 case spv::OpFUnordGreaterThanEqual:
Ben Claytondd1e37e2019-02-28 19:59:15 +0000305 case spv::OpUMod:
Ben Claytone95eeb12019-03-04 16:32:09 +0000306 case spv::OpIEqual:
307 case spv::OpINotEqual:
308 case spv::OpUGreaterThan:
309 case spv::OpSGreaterThan:
310 case spv::OpUGreaterThanEqual:
311 case spv::OpSGreaterThanEqual:
312 case spv::OpULessThan:
313 case spv::OpSLessThan:
314 case spv::OpULessThanEqual:
315 case spv::OpSLessThanEqual:
Ben Claytondd1e37e2019-02-28 19:59:15 +0000316 case spv::OpShiftRightLogical:
317 case spv::OpShiftRightArithmetic:
318 case spv::OpShiftLeftLogical:
319 case spv::OpBitwiseOr:
320 case spv::OpBitwiseXor:
321 case spv::OpBitwiseAnd:
322 case spv::OpLogicalOr:
323 case spv::OpLogicalAnd:
Chris Forbese86b6dc2019-03-01 09:08:47 -0800324 case spv::OpUMulExtended:
325 case spv::OpSMulExtended:
Chris Forbes2b287cc2019-03-01 13:24:17 -0800326 case spv::OpDot:
Chris Forbes4d503052019-03-01 17:13:57 -0800327 case spv::OpConvertFToU:
328 case spv::OpConvertFToS:
329 case spv::OpConvertSToF:
330 case spv::OpConvertUToF:
331 case spv::OpBitcast:
Ben Claytonbf943f62019-03-05 12:57:39 +0000332 case spv::OpSelect:
Chris Forbes9667a5b2019-03-07 09:26:48 -0800333 case spv::OpExtInst:
Chris Forbes3ed33ce2019-03-07 13:38:31 -0800334 case spv::OpIsInf:
335 case spv::OpIsNan:
Chris Forbes0785f692019-03-08 09:09:18 -0800336 case spv::OpAny:
337 case spv::OpAll:
Chris Forbese86b6dc2019-03-01 09:08:47 -0800338 // Instructions that yield an intermediate value
Chris Forbesa71b8e92019-02-10 22:42:42 +0000339 {
Ben Claytonab51bbf2019-02-20 14:36:27 +0000340 TypeID typeId = insn.word(1);
341 ObjectID resultId = insn.word(2);
Chris Forbesa71b8e92019-02-10 22:42:42 +0000342 auto &object = defs[resultId];
Ben Clayton9a162482019-02-25 11:54:43 +0000343 object.type = typeId;
Chris Forbesa71b8e92019-02-10 22:42:42 +0000344 object.kind = Object::Kind::Value;
345 object.definition = insn;
Chris Forbesa71b8e92019-02-10 22:42:42 +0000346
347 if (insn.opcode() == spv::OpAccessChain)
348 {
349 // interior ptr has two parts:
350 // - logical base ptr, common across all lanes and known at compile time
351 // - per-lane offset
Ben Clayton9a162482019-02-25 11:54:43 +0000352 ObjectID baseId = insn.word(3);
353 object.pointerBase = getObject(baseId).pointerBase;
Chris Forbesa71b8e92019-02-10 22:42:42 +0000354 }
355 break;
356 }
357
Chris Forbes7edf5342019-02-10 22:41:21 +0000358 case spv::OpStore:
Chris Forbes7edf5342019-02-10 22:41:21 +0000359 // Don't need to do anything during analysis pass
360 break;
361
362 case spv::OpKill:
363 modes.ContainsKill = true;
Chris Forbesbde34082018-12-28 12:03:10 -0800364 break;
365
Chris Forbes4a979dc2019-01-17 09:36:46 -0800366 default:
Chris Forbese57f10e2019-03-04 10:53:07 -0800367 UNIMPLEMENTED(OpcodeName(insn.opcode()).c_str());
Chris Forbesaf4ed532018-12-06 18:33:27 -0800368 }
369 }
370 }
371
Ben Clayton0bb83b82019-02-26 11:41:07 +0000372 void SpirvShader::DeclareType(InsnIterator insn)
373 {
374 TypeID resultId = insn.word(1);
375
376 auto &type = types[resultId];
377 type.definition = insn;
378 type.sizeInComponents = ComputeTypeSize(insn);
379
380 // A structure is a builtin block if it has a builtin
381 // member. All members of such a structure are builtins.
382 switch (insn.opcode())
383 {
384 case spv::OpTypeStruct:
385 {
386 auto d = memberDecorations.find(resultId);
387 if (d != memberDecorations.end())
388 {
389 for (auto &m : d->second)
390 {
391 if (m.HasBuiltIn)
392 {
393 type.isBuiltInBlock = true;
394 break;
395 }
396 }
397 }
398 break;
399 }
400 case spv::OpTypePointer:
401 {
402 TypeID elementTypeId = insn.word(3);
403 type.element = elementTypeId;
404 type.isBuiltInBlock = getType(elementTypeId).isBuiltInBlock;
405 type.storageClass = static_cast<spv::StorageClass>(insn.word(2));
406 break;
407 }
408 case spv::OpTypeVector:
409 case spv::OpTypeMatrix:
410 case spv::OpTypeArray:
411 case spv::OpTypeRuntimeArray:
412 {
413 TypeID elementTypeId = insn.word(2);
414 type.element = elementTypeId;
415 break;
416 }
417 default:
418 break;
419 }
420 }
421
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800422 SpirvShader::Object& SpirvShader::CreateConstant(InsnIterator insn)
423 {
Ben Claytonab51bbf2019-02-20 14:36:27 +0000424 TypeID typeId = insn.word(1);
425 ObjectID resultId = insn.word(2);
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800426 auto &object = defs[resultId];
Ben Clayton9a162482019-02-25 11:54:43 +0000427 auto &objectTy = getType(typeId);
428 object.type = typeId;
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800429 object.kind = Object::Kind::Constant;
430 object.definition = insn;
Ben Clayton9a162482019-02-25 11:54:43 +0000431 object.constantValue = std::unique_ptr<uint32_t[]>(new uint32_t[objectTy.sizeInComponents]);
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800432 return object;
433 }
434
Chris Forbes049ff382019-02-02 15:16:43 -0800435 void SpirvShader::ProcessInterfaceVariable(Object &object)
Chris Forbesbde34082018-12-28 12:03:10 -0800436 {
Ben Clayton9a162482019-02-25 11:54:43 +0000437 auto &objectTy = getType(object.type);
Ben Clayton6fae32c2019-02-28 20:06:42 +0000438 ASSERT(objectTy.storageClass == spv::StorageClassInput || objectTy.storageClass == spv::StorageClassOutput);
Chris Forbesbde34082018-12-28 12:03:10 -0800439
Ben Clayton6fae32c2019-02-28 20:06:42 +0000440 ASSERT(objectTy.definition.opcode() == spv::OpTypePointer);
Ben Clayton9a162482019-02-25 11:54:43 +0000441 auto pointeeTy = getType(objectTy.element);
Chris Forbesbde34082018-12-28 12:03:10 -0800442
Ben Clayton9a162482019-02-25 11:54:43 +0000443 auto &builtinInterface = (objectTy.storageClass == spv::StorageClassInput) ? inputBuiltins : outputBuiltins;
444 auto &userDefinedInterface = (objectTy.storageClass == spv::StorageClassInput) ? inputs : outputs;
445
Ben Clayton6fae32c2019-02-28 20:06:42 +0000446 ASSERT(object.definition.opcode() == spv::OpVariable);
Ben Claytonab51bbf2019-02-20 14:36:27 +0000447 ObjectID resultId = object.definition.word(2);
Ben Clayton9a162482019-02-25 11:54:43 +0000448
449 if (objectTy.isBuiltInBlock)
Chris Forbesbde34082018-12-28 12:03:10 -0800450 {
451 // walk the builtin block, registering each of its members separately.
Ben Clayton9a162482019-02-25 11:54:43 +0000452 auto m = memberDecorations.find(objectTy.element);
Ben Clayton6fae32c2019-02-28 20:06:42 +0000453 ASSERT(m != memberDecorations.end()); // otherwise we wouldn't have marked the type chain
Ben Clayton9a162482019-02-25 11:54:43 +0000454 auto &structType = pointeeTy.definition;
Chris Forbesbde34082018-12-28 12:03:10 -0800455 auto offset = 0u;
456 auto word = 2u;
457 for (auto &member : m->second)
458 {
Chris Forbes840809a2019-01-14 14:30:20 -0800459 auto &memberType = getType(structType.word(word));
Chris Forbesbde34082018-12-28 12:03:10 -0800460
461 if (member.HasBuiltIn)
462 {
463 builtinInterface[member.BuiltIn] = {resultId, offset, memberType.sizeInComponents};
464 }
465
466 offset += memberType.sizeInComponents;
467 ++word;
468 }
469 return;
470 }
471
472 auto d = decorations.find(resultId);
473 if (d != decorations.end() && d->second.HasBuiltIn)
474 {
Ben Clayton9a162482019-02-25 11:54:43 +0000475 builtinInterface[d->second.BuiltIn] = {resultId, 0, pointeeTy.sizeInComponents};
Chris Forbesbde34082018-12-28 12:03:10 -0800476 }
477 else
478 {
Chris Forbes049ff382019-02-02 15:16:43 -0800479 object.kind = Object::Kind::InterfaceVariable;
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800480 VisitInterface(resultId,
481 [&userDefinedInterface](Decorations const &d, AttribType type) {
482 // Populate a single scalar slot in the interface from a collection of decorations and the intended component type.
483 auto scalarSlot = (d.Location << 2) | d.Component;
Ben Clayton6fae32c2019-02-28 20:06:42 +0000484 ASSERT(scalarSlot >= 0 &&
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800485 scalarSlot < static_cast<int32_t>(userDefinedInterface.size()));
486
487 auto &slot = userDefinedInterface[scalarSlot];
488 slot.Type = type;
489 slot.Flat = d.Flat;
490 slot.NoPerspective = d.NoPerspective;
491 slot.Centroid = d.Centroid;
492 });
Chris Forbesbde34082018-12-28 12:03:10 -0800493 }
494 }
495
Chris Forbesaf4ed532018-12-06 18:33:27 -0800496 void SpirvShader::ProcessExecutionMode(InsnIterator insn)
497 {
498 auto mode = static_cast<spv::ExecutionMode>(insn.word(2));
Chris Forbes4a979dc2019-01-17 09:36:46 -0800499 switch (mode)
500 {
501 case spv::ExecutionModeEarlyFragmentTests:
502 modes.EarlyFragmentTests = true;
503 break;
504 case spv::ExecutionModeDepthReplacing:
505 modes.DepthReplacing = true;
506 break;
507 case spv::ExecutionModeDepthGreater:
508 modes.DepthGreater = true;
509 break;
510 case spv::ExecutionModeDepthLess:
511 modes.DepthLess = true;
512 break;
513 case spv::ExecutionModeDepthUnchanged:
514 modes.DepthUnchanged = true;
515 break;
516 case spv::ExecutionModeLocalSize:
517 modes.LocalSizeX = insn.word(3);
518 modes.LocalSizeZ = insn.word(5);
519 modes.LocalSizeY = insn.word(4);
520 break;
521 case spv::ExecutionModeOriginUpperLeft:
522 // This is always the case for a Vulkan shader. Do nothing.
523 break;
524 default:
525 UNIMPLEMENTED("No other execution modes are permitted");
Chris Forbesaf4ed532018-12-06 18:33:27 -0800526 }
527 }
Chris Forbes739a7fb2018-12-08 13:09:40 -0800528
529 uint32_t SpirvShader::ComputeTypeSize(sw::SpirvShader::InsnIterator insn)
530 {
531 // Types are always built from the bottom up (with the exception of forward ptrs, which
532 // don't appear in Vulkan shaders. Therefore, we can always assume our component parts have
533 // already been described (and so their sizes determined)
534 switch (insn.opcode())
535 {
536 case spv::OpTypeVoid:
537 case spv::OpTypeSampler:
538 case spv::OpTypeImage:
539 case spv::OpTypeSampledImage:
540 case spv::OpTypeFunction:
541 case spv::OpTypeRuntimeArray:
542 // Objects that don't consume any space.
543 // Descriptor-backed objects currently only need exist at compile-time.
544 // Runtime arrays don't appear in places where their size would be interesting
545 return 0;
546
547 case spv::OpTypeBool:
548 case spv::OpTypeFloat:
549 case spv::OpTypeInt:
550 // All the fundamental types are 1 component. If we ever add support for 8/16/64-bit components,
551 // we might need to change this, but only 32 bit components are required for Vulkan 1.1.
552 return 1;
553
554 case spv::OpTypeVector:
555 case spv::OpTypeMatrix:
556 // Vectors and matrices both consume element count * element size.
Chris Forbes840809a2019-01-14 14:30:20 -0800557 return getType(insn.word(2)).sizeInComponents * insn.word(3);
Chris Forbes739a7fb2018-12-08 13:09:40 -0800558
559 case spv::OpTypeArray:
Chris Forbes5be4d702018-12-27 16:12:31 -0800560 {
561 // Element count * element size. Array sizes come from constant ids.
562 auto arraySize = GetConstantInt(insn.word(3));
Chris Forbes840809a2019-01-14 14:30:20 -0800563 return getType(insn.word(2)).sizeInComponents * arraySize;
Chris Forbes5be4d702018-12-27 16:12:31 -0800564 }
Chris Forbes739a7fb2018-12-08 13:09:40 -0800565
566 case spv::OpTypeStruct:
567 {
568 uint32_t size = 0;
569 for (uint32_t i = 2u; i < insn.wordCount(); i++)
570 {
Chris Forbes840809a2019-01-14 14:30:20 -0800571 size += getType(insn.word(i)).sizeInComponents;
Chris Forbes739a7fb2018-12-08 13:09:40 -0800572 }
573 return size;
574 }
575
576 case spv::OpTypePointer:
Chris Forbes0f59a2c2019-02-10 23:03:12 +0000577 // Runtime representation of a pointer is a per-lane index.
578 // Note: clients are expected to look through the pointer if they want the pointee size instead.
579 return 1;
Chris Forbes739a7fb2018-12-08 13:09:40 -0800580
581 default:
582 // Some other random insn.
583 UNIMPLEMENTED("Only types are supported");
Ben Clayton60a3d6f2019-02-26 17:24:46 +0000584 return 0;
Chris Forbes739a7fb2018-12-08 13:09:40 -0800585 }
586 }
Chris Forbesc25b8072018-12-10 15:10:39 -0800587
Ben Clayton831db962019-02-27 14:57:18 +0000588 bool SpirvShader::IsStorageInterleavedByLane(spv::StorageClass storageClass)
589 {
590 switch (storageClass)
591 {
592 case spv::StorageClassUniform:
593 case spv::StorageClassStorageBuffer:
594 return false;
595 default:
596 return true;
597 }
598 }
599
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800600 template<typename F>
Ben Claytonab51bbf2019-02-20 14:36:27 +0000601 int SpirvShader::VisitInterfaceInner(TypeID id, Decorations d, F f) const
Chris Forbes5839dcf2018-12-10 19:02:58 -0800602 {
603 // Recursively walks variable definition and its type tree, taking into account
604 // any explicit Location or Component decorations encountered; where explicit
605 // Locations or Components are not specified, assigns them sequentially.
606 // Collected decorations are carried down toward the leaves and across
607 // siblings; Effect of decorations intentionally does not flow back up the tree.
608 //
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800609 // F is a functor to be called with the effective decoration set for every component.
610 //
611 // Returns the next available location, and calls f().
Chris Forbes5839dcf2018-12-10 19:02:58 -0800612
613 // This covers the rules in Vulkan 1.1 spec, 14.1.4 Location Assignment.
614
Chris Forbes49d664d2019-02-12 19:24:50 +0000615 ApplyDecorationsForId(&d, id);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800616
Chris Forbes840809a2019-01-14 14:30:20 -0800617 auto const &obj = getType(id);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800618 switch (obj.definition.opcode())
619 {
Chris Forbes5839dcf2018-12-10 19:02:58 -0800620 case spv::OpTypePointer:
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800621 return VisitInterfaceInner<F>(obj.definition.word(3), d, f);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800622 case spv::OpTypeMatrix:
623 for (auto i = 0u; i < obj.definition.word(3); i++, d.Location++)
624 {
625 // consumes same components of N consecutive locations
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;
629 case spv::OpTypeVector:
630 for (auto i = 0u; i < obj.definition.word(3); i++, d.Component++)
631 {
632 // consumes N consecutive components in the same location
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800633 VisitInterfaceInner<F>(obj.definition.word(2), d, f);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800634 }
635 return d.Location + 1;
636 case spv::OpTypeFloat:
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800637 f(d, ATTRIBTYPE_FLOAT);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800638 return d.Location + 1;
639 case spv::OpTypeInt:
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800640 f(d, obj.definition.word(3) ? ATTRIBTYPE_INT : ATTRIBTYPE_UINT);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800641 return d.Location + 1;
642 case spv::OpTypeBool:
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800643 f(d, ATTRIBTYPE_UINT);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800644 return d.Location + 1;
645 case spv::OpTypeStruct:
646 {
Chris Forbes5839dcf2018-12-10 19:02:58 -0800647 // iterate over members, which may themselves have Location/Component decorations
648 for (auto i = 0u; i < obj.definition.wordCount() - 2; i++)
649 {
Chris Forbes49d664d2019-02-12 19:24:50 +0000650 ApplyDecorationsForIdMember(&d, id, i);
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800651 d.Location = VisitInterfaceInner<F>(obj.definition.word(i + 2), d, f);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800652 d.Component = 0; // Implicit locations always have component=0
653 }
654 return d.Location;
655 }
Chris Forbes5be4d702018-12-27 16:12:31 -0800656 case spv::OpTypeArray:
657 {
658 auto arraySize = GetConstantInt(obj.definition.word(3));
659 for (auto i = 0u; i < arraySize; i++)
660 {
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800661 d.Location = VisitInterfaceInner<F>(obj.definition.word(2), d, f);
Chris Forbes5be4d702018-12-27 16:12:31 -0800662 }
663 return d.Location;
664 }
Chris Forbes5839dcf2018-12-10 19:02:58 -0800665 default:
666 // Intentionally partial; most opcodes do not participate in type hierarchies
667 return 0;
668 }
669 }
670
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800671 template<typename F>
Ben Claytonab51bbf2019-02-20 14:36:27 +0000672 void SpirvShader::VisitInterface(ObjectID id, F f) const
Chris Forbes5839dcf2018-12-10 19:02:58 -0800673 {
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800674 // Walk a variable definition and call f for each component in it.
Chris Forbes5839dcf2018-12-10 19:02:58 -0800675 Decorations d{};
Chris Forbes49d664d2019-02-12 19:24:50 +0000676 ApplyDecorationsForId(&d, id);
Chris Forbes1c658232019-02-01 17:12:25 -0800677
678 auto def = getObject(id).definition;
Ben Clayton6fae32c2019-02-28 20:06:42 +0000679 ASSERT(def.opcode() == spv::OpVariable);
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800680 VisitInterfaceInner<F>(def.word(1), d, f);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800681 }
682
Ben Clayton24ea5152019-02-26 11:02:42 +0000683 SIMD::Int SpirvShader::WalkAccessChain(ObjectID id, uint32_t numIndexes, uint32_t const *indexIds, SpirvRoutine *routine) const
Chris Forbes38f85b32019-02-12 20:10:05 +0000684 {
Chris Forbes38f85b32019-02-12 20:10:05 +0000685 // TODO: think about explicit layout (UBO/SSBO) storage classes
686 // TODO: avoid doing per-lane work in some cases if we can?
687
Chris Forbes6397ed02019-02-15 16:39:17 -0800688 int constantOffset = 0;
Ben Clayton24ea5152019-02-26 11:02:42 +0000689 SIMD::Int dynamicOffset = SIMD::Int(0);
Ben Clayton9a162482019-02-25 11:54:43 +0000690 auto &baseObject = getObject(id);
691 TypeID typeId = getType(baseObject.type).element;
Chris Forbes38f85b32019-02-12 20:10:05 +0000692
Chris Forbese4ef5f72019-02-15 16:00:08 -0800693 // The <base> operand is an intermediate value itself, ie produced by a previous OpAccessChain.
694 // Start with its offset and build from there.
Chris Forbes38f85b32019-02-12 20:10:05 +0000695 if (baseObject.kind == Object::Kind::Value)
Ben Clayton24ea5152019-02-26 11:02:42 +0000696 dynamicOffset += As<SIMD::Int>(routine->getIntermediate(id)[0]);
Chris Forbes38f85b32019-02-12 20:10:05 +0000697
698 for (auto i = 0u; i < numIndexes; i++)
699 {
700 auto & type = getType(typeId);
701 switch (type.definition.opcode())
702 {
703 case spv::OpTypeStruct:
704 {
705 int memberIndex = GetConstantInt(indexIds[i]);
706 int offsetIntoStruct = 0;
707 for (auto j = 0; j < memberIndex; j++) {
Chris Forbes58bee562019-02-19 17:41:41 -0800708 auto memberType = type.definition.word(2u + j);
709 offsetIntoStruct += getType(memberType).sizeInComponents;
Chris Forbes38f85b32019-02-12 20:10:05 +0000710 }
Chris Forbes6397ed02019-02-15 16:39:17 -0800711 constantOffset += offsetIntoStruct;
Chris Forbes58bee562019-02-19 17:41:41 -0800712 typeId = type.definition.word(2u + memberIndex);
Chris Forbes38f85b32019-02-12 20:10:05 +0000713 break;
714 }
715
716 case spv::OpTypeVector:
717 case spv::OpTypeMatrix:
718 case spv::OpTypeArray:
719 {
Ben Clayton9a162482019-02-25 11:54:43 +0000720 auto stride = getType(type.element).sizeInComponents;
Chris Forbes38f85b32019-02-12 20:10:05 +0000721 auto & obj = getObject(indexIds[i]);
722 if (obj.kind == Object::Kind::Constant)
Chris Forbes6397ed02019-02-15 16:39:17 -0800723 constantOffset += stride * GetConstantInt(indexIds[i]);
Chris Forbes38f85b32019-02-12 20:10:05 +0000724 else
Ben Clayton24ea5152019-02-26 11:02:42 +0000725 dynamicOffset += SIMD::Int(stride) * As<SIMD::Int>(routine->getIntermediate(indexIds[i])[0]);
Ben Clayton9a162482019-02-25 11:54:43 +0000726 typeId = type.element;
Chris Forbes38f85b32019-02-12 20:10:05 +0000727 break;
728 }
729
730 default:
Ben Claytond4e4c662019-02-26 11:54:34 +0000731 UNIMPLEMENTED("Unexpected type '%s' in WalkAccessChain", OpcodeName(type.definition.opcode()).c_str());
Chris Forbes38f85b32019-02-12 20:10:05 +0000732 }
733 }
734
Ben Clayton24ea5152019-02-26 11:02:42 +0000735 return dynamicOffset + SIMD::Int(constantOffset);
Chris Forbes38f85b32019-02-12 20:10:05 +0000736 }
737
Chris Forbes9638b942019-02-21 18:39:31 -0800738 uint32_t SpirvShader::WalkLiteralAccessChain(TypeID typeId, uint32_t numIndexes, uint32_t const *indexes) const
739 {
740 uint32_t constantOffset = 0;
741
742 for (auto i = 0u; i < numIndexes; i++)
743 {
744 auto & type = getType(typeId);
745 switch (type.definition.opcode())
746 {
747 case spv::OpTypeStruct:
748 {
749 int memberIndex = indexes[i];
750 int offsetIntoStruct = 0;
751 for (auto j = 0; j < memberIndex; j++) {
752 auto memberType = type.definition.word(2u + j);
753 offsetIntoStruct += getType(memberType).sizeInComponents;
754 }
755 constantOffset += offsetIntoStruct;
756 typeId = type.definition.word(2u + memberIndex);
757 break;
758 }
759
760 case spv::OpTypeVector:
761 case spv::OpTypeMatrix:
762 case spv::OpTypeArray:
763 {
764 auto elementType = type.definition.word(2);
765 auto stride = getType(elementType).sizeInComponents;
766 constantOffset += stride * indexes[i];
767 typeId = elementType;
768 break;
769 }
770
771 default:
772 UNIMPLEMENTED("Unexpected type in WalkLiteralAccessChain");
773 }
774 }
775
776 return constantOffset;
777 }
778
Chris Forbesc25b8072018-12-10 15:10:39 -0800779 void SpirvShader::Decorations::Apply(spv::Decoration decoration, uint32_t arg)
780 {
781 switch (decoration)
782 {
783 case spv::DecorationLocation:
784 HasLocation = true;
785 Location = static_cast<int32_t>(arg);
786 break;
787 case spv::DecorationComponent:
788 HasComponent = true;
789 Component = arg;
790 break;
Ben Claytond073d8e2019-02-26 11:06:50 +0000791 case spv::DecorationDescriptorSet:
792 HasDescriptorSet = true;
793 DescriptorSet = arg;
794 break;
795 case spv::DecorationBinding:
796 HasBinding = true;
797 Binding = arg;
798 break;
Chris Forbesc25b8072018-12-10 15:10:39 -0800799 case spv::DecorationBuiltIn:
800 HasBuiltIn = true;
801 BuiltIn = static_cast<spv::BuiltIn>(arg);
802 break;
803 case spv::DecorationFlat:
804 Flat = true;
805 break;
806 case spv::DecorationNoPerspective:
Chris Forbes5839dcf2018-12-10 19:02:58 -0800807 NoPerspective = true;
Chris Forbesc25b8072018-12-10 15:10:39 -0800808 break;
809 case spv::DecorationCentroid:
810 Centroid = true;
811 break;
812 case spv::DecorationBlock:
813 Block = true;
814 break;
815 case spv::DecorationBufferBlock:
816 BufferBlock = true;
817 break;
Chris Forbes65321072019-03-07 16:13:56 -0800818 case spv::DecorationOffset:
819 HasOffset = true;
820 Offset = static_cast<int32_t>(arg);
821 break;
822 case spv::DecorationArrayStride:
823 HasArrayStride = true;
824 ArrayStride = static_cast<int32_t>(arg);
825 break;
826 case spv::DecorationMatrixStride:
827 HasMatrixStride = true;
828 MatrixStride = static_cast<int32_t>(arg);
829 break;
Chris Forbesc25b8072018-12-10 15:10:39 -0800830 default:
831 // Intentionally partial, there are many decorations we just don't care about.
832 break;
833 }
834 }
835
836 void SpirvShader::Decorations::Apply(const sw::SpirvShader::Decorations &src)
837 {
838 // Apply a decoration group to this set of decorations
839 if (src.HasBuiltIn)
840 {
841 HasBuiltIn = true;
842 BuiltIn = src.BuiltIn;
843 }
844
845 if (src.HasLocation)
846 {
847 HasLocation = true;
848 Location = src.Location;
849 }
850
851 if (src.HasComponent)
852 {
853 HasComponent = true;
854 Component = src.Component;
855 }
856
Ben Claytond073d8e2019-02-26 11:06:50 +0000857 if (src.HasDescriptorSet)
858 {
859 HasDescriptorSet = true;
860 DescriptorSet = src.DescriptorSet;
861 }
862
863 if (src.HasBinding)
864 {
865 HasBinding = true;
866 Binding = src.Binding;
867 }
868
Chris Forbes65321072019-03-07 16:13:56 -0800869 if (src.HasOffset)
870 {
871 HasOffset = true;
872 Offset = src.Offset;
873 }
874
875 if (src.HasArrayStride)
876 {
877 HasArrayStride = true;
878 ArrayStride = src.ArrayStride;
879 }
880
881 if (src.HasMatrixStride)
882 {
883 HasMatrixStride = true;
884 MatrixStride = src.MatrixStride;
885 }
886
Chris Forbesc25b8072018-12-10 15:10:39 -0800887 Flat |= src.Flat;
Chris Forbes5839dcf2018-12-10 19:02:58 -0800888 NoPerspective |= src.NoPerspective;
Chris Forbesc25b8072018-12-10 15:10:39 -0800889 Centroid |= src.Centroid;
890 Block |= src.Block;
891 BufferBlock |= src.BufferBlock;
892 }
Chris Forbesbc3a0ee2018-12-27 16:02:58 -0800893
Ben Claytonab51bbf2019-02-20 14:36:27 +0000894 void SpirvShader::ApplyDecorationsForId(Decorations *d, TypeOrObjectID id) const
Chris Forbes49d664d2019-02-12 19:24:50 +0000895 {
896 auto it = decorations.find(id);
897 if (it != decorations.end())
898 d->Apply(it->second);
899 }
900
Ben Claytonab51bbf2019-02-20 14:36:27 +0000901 void SpirvShader::ApplyDecorationsForIdMember(Decorations *d, TypeID id, uint32_t member) const
Chris Forbes49d664d2019-02-12 19:24:50 +0000902 {
903 auto it = memberDecorations.find(id);
904 if (it != memberDecorations.end() && member < it->second.size())
905 {
906 d->Apply(it->second[member]);
907 }
908 }
909
Ben Claytonab51bbf2019-02-20 14:36:27 +0000910 uint32_t SpirvShader::GetConstantInt(ObjectID id) const
Chris Forbesbc3a0ee2018-12-27 16:02:58 -0800911 {
912 // Slightly hackish access to constants very early in translation.
913 // General consumption of constants by other instructions should
914 // probably be just lowered to Reactor.
915
916 // TODO: not encountered yet since we only use this for array sizes etc,
917 // but is possible to construct integer constant 0 via OpConstantNull.
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800918 auto insn = getObject(id).definition;
Ben Clayton6fae32c2019-02-28 20:06:42 +0000919 ASSERT(insn.opcode() == spv::OpConstant);
920 ASSERT(getType(insn.word(1)).definition.opcode() == spv::OpTypeInt);
Chris Forbesbc3a0ee2018-12-27 16:02:58 -0800921 return insn.word(3);
922 }
Chris Forbesd5aed492019-02-02 15:18:52 -0800923
924 // emit-time
925
Chris Forbesc61271e2019-02-19 17:01:28 -0800926 void SpirvShader::emitProlog(SpirvRoutine *routine) const
Chris Forbesd5aed492019-02-02 15:18:52 -0800927 {
928 for (auto insn : *this)
929 {
930 switch (insn.opcode())
931 {
932 case spv::OpVariable:
933 {
Ben Claytonab51bbf2019-02-20 14:36:27 +0000934 ObjectID resultId = insn.word(2);
Chris Forbes0eba65b2019-02-13 12:24:35 -0800935 auto &object = getObject(resultId);
Ben Clayton9a162482019-02-25 11:54:43 +0000936 auto &objectTy = getType(object.type);
937 auto &pointeeTy = getType(objectTy.element);
Chris Forbesd5aed492019-02-02 15:18:52 -0800938 // TODO: what to do about zero-slot objects?
Ben Clayton9a162482019-02-25 11:54:43 +0000939 if (pointeeTy.sizeInComponents > 0)
Chris Forbesd5aed492019-02-02 15:18:52 -0800940 {
Ben Clayton9a162482019-02-25 11:54:43 +0000941 routine->createLvalue(insn.word(2), pointeeTy.sizeInComponents);
Chris Forbesd5aed492019-02-02 15:18:52 -0800942 }
943 break;
944 }
945 default:
Chris Forbese9f8f5b2019-02-11 00:20:16 +0000946 // Nothing else produces interface variables, so can all be safely ignored.
Chris Forbesd5aed492019-02-02 15:18:52 -0800947 break;
948 }
949 }
950 }
951
952 void SpirvShader::emit(SpirvRoutine *routine) const
953 {
Chris Forbesd5aed492019-02-02 15:18:52 -0800954 for (auto insn : *this)
955 {
956 switch (insn.opcode())
957 {
Chris Forbese53533d2019-02-21 16:49:51 -0800958 case spv::OpTypeVoid:
959 case spv::OpTypeInt:
960 case spv::OpTypeFloat:
961 case spv::OpTypeBool:
962 case spv::OpTypeVector:
963 case spv::OpTypeArray:
964 case spv::OpTypeRuntimeArray:
965 case spv::OpTypeMatrix:
966 case spv::OpTypeStruct:
967 case spv::OpTypePointer:
968 case spv::OpTypeFunction:
969 case spv::OpExecutionMode:
970 case spv::OpMemoryModel:
971 case spv::OpFunction:
972 case spv::OpFunctionEnd:
973 case spv::OpConstant:
974 case spv::OpConstantNull:
975 case spv::OpConstantTrue:
976 case spv::OpConstantFalse:
977 case spv::OpConstantComposite:
978 case spv::OpExtension:
979 case spv::OpCapability:
980 case spv::OpEntryPoint:
981 case spv::OpExtInstImport:
982 case spv::OpDecorate:
983 case spv::OpMemberDecorate:
984 case spv::OpGroupDecorate:
985 case spv::OpGroupMemberDecorate:
986 case spv::OpDecorationGroup:
Chris Forbes1776af72019-02-22 17:39:57 -0800987 case spv::OpName:
988 case spv::OpMemberName:
989 case spv::OpSource:
990 case spv::OpSourceContinued:
991 case spv::OpSourceExtension:
Chris Forbesf3a430d2019-03-08 07:51:39 -0800992 case spv::OpLine:
993 case spv::OpNoLine:
994 case spv::OpModuleProcessed:
995 case spv::OpString:
Chris Forbese53533d2019-02-21 16:49:51 -0800996 // Nothing to do at emit time. These are either fully handled at analysis time,
997 // or don't require any work at all.
998 break;
999
Chris Forbese57f10e2019-03-04 10:53:07 -08001000 case spv::OpLabel:
1001 case spv::OpReturn:
1002 // TODO: when we do control flow, will need to do some work here.
1003 // Until then, there is nothing to do -- we expect there to be an initial OpLabel
1004 // in the entrypoint function, for which we do nothing; and a final OpReturn at the
1005 // end of the entrypoint function, for which we do nothing.
1006 break;
1007
Chris Forbes0eba65b2019-02-13 12:24:35 -08001008 case spv::OpVariable:
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001009 EmitVariable(insn, routine);
Chris Forbes0eba65b2019-02-13 12:24:35 -08001010 break;
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001011
Chris Forbese9f8f5b2019-02-11 00:20:16 +00001012 case spv::OpLoad:
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001013 EmitLoad(insn, routine);
Chris Forbese9f8f5b2019-02-11 00:20:16 +00001014 break;
Chris Forbes38f85b32019-02-12 20:10:05 +00001015
Chris Forbes1c588002019-02-12 18:56:38 +00001016 case spv::OpStore:
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001017 EmitStore(insn, routine);
Chris Forbes1c588002019-02-12 18:56:38 +00001018 break;
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001019
1020 case spv::OpAccessChain:
1021 EmitAccessChain(insn, routine);
1022 break;
1023
Chris Forbesb97a9572019-02-21 16:51:42 -08001024 case spv::OpCompositeConstruct:
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001025 EmitCompositeConstruct(insn, routine);
Chris Forbesb97a9572019-02-21 16:51:42 -08001026 break;
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001027
Chris Forbes1bc1acf2019-02-21 18:40:33 -08001028 case spv::OpCompositeInsert:
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001029 EmitCompositeInsert(insn, routine);
Chris Forbes1bc1acf2019-02-21 18:40:33 -08001030 break;
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001031
Chris Forbesb12846d2019-02-21 18:53:58 -08001032 case spv::OpCompositeExtract:
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001033 EmitCompositeExtract(insn, routine);
Chris Forbesb12846d2019-02-21 18:53:58 -08001034 break;
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001035
Chris Forbes83fc5442019-02-26 22:16:07 -08001036 case spv::OpVectorShuffle:
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001037 EmitVectorShuffle(insn, routine);
Chris Forbes83fc5442019-02-26 22:16:07 -08001038 break;
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001039
Ben Claytondd1e37e2019-02-28 19:59:15 +00001040 case spv::OpNot:
1041 case spv::OpSNegate:
1042 case spv::OpFNegate:
1043 case spv::OpLogicalNot:
Chris Forbes4d503052019-03-01 17:13:57 -08001044 case spv::OpConvertFToU:
1045 case spv::OpConvertFToS:
1046 case spv::OpConvertSToF:
1047 case spv::OpConvertUToF:
1048 case spv::OpBitcast:
Chris Forbes3ed33ce2019-03-07 13:38:31 -08001049 case spv::OpIsInf:
1050 case spv::OpIsNan:
Ben Claytondd1e37e2019-02-28 19:59:15 +00001051 EmitUnaryOp(insn, routine);
1052 break;
1053
1054 case spv::OpIAdd:
1055 case spv::OpISub:
1056 case spv::OpIMul:
1057 case spv::OpSDiv:
1058 case spv::OpUDiv:
1059 case spv::OpFAdd:
1060 case spv::OpFSub:
Chris Forbes9d931532019-03-08 09:53:03 -08001061 case spv::OpFMul:
Ben Claytondd1e37e2019-02-28 19:59:15 +00001062 case spv::OpFDiv:
Ben Claytonec1aeb82019-03-04 19:33:27 +00001063 case spv::OpFOrdEqual:
1064 case spv::OpFUnordEqual:
1065 case spv::OpFOrdNotEqual:
1066 case spv::OpFUnordNotEqual:
1067 case spv::OpFOrdLessThan:
1068 case spv::OpFUnordLessThan:
1069 case spv::OpFOrdGreaterThan:
1070 case spv::OpFUnordGreaterThan:
1071 case spv::OpFOrdLessThanEqual:
1072 case spv::OpFUnordLessThanEqual:
1073 case spv::OpFOrdGreaterThanEqual:
1074 case spv::OpFUnordGreaterThanEqual:
Ben Claytondd1e37e2019-02-28 19:59:15 +00001075 case spv::OpUMod:
Ben Claytone95eeb12019-03-04 16:32:09 +00001076 case spv::OpIEqual:
1077 case spv::OpINotEqual:
1078 case spv::OpUGreaterThan:
1079 case spv::OpSGreaterThan:
1080 case spv::OpUGreaterThanEqual:
1081 case spv::OpSGreaterThanEqual:
1082 case spv::OpULessThan:
1083 case spv::OpSLessThan:
1084 case spv::OpULessThanEqual:
1085 case spv::OpSLessThanEqual:
Ben Claytondd1e37e2019-02-28 19:59:15 +00001086 case spv::OpShiftRightLogical:
1087 case spv::OpShiftRightArithmetic:
1088 case spv::OpShiftLeftLogical:
1089 case spv::OpBitwiseOr:
1090 case spv::OpBitwiseXor:
1091 case spv::OpBitwiseAnd:
1092 case spv::OpLogicalOr:
1093 case spv::OpLogicalAnd:
Chris Forbese86b6dc2019-03-01 09:08:47 -08001094 case spv::OpUMulExtended:
1095 case spv::OpSMulExtended:
Ben Claytondd1e37e2019-02-28 19:59:15 +00001096 EmitBinaryOp(insn, routine);
1097 break;
1098
Chris Forbes2b287cc2019-03-01 13:24:17 -08001099 case spv::OpDot:
1100 EmitDot(insn, routine);
1101 break;
1102
Ben Claytonbf943f62019-03-05 12:57:39 +00001103 case spv::OpSelect:
1104 EmitSelect(insn, routine);
1105 break;
1106
Chris Forbes9667a5b2019-03-07 09:26:48 -08001107 case spv::OpExtInst:
1108 EmitExtendedInstruction(insn, routine);
1109 break;
1110
Chris Forbes0785f692019-03-08 09:09:18 -08001111 case spv::OpAny:
1112 EmitAny(insn, routine);
1113 break;
1114
1115 case spv::OpAll:
1116 EmitAll(insn, routine);
1117 break;
1118
Chris Forbesd5aed492019-02-02 15:18:52 -08001119 default:
Chris Forbese57f10e2019-03-04 10:53:07 -08001120 UNIMPLEMENTED(OpcodeName(insn.opcode()).c_str());
Chris Forbesd5aed492019-02-02 15:18:52 -08001121 break;
1122 }
1123 }
1124 }
Chris Forbesc61271e2019-02-19 17:01:28 -08001125
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001126 void SpirvShader::EmitVariable(InsnIterator insn, SpirvRoutine *routine) const
1127 {
1128 ObjectID resultId = insn.word(2);
1129 auto &object = getObject(resultId);
1130 auto &objectTy = getType(object.type);
Ben Claytonefec1b92019-03-05 17:38:16 +00001131 switch (objectTy.storageClass)
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001132 {
Ben Claytonefec1b92019-03-05 17:38:16 +00001133 case spv::StorageClassInput:
1134 {
1135 if (object.kind == Object::Kind::InterfaceVariable)
1136 {
1137 auto &dst = routine->getValue(resultId);
1138 int offset = 0;
1139 VisitInterface(resultId,
1140 [&](Decorations const &d, AttribType type) {
1141 auto scalarSlot = d.Location << 2 | d.Component;
1142 dst[offset++] = routine->inputs[scalarSlot];
1143 });
1144 }
1145 break;
1146 }
1147 case spv::StorageClassUniform:
1148 case spv::StorageClassStorageBuffer:
1149 {
1150 Decorations d{};
1151 ApplyDecorationsForId(&d, resultId);
1152 ASSERT(d.DescriptorSet >= 0);
1153 ASSERT(d.Binding >= 0);
1154
1155 size_t bindingOffset = routine->pipelineLayout->getBindingOffset(d.DescriptorSet, d.Binding);
1156
1157 Pointer<Byte> set = routine->descriptorSets[d.DescriptorSet]; // DescriptorSet*
1158 Pointer<Byte> binding = Pointer<Byte>(set + bindingOffset); // VkDescriptorBufferInfo*
1159 Pointer<Byte> buffer = *Pointer<Pointer<Byte>>(binding + OFFSET(VkDescriptorBufferInfo, buffer)); // vk::Buffer*
1160 Pointer<Byte> data = *Pointer<Pointer<Byte>>(buffer + vk::Buffer::DataOffset); // void*
1161 Int offset = *Pointer<Int>(binding + OFFSET(VkDescriptorBufferInfo, offset));
1162 Pointer<Byte> address = data + offset;
1163 routine->physicalPointers[resultId] = address;
1164 break;
1165 }
1166 default:
1167 break;
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001168 }
1169 }
1170
1171 void SpirvShader::EmitLoad(InsnIterator insn, SpirvRoutine *routine) const
1172 {
1173 ObjectID objectId = insn.word(2);
1174 ObjectID pointerId = insn.word(3);
1175 auto &object = getObject(objectId);
1176 auto &objectTy = getType(object.type);
1177 auto &pointer = getObject(pointerId);
1178 auto &pointerBase = getObject(pointer.pointerBase);
1179 auto &pointerBaseTy = getType(pointerBase.type);
1180
1181 ASSERT(getType(pointer.type).element == object.type);
1182 ASSERT(TypeID(insn.word(1)) == object.type);
1183
Ben Claytonefec1b92019-03-05 17:38:16 +00001184 if (pointerBaseTy.storageClass == spv::StorageClassImage)
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001185 {
Ben Claytonefec1b92019-03-05 17:38:16 +00001186 UNIMPLEMENTED("StorageClassImage load not yet implemented");
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001187 }
1188
Ben Clayton831db962019-02-27 14:57:18 +00001189 Pointer<Float> ptrBase;
1190 if (pointerBase.kind == Object::Kind::PhysicalPointer)
1191 {
1192 ptrBase = routine->getPhysicalPointer(pointer.pointerBase);
1193 }
1194 else
1195 {
1196 ptrBase = &routine->getValue(pointer.pointerBase)[0];
1197 }
1198
1199 bool interleavedByLane = IsStorageInterleavedByLane(pointerBaseTy.storageClass);
1200
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001201 auto &dst = routine->createIntermediate(objectId, objectTy.sizeInComponents);
1202
1203 if (pointer.kind == Object::Kind::Value)
1204 {
Ben Clayton831db962019-02-27 14:57:18 +00001205 // Divergent offsets.
1206 auto offsets = As<SIMD::Int>(routine->getIntermediate(pointerId)[0]);
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001207 for (auto i = 0u; i < objectTy.sizeInComponents; i++)
1208 {
1209 // i wish i had a Float,Float,Float,Float constructor here..
1210 SIMD::Float v;
1211 for (int j = 0; j < SIMD::Width; j++)
1212 {
1213 Int offset = Int(i) + Extract(offsets, j);
Ben Clayton831db962019-02-27 14:57:18 +00001214 if (interleavedByLane) { offset = offset * SIMD::Width + j; }
1215 v = Insert(v, ptrBase[offset], j);
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001216 }
1217 dst.emplace(i, v);
1218 }
1219 }
Ben Clayton831db962019-02-27 14:57:18 +00001220 else if (interleavedByLane)
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001221 {
Ben Clayton831db962019-02-27 14:57:18 +00001222 // Lane-interleaved data. No divergent offsets.
1223 Pointer<SIMD::Float> src = ptrBase;
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001224 for (auto i = 0u; i < objectTy.sizeInComponents; i++)
1225 {
Ben Clayton831db962019-02-27 14:57:18 +00001226 dst.emplace(i, src[i]);
1227 }
1228 }
1229 else
1230 {
1231 // Non-interleaved data. No divergent offsets.
1232 for (auto i = 0u; i < objectTy.sizeInComponents; i++)
1233 {
1234 dst.emplace(i, RValue<SIMD::Float>(ptrBase[i]));
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001235 }
1236 }
1237 }
1238
1239 void SpirvShader::EmitAccessChain(InsnIterator insn, SpirvRoutine *routine) const
1240 {
1241 TypeID typeId = insn.word(1);
1242 ObjectID objectId = insn.word(2);
1243 ObjectID baseId = insn.word(3);
1244 auto &object = getObject(objectId);
1245 auto &type = getType(typeId);
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001246 ASSERT(type.sizeInComponents == 1);
1247 ASSERT(getObject(baseId).pointerBase == object.pointerBase);
1248
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001249 auto &dst = routine->createIntermediate(objectId, type.sizeInComponents);
1250 dst.emplace(0, As<SIMD::Float>(WalkAccessChain(baseId, insn.wordCount() - 4, insn.wordPointer(4), routine)));
1251 }
1252
1253 void SpirvShader::EmitStore(InsnIterator insn, SpirvRoutine *routine) const
1254 {
1255 ObjectID pointerId = insn.word(1);
1256 ObjectID objectId = insn.word(2);
1257 auto &object = getObject(objectId);
1258 auto &pointer = getObject(pointerId);
1259 auto &pointerTy = getType(pointer.type);
1260 auto &elementTy = getType(pointerTy.element);
1261 auto &pointerBase = getObject(pointer.pointerBase);
1262 auto &pointerBaseTy = getType(pointerBase.type);
1263
Ben Claytonefec1b92019-03-05 17:38:16 +00001264 if (pointerBaseTy.storageClass == spv::StorageClassImage)
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001265 {
Ben Claytonefec1b92019-03-05 17:38:16 +00001266 UNIMPLEMENTED("StorageClassImage store not yet implemented");
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001267 }
1268
Ben Clayton831db962019-02-27 14:57:18 +00001269 Pointer<Float> ptrBase;
1270 if (pointerBase.kind == Object::Kind::PhysicalPointer)
1271 {
1272 ptrBase = routine->getPhysicalPointer(pointer.pointerBase);
1273 }
1274 else
1275 {
1276 ptrBase = &routine->getValue(pointer.pointerBase)[0];
1277 }
1278
1279 bool interleavedByLane = IsStorageInterleavedByLane(pointerBaseTy.storageClass);
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001280
1281 if (object.kind == Object::Kind::Constant)
1282 {
1283 auto src = reinterpret_cast<float *>(object.constantValue.get());
1284
1285 if (pointer.kind == Object::Kind::Value)
1286 {
Ben Clayton831db962019-02-27 14:57:18 +00001287 // Constant source data. Divergent offsets.
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001288 auto offsets = As<SIMD::Int>(routine->getIntermediate(pointerId)[0]);
1289 for (auto i = 0u; i < elementTy.sizeInComponents; i++)
1290 {
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001291 for (int j = 0; j < SIMD::Width; j++)
1292 {
Ben Clayton831db962019-02-27 14:57:18 +00001293 Int offset = Int(i) + Extract(offsets, j);
1294 if (interleavedByLane) { offset = offset * SIMD::Width + j; }
1295 ptrBase[offset] = RValue<Float>(src[i]);
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001296 }
1297 }
1298 }
1299 else
1300 {
Ben Clayton831db962019-02-27 14:57:18 +00001301 // Constant source data. No divergent offsets.
1302 Pointer<SIMD::Float> dst = ptrBase;
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001303 for (auto i = 0u; i < elementTy.sizeInComponents; i++)
1304 {
Ben Clayton831db962019-02-27 14:57:18 +00001305 dst[i] = RValue<SIMD::Float>(src[i]);
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001306 }
1307 }
1308 }
1309 else
1310 {
1311 auto &src = routine->getIntermediate(objectId);
1312
1313 if (pointer.kind == Object::Kind::Value)
1314 {
Ben Clayton831db962019-02-27 14:57:18 +00001315 // Intermediate source data. Divergent offsets.
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001316 auto offsets = As<SIMD::Int>(routine->getIntermediate(pointerId)[0]);
1317 for (auto i = 0u; i < elementTy.sizeInComponents; i++)
1318 {
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001319 for (int j = 0; j < SIMD::Width; j++)
1320 {
Ben Clayton831db962019-02-27 14:57:18 +00001321 Int offset = Int(i) + Extract(offsets, j);
1322 if (interleavedByLane) { offset = offset * SIMD::Width + j; }
1323 ptrBase[offset] = Extract(src[i], j);
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001324 }
1325 }
1326 }
Ben Clayton831db962019-02-27 14:57:18 +00001327 else if (interleavedByLane)
1328 {
1329 // Intermediate source data. Lane-interleaved data. No divergent offsets.
1330 Pointer<SIMD::Float> dst = ptrBase;
1331 for (auto i = 0u; i < elementTy.sizeInComponents; i++)
1332 {
1333 dst[i] = src[i];
1334 }
1335 }
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001336 else
1337 {
Ben Clayton831db962019-02-27 14:57:18 +00001338 // Intermediate source data. Non-interleaved data. No divergent offsets.
1339 Pointer<SIMD::Float> dst = ptrBase;
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001340 for (auto i = 0u; i < elementTy.sizeInComponents; i++)
1341 {
Ben Clayton831db962019-02-27 14:57:18 +00001342 dst[i] = SIMD::Float(src[i]);
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001343 }
1344 }
1345 }
1346 }
1347
1348 void SpirvShader::EmitCompositeConstruct(InsnIterator insn, SpirvRoutine *routine) const
1349 {
1350 auto &type = getType(insn.word(1));
1351 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
1352 auto offset = 0u;
1353
1354 for (auto i = 0u; i < insn.wordCount() - 3; i++)
1355 {
1356 ObjectID srcObjectId = insn.word(3u + i);
1357 auto & srcObject = getObject(srcObjectId);
1358 auto & srcObjectTy = getType(srcObject.type);
1359 GenericValue srcObjectAccess(this, routine, srcObjectId);
1360
1361 for (auto j = 0u; j < srcObjectTy.sizeInComponents; j++)
1362 dst.emplace(offset++, srcObjectAccess[j]);
1363 }
1364 }
1365
1366 void SpirvShader::EmitCompositeInsert(InsnIterator insn, SpirvRoutine *routine) const
1367 {
1368 TypeID resultTypeId = insn.word(1);
1369 auto &type = getType(resultTypeId);
1370 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
1371 auto &newPartObject = getObject(insn.word(3));
1372 auto &newPartObjectTy = getType(newPartObject.type);
1373 auto firstNewComponent = WalkLiteralAccessChain(resultTypeId, insn.wordCount() - 5, insn.wordPointer(5));
1374
1375 GenericValue srcObjectAccess(this, routine, insn.word(4));
1376 GenericValue newPartObjectAccess(this, routine, insn.word(3));
1377
1378 // old components before
1379 for (auto i = 0u; i < firstNewComponent; i++)
1380 {
1381 dst.emplace(i, srcObjectAccess[i]);
1382 }
1383 // new part
1384 for (auto i = 0u; i < newPartObjectTy.sizeInComponents; i++)
1385 {
1386 dst.emplace(firstNewComponent + i, newPartObjectAccess[i]);
1387 }
1388 // old components after
1389 for (auto i = firstNewComponent + newPartObjectTy.sizeInComponents; i < type.sizeInComponents; i++)
1390 {
1391 dst.emplace(i, srcObjectAccess[i]);
1392 }
1393 }
1394
1395 void SpirvShader::EmitCompositeExtract(InsnIterator insn, SpirvRoutine *routine) const
1396 {
1397 auto &type = getType(insn.word(1));
1398 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
1399 auto &compositeObject = getObject(insn.word(3));
1400 TypeID compositeTypeId = compositeObject.definition.word(1);
1401 auto firstComponent = WalkLiteralAccessChain(compositeTypeId, insn.wordCount() - 4, insn.wordPointer(4));
1402
1403 GenericValue compositeObjectAccess(this, routine, insn.word(3));
1404 for (auto i = 0u; i < type.sizeInComponents; i++)
1405 {
1406 dst.emplace(i, compositeObjectAccess[firstComponent + i]);
1407 }
1408 }
1409
1410 void SpirvShader::EmitVectorShuffle(InsnIterator insn, SpirvRoutine *routine) const
1411 {
1412 auto &type = getType(insn.word(1));
1413 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
1414
Chris Forbes13eba6c2019-03-08 10:41:05 -08001415 // Note: number of components in result type, first half type, and second
1416 // half type are all independent.
1417 auto &firstHalfType = getType(getObject(insn.word(3)).type);
1418
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001419 GenericValue firstHalfAccess(this, routine, insn.word(3));
1420 GenericValue secondHalfAccess(this, routine, insn.word(4));
1421
1422 for (auto i = 0u; i < type.sizeInComponents; i++)
1423 {
1424 auto selector = insn.word(5 + i);
1425 if (selector == static_cast<uint32_t>(-1))
1426 {
1427 // Undefined value. Until we decide to do real undef values, zero is as good
1428 // a value as any
1429 dst.emplace(i, RValue<SIMD::Float>(0.0f));
1430 }
Chris Forbes13eba6c2019-03-08 10:41:05 -08001431 else if (selector < firstHalfType.sizeInComponents)
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001432 {
1433 dst.emplace(i, firstHalfAccess[selector]);
1434 }
1435 else
1436 {
Chris Forbes13eba6c2019-03-08 10:41:05 -08001437 dst.emplace(i, secondHalfAccess[selector - firstHalfType.sizeInComponents]);
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001438 }
1439 }
1440 }
1441
Ben Claytondd1e37e2019-02-28 19:59:15 +00001442 void SpirvShader::EmitUnaryOp(InsnIterator insn, SpirvRoutine *routine) const
1443 {
1444 auto &type = getType(insn.word(1));
1445 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
1446 auto src = GenericValue(this, routine, insn.word(3));
1447
1448 for (auto i = 0u; i < type.sizeInComponents; i++)
1449 {
1450 auto val = src[i];
1451
1452 switch (insn.opcode())
1453 {
1454 case spv::OpNot:
1455 case spv::OpLogicalNot: // logical not == bitwise not due to all-bits boolean representation
1456 dst.emplace(i, As<SIMD::Float>(~As<SIMD::UInt>(val)));
1457 break;
1458 case spv::OpSNegate:
1459 dst.emplace(i, As<SIMD::Float>(-As<SIMD::Int>(val)));
1460 break;
1461 case spv::OpFNegate:
1462 dst.emplace(i, -val);
1463 break;
Chris Forbes4d503052019-03-01 17:13:57 -08001464 case spv::OpConvertFToU:
1465 dst.emplace(i, As<SIMD::Float>(SIMD::UInt(val)));
1466 break;
1467 case spv::OpConvertFToS:
1468 dst.emplace(i, As<SIMD::Float>(SIMD::Int(val)));
1469 break;
1470 case spv::OpConvertSToF:
1471 dst.emplace(i, SIMD::Float(As<SIMD::Int>(val)));
1472 break;
1473 case spv::OpConvertUToF:
1474 dst.emplace(i, SIMD::Float(As<SIMD::UInt>(val)));
1475 break;
1476 case spv::OpBitcast:
1477 dst.emplace(i, val);
1478 break;
Chris Forbes3ed33ce2019-03-07 13:38:31 -08001479 case spv::OpIsInf:
1480 dst.emplace(i, As<SIMD::Float>(IsInf(val)));
1481 break;
1482 case spv::OpIsNan:
1483 dst.emplace(i, As<SIMD::Float>(IsNan(val)));
1484 break;
Ben Claytondd1e37e2019-02-28 19:59:15 +00001485 default:
1486 UNIMPLEMENTED("Unhandled unary operator %s", OpcodeName(insn.opcode()).c_str());
1487 }
1488 }
1489 }
1490
1491 void SpirvShader::EmitBinaryOp(InsnIterator insn, SpirvRoutine *routine) const
1492 {
1493 auto &type = getType(insn.word(1));
1494 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
Chris Forbese86b6dc2019-03-01 09:08:47 -08001495 auto &lhsType = getType(getObject(insn.word(3)).type);
Ben Claytondd1e37e2019-02-28 19:59:15 +00001496 auto srcLHS = GenericValue(this, routine, insn.word(3));
1497 auto srcRHS = GenericValue(this, routine, insn.word(4));
1498
Chris Forbese86b6dc2019-03-01 09:08:47 -08001499 for (auto i = 0u; i < lhsType.sizeInComponents; i++)
Ben Claytondd1e37e2019-02-28 19:59:15 +00001500 {
1501 auto lhs = srcLHS[i];
1502 auto rhs = srcRHS[i];
1503
1504 switch (insn.opcode())
1505 {
1506 case spv::OpIAdd:
1507 dst.emplace(i, As<SIMD::Float>(As<SIMD::Int>(lhs) + As<SIMD::Int>(rhs)));
1508 break;
1509 case spv::OpISub:
1510 dst.emplace(i, As<SIMD::Float>(As<SIMD::Int>(lhs) - As<SIMD::Int>(rhs)));
1511 break;
1512 case spv::OpIMul:
1513 dst.emplace(i, As<SIMD::Float>(As<SIMD::Int>(lhs) * As<SIMD::Int>(rhs)));
1514 break;
1515 case spv::OpSDiv:
1516 dst.emplace(i, As<SIMD::Float>(As<SIMD::Int>(lhs) / As<SIMD::Int>(rhs)));
1517 break;
1518 case spv::OpUDiv:
1519 dst.emplace(i, As<SIMD::Float>(As<SIMD::UInt>(lhs) / As<SIMD::UInt>(rhs)));
1520 break;
1521 case spv::OpUMod:
1522 dst.emplace(i, As<SIMD::Float>(As<SIMD::UInt>(lhs) % As<SIMD::UInt>(rhs)));
1523 break;
Ben Claytone95eeb12019-03-04 16:32:09 +00001524 case spv::OpIEqual:
1525 dst.emplace(i, As<SIMD::Float>(CmpEQ(As<SIMD::Int>(lhs), As<SIMD::Int>(rhs))));
1526 break;
1527 case spv::OpINotEqual:
1528 dst.emplace(i, As<SIMD::Float>(CmpNEQ(As<SIMD::Int>(lhs), As<SIMD::Int>(rhs))));
1529 break;
1530 case spv::OpUGreaterThan:
1531 dst.emplace(i, As<SIMD::Float>(CmpGT(As<SIMD::UInt>(lhs), As<SIMD::UInt>(rhs))));
1532 break;
1533 case spv::OpSGreaterThan:
1534 dst.emplace(i, As<SIMD::Float>(CmpGT(As<SIMD::Int>(lhs), As<SIMD::Int>(rhs))));
1535 break;
1536 case spv::OpUGreaterThanEqual:
1537 dst.emplace(i, As<SIMD::Float>(CmpGE(As<SIMD::UInt>(lhs), As<SIMD::UInt>(rhs))));
1538 break;
1539 case spv::OpSGreaterThanEqual:
1540 dst.emplace(i, As<SIMD::Float>(CmpGE(As<SIMD::Int>(lhs), As<SIMD::Int>(rhs))));
1541 break;
1542 case spv::OpULessThan:
1543 dst.emplace(i, As<SIMD::Float>(CmpLT(As<SIMD::UInt>(lhs), As<SIMD::UInt>(rhs))));
1544 break;
1545 case spv::OpSLessThan:
1546 dst.emplace(i, As<SIMD::Float>(CmpLT(As<SIMD::Int>(lhs), As<SIMD::Int>(rhs))));
1547 break;
1548 case spv::OpULessThanEqual:
1549 dst.emplace(i, As<SIMD::Float>(CmpLE(As<SIMD::UInt>(lhs), As<SIMD::UInt>(rhs))));
1550 break;
1551 case spv::OpSLessThanEqual:
1552 dst.emplace(i, As<SIMD::Float>(CmpLE(As<SIMD::Int>(lhs), As<SIMD::Int>(rhs))));
1553 break;
Ben Claytondd1e37e2019-02-28 19:59:15 +00001554 case spv::OpFAdd:
1555 dst.emplace(i, lhs + rhs);
1556 break;
1557 case spv::OpFSub:
1558 dst.emplace(i, lhs - rhs);
1559 break;
Chris Forbes9d931532019-03-08 09:53:03 -08001560 case spv::OpFMul:
1561 dst.emplace(i, lhs * rhs);
1562 break;
Ben Claytondd1e37e2019-02-28 19:59:15 +00001563 case spv::OpFDiv:
1564 dst.emplace(i, lhs / rhs);
1565 break;
Ben Claytonec1aeb82019-03-04 19:33:27 +00001566 case spv::OpFOrdEqual:
1567 dst.emplace(i, As<SIMD::Float>(CmpEQ(lhs, rhs)));
1568 break;
1569 case spv::OpFUnordEqual:
1570 dst.emplace(i, As<SIMD::Float>(CmpUEQ(lhs, rhs)));
1571 break;
1572 case spv::OpFOrdNotEqual:
1573 dst.emplace(i, As<SIMD::Float>(CmpNEQ(lhs, rhs)));
1574 break;
1575 case spv::OpFUnordNotEqual:
1576 dst.emplace(i, As<SIMD::Float>(CmpUNEQ(lhs, rhs)));
1577 break;
1578 case spv::OpFOrdLessThan:
1579 dst.emplace(i, As<SIMD::Float>(CmpLT(lhs, rhs)));
1580 break;
1581 case spv::OpFUnordLessThan:
1582 dst.emplace(i, As<SIMD::Float>(CmpULT(lhs, rhs)));
1583 break;
1584 case spv::OpFOrdGreaterThan:
1585 dst.emplace(i, As<SIMD::Float>(CmpGT(lhs, rhs)));
1586 break;
1587 case spv::OpFUnordGreaterThan:
1588 dst.emplace(i, As<SIMD::Float>(CmpUGT(lhs, rhs)));
1589 break;
1590 case spv::OpFOrdLessThanEqual:
1591 dst.emplace(i, As<SIMD::Float>(CmpLE(lhs, rhs)));
1592 break;
1593 case spv::OpFUnordLessThanEqual:
1594 dst.emplace(i, As<SIMD::Float>(CmpULE(lhs, rhs)));
1595 break;
1596 case spv::OpFOrdGreaterThanEqual:
1597 dst.emplace(i, As<SIMD::Float>(CmpGE(lhs, rhs)));
1598 break;
1599 case spv::OpFUnordGreaterThanEqual:
1600 dst.emplace(i, As<SIMD::Float>(CmpUGE(lhs, rhs)));
1601 break;
Ben Claytondd1e37e2019-02-28 19:59:15 +00001602 case spv::OpShiftRightLogical:
1603 dst.emplace(i, As<SIMD::Float>(As<SIMD::UInt>(lhs) >> As<SIMD::UInt>(rhs)));
1604 break;
1605 case spv::OpShiftRightArithmetic:
1606 dst.emplace(i, As<SIMD::Float>(As<SIMD::Int>(lhs) >> As<SIMD::Int>(rhs)));
1607 break;
1608 case spv::OpShiftLeftLogical:
1609 dst.emplace(i, As<SIMD::Float>(As<SIMD::UInt>(lhs) << As<SIMD::UInt>(rhs)));
1610 break;
1611 case spv::OpBitwiseOr:
1612 case spv::OpLogicalOr:
1613 dst.emplace(i, As<SIMD::Float>(As<SIMD::UInt>(lhs) | As<SIMD::UInt>(rhs)));
1614 break;
1615 case spv::OpBitwiseXor:
1616 dst.emplace(i, As<SIMD::Float>(As<SIMD::UInt>(lhs) ^ As<SIMD::UInt>(rhs)));
1617 break;
1618 case spv::OpBitwiseAnd:
1619 case spv::OpLogicalAnd:
1620 dst.emplace(i, As<SIMD::Float>(As<SIMD::UInt>(lhs) & As<SIMD::UInt>(rhs)));
1621 break;
Chris Forbese86b6dc2019-03-01 09:08:47 -08001622 case spv::OpSMulExtended:
1623 // Extended ops: result is a structure containing two members of the same type as lhs & rhs.
1624 // In our flat view then, component i is the i'th component of the first member;
1625 // component i + N is the i'th component of the second member.
1626 dst.emplace(i, As<SIMD::Float>(As<SIMD::Int>(lhs) * As<SIMD::Int>(rhs)));
1627 dst.emplace(i + lhsType.sizeInComponents, As<SIMD::Float>(MulHigh(As<SIMD::Int>(lhs), As<SIMD::Int>(rhs))));
1628 break;
1629 case spv::OpUMulExtended:
1630 dst.emplace(i, As<SIMD::Float>(As<SIMD::UInt>(lhs) * As<SIMD::UInt>(rhs)));
1631 dst.emplace(i + lhsType.sizeInComponents, As<SIMD::Float>(MulHigh(As<SIMD::UInt>(lhs), As<SIMD::UInt>(rhs))));
1632 break;
Ben Claytondd1e37e2019-02-28 19:59:15 +00001633 default:
1634 UNIMPLEMENTED("Unhandled binary operator %s", OpcodeName(insn.opcode()).c_str());
1635 }
1636 }
1637 }
1638
Chris Forbes2b287cc2019-03-01 13:24:17 -08001639 void SpirvShader::EmitDot(InsnIterator insn, SpirvRoutine *routine) const
1640 {
1641 auto &type = getType(insn.word(1));
1642 assert(type.sizeInComponents == 1);
1643 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
1644 auto &lhsType = getType(getObject(insn.word(3)).type);
1645 auto srcLHS = GenericValue(this, routine, insn.word(3));
1646 auto srcRHS = GenericValue(this, routine, insn.word(4));
1647
1648 SIMD::Float result = srcLHS[0] * srcRHS[0];
1649
1650 for (auto i = 1u; i < lhsType.sizeInComponents; i++)
1651 {
1652 result += srcLHS[i] * srcRHS[i];
1653 }
1654
1655 dst.emplace(0, result);
1656 }
1657
Ben Claytonbf943f62019-03-05 12:57:39 +00001658 void SpirvShader::EmitSelect(InsnIterator insn, SpirvRoutine *routine) const
1659 {
1660 auto &type = getType(insn.word(1));
1661 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
1662 auto srcCond = GenericValue(this, routine, insn.word(3));
1663 auto srcLHS = GenericValue(this, routine, insn.word(4));
1664 auto srcRHS = GenericValue(this, routine, insn.word(5));
1665
1666 for (auto i = 0u; i < type.sizeInComponents; i++)
1667 {
1668 auto cond = As<SIMD::Int>(srcCond[i]);
1669 auto lhs = srcLHS[i];
1670 auto rhs = srcRHS[i];
1671 auto out = (cond & As<Int4>(lhs)) | (~cond & As<Int4>(rhs)); // FIXME: IfThenElse()
1672 dst.emplace(i, As<SIMD::Float>(out));
1673 }
1674 }
1675
Chris Forbes9667a5b2019-03-07 09:26:48 -08001676 void SpirvShader::EmitExtendedInstruction(InsnIterator insn, SpirvRoutine *routine) const
1677 {
1678 auto &type = getType(insn.word(1));
1679 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
1680 auto extInstIndex = static_cast<GLSLstd450>(insn.word(4));
1681
1682 switch (extInstIndex)
1683 {
1684 case GLSLstd450FAbs:
1685 {
1686 auto src = GenericValue(this, routine, insn.word(5));
1687 for (auto i = 0u; i < type.sizeInComponents; i++)
1688 {
1689 dst.emplace(i, Abs(src[i]));
1690 }
1691 break;
1692 }
1693 case GLSLstd450SAbs:
1694 {
1695 auto src = GenericValue(this, routine, insn.word(5));
1696 for (auto i = 0u; i < type.sizeInComponents; i++)
1697 {
1698 dst.emplace(i, As<SIMD::Float>(Abs(As<SIMD::Int>(src[i]))));
1699 }
1700 break;
1701 }
Chris Forbes15dff362019-03-08 11:31:31 -08001702 case GLSLstd450Cross:
1703 {
1704 auto lhs = GenericValue(this, routine, insn.word(5));
1705 auto rhs = GenericValue(this, routine, insn.word(6));
1706 dst.emplace(0, lhs[1] * rhs[2] - rhs[1] * lhs[2]);
1707 dst.emplace(1, lhs[2] * rhs[0] - rhs[2] * lhs[0]);
1708 dst.emplace(2, lhs[0] * rhs[1] - rhs[0] * lhs[1]);
1709 break;
1710 }
Chris Forbes9667a5b2019-03-07 09:26:48 -08001711 default:
1712 UNIMPLEMENTED("Unhandled ExtInst %d", extInstIndex);
1713 }
1714 }
1715
Chris Forbes0785f692019-03-08 09:09:18 -08001716 void SpirvShader::EmitAny(InsnIterator insn, SpirvRoutine *routine) const
1717 {
1718 auto &type = getType(insn.word(1));
1719 assert(type.sizeInComponents == 1);
1720 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
1721 auto &srcType = getType(getObject(insn.word(3)).type);
1722 auto src = GenericValue(this, routine, insn.word(3));
1723
1724 SIMD::UInt result = As<SIMD::UInt>(src[0]);
1725
1726 for (auto i = 1u; i < srcType.sizeInComponents; i++)
1727 {
1728 result |= As<SIMD::UInt>(src[i]);
1729 }
1730
1731 dst.emplace(0, As<SIMD::Float>(result));
1732 }
1733
1734 void SpirvShader::EmitAll(InsnIterator insn, SpirvRoutine *routine) const
1735 {
1736 auto &type = getType(insn.word(1));
1737 assert(type.sizeInComponents == 1);
1738 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
1739 auto &srcType = getType(getObject(insn.word(3)).type);
1740 auto src = GenericValue(this, routine, insn.word(3));
1741
1742 SIMD::UInt result = As<SIMD::UInt>(src[0]);
1743
1744 for (auto i = 1u; i < srcType.sizeInComponents; i++)
1745 {
1746 result &= As<SIMD::UInt>(src[i]);
1747 }
1748
1749 dst.emplace(0, As<SIMD::Float>(result));
1750 }
1751
Chris Forbesc61271e2019-02-19 17:01:28 -08001752 void SpirvShader::emitEpilog(SpirvRoutine *routine) const
1753 {
1754 for (auto insn : *this)
1755 {
1756 switch (insn.opcode())
1757 {
1758 case spv::OpVariable:
1759 {
Ben Claytonab51bbf2019-02-20 14:36:27 +00001760 ObjectID resultId = insn.word(2);
Chris Forbesc61271e2019-02-19 17:01:28 -08001761 auto &object = getObject(resultId);
Ben Clayton9a162482019-02-25 11:54:43 +00001762 auto &objectTy = getType(object.type);
1763 if (object.kind == Object::Kind::InterfaceVariable && objectTy.storageClass == spv::StorageClassOutput)
Chris Forbesc61271e2019-02-19 17:01:28 -08001764 {
1765 auto &dst = routine->getValue(resultId);
1766 int offset = 0;
1767 VisitInterface(resultId,
1768 [&](Decorations const &d, AttribType type) {
1769 auto scalarSlot = d.Location << 2 | d.Component;
1770 routine->outputs[scalarSlot] = dst[offset++];
1771 });
1772 }
1773 break;
1774 }
1775 default:
1776 break;
1777 }
1778 }
1779 }
Ben Clayton76e9bc02019-02-26 15:02:18 +00001780
1781 SpirvRoutine::SpirvRoutine(vk::PipelineLayout const *pipelineLayout) :
1782 pipelineLayout(pipelineLayout)
1783 {
1784 }
1785
Chris Forbesc25b8072018-12-10 15:10:39 -08001786}