blob: 478910876c500f1be414f32f3f957a44040cc075 [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>
16#include "SpirvShader.hpp"
17#include "System/Math.hpp"
Chris Forbesebe5f7f2019-01-16 10:38:34 -080018#include "Vulkan/VkDebug.hpp"
Chris Forbesaf4ed532018-12-06 18:33:27 -080019#include "Device/Config.hpp"
20
21namespace sw
22{
23 volatile int SpirvShader::serialCounter = 1; // Start at 1, 0 is invalid shader.
24
Chris Forbes5839dcf2018-12-10 19:02:58 -080025 SpirvShader::SpirvShader(InsnStore const &insns)
26 : insns{insns}, inputs{MAX_INTERFACE_COMPONENTS},
27 outputs{MAX_INTERFACE_COMPONENTS},
28 serialID{serialCounter++}, modes{}
Chris Forbesaf4ed532018-12-06 18:33:27 -080029 {
30 // Simplifying assumptions (to be satisfied by earlier transformations)
Chris Forbesbde34082018-12-28 12:03:10 -080031 // - There is exactly one entrypoint in the module, and it's the one we want
Chris Forbesaf4ed532018-12-06 18:33:27 -080032 // - The only input/output OpVariables present are those used by the entrypoint
33
Chris Forbes4a979dc2019-01-17 09:36:46 -080034 for (auto insn : *this)
35 {
36 switch (insn.opcode())
37 {
38 case spv::OpExecutionMode:
39 ProcessExecutionMode(insn);
40 break;
Chris Forbesaf4ed532018-12-06 18:33:27 -080041
Chris Forbesc25b8072018-12-10 15:10:39 -080042 case spv::OpDecorate:
43 {
Ben Claytonab51bbf2019-02-20 14:36:27 +000044 TypeOrObjectID targetId = insn.word(1);
Chris Forbes93f70b32019-02-10 21:26:27 +000045 auto decoration = static_cast<spv::Decoration>(insn.word(2));
Chris Forbesc25b8072018-12-10 15:10:39 -080046 decorations[targetId].Apply(
Chris Forbes93f70b32019-02-10 21:26:27 +000047 decoration,
Chris Forbesc25b8072018-12-10 15:10:39 -080048 insn.wordCount() > 3 ? insn.word(3) : 0);
Chris Forbes93f70b32019-02-10 21:26:27 +000049
50 if (decoration == spv::DecorationCentroid)
51 modes.NeedsCentroid = true;
Chris Forbesc25b8072018-12-10 15:10:39 -080052 break;
53 }
54
55 case spv::OpMemberDecorate:
56 {
Ben Claytonab51bbf2019-02-20 14:36:27 +000057 TypeID targetId = insn.word(1);
Chris Forbesc25b8072018-12-10 15:10:39 -080058 auto memberIndex = insn.word(2);
59 auto &d = memberDecorations[targetId];
60 if (memberIndex >= d.size())
61 d.resize(memberIndex + 1); // on demand; exact size would require another pass...
Chris Forbes93f70b32019-02-10 21:26:27 +000062 auto decoration = static_cast<spv::Decoration>(insn.word(3));
Chris Forbesc25b8072018-12-10 15:10:39 -080063 d[memberIndex].Apply(
Chris Forbes93f70b32019-02-10 21:26:27 +000064 decoration,
Chris Forbesc25b8072018-12-10 15:10:39 -080065 insn.wordCount() > 4 ? insn.word(4) : 0);
Chris Forbes93f70b32019-02-10 21:26:27 +000066
67 if (decoration == spv::DecorationCentroid)
68 modes.NeedsCentroid = true;
Chris Forbesc25b8072018-12-10 15:10:39 -080069 break;
70 }
71
72 case spv::OpDecorationGroup:
73 // Nothing to do here. We don't need to record the definition of the group; we'll just have
74 // the bundle of decorations float around. If we were to ever walk the decorations directly,
75 // we might think about introducing this as a real Object.
76 break;
77
78 case spv::OpGroupDecorate:
79 {
80 auto const &srcDecorations = decorations[insn.word(1)];
81 for (auto i = 2u; i < insn.wordCount(); i++)
82 {
83 // remaining operands are targets to apply the group to.
84 decorations[insn.word(i)].Apply(srcDecorations);
85 }
86 break;
87 }
88
89 case spv::OpGroupMemberDecorate:
90 {
91 auto const &srcDecorations = decorations[insn.word(1)];
92 for (auto i = 2u; i < insn.wordCount(); i += 2)
93 {
94 // remaining operands are pairs of <id>, literal for members to apply to.
95 auto &d = memberDecorations[insn.word(i)];
96 auto memberIndex = insn.word(i + 1);
97 if (memberIndex >= d.size())
98 d.resize(memberIndex + 1); // on demand resize, see above...
99 d[memberIndex].Apply(srcDecorations);
100 }
101 break;
102 }
103
Chris Forbes4a979dc2019-01-17 09:36:46 -0800104 case spv::OpTypeVoid:
105 case spv::OpTypeBool:
106 case spv::OpTypeInt:
107 case spv::OpTypeFloat:
108 case spv::OpTypeVector:
109 case spv::OpTypeMatrix:
110 case spv::OpTypeImage:
111 case spv::OpTypeSampler:
112 case spv::OpTypeSampledImage:
113 case spv::OpTypeArray:
114 case spv::OpTypeRuntimeArray:
115 case spv::OpTypeStruct:
116 case spv::OpTypePointer:
117 case spv::OpTypeFunction:
Ben Clayton0bb83b82019-02-26 11:41:07 +0000118 DeclareType(insn);
Chris Forbes4a979dc2019-01-17 09:36:46 -0800119 break;
Chris Forbes296aa252018-12-27 11:48:21 -0800120
Chris Forbes4a979dc2019-01-17 09:36:46 -0800121 case spv::OpVariable:
122 {
Ben Claytonab51bbf2019-02-20 14:36:27 +0000123 TypeID typeId = insn.word(1);
124 ObjectID resultId = insn.word(2);
Chris Forbes4a979dc2019-01-17 09:36:46 -0800125 auto storageClass = static_cast<spv::StorageClass>(insn.word(3));
126 if (insn.wordCount() > 4)
127 UNIMPLEMENTED("Variable initializers not yet supported");
Chris Forbes296aa252018-12-27 11:48:21 -0800128
Chris Forbes4a979dc2019-01-17 09:36:46 -0800129 auto &object = defs[resultId];
130 object.kind = Object::Kind::Variable;
131 object.definition = insn;
Ben Clayton9a162482019-02-25 11:54:43 +0000132 object.type = typeId;
Chris Forbese9f8f5b2019-02-11 00:20:16 +0000133 object.pointerBase = insn.word(2); // base is itself
Chris Forbesc25b8072018-12-10 15:10:39 -0800134
135 // Register builtins
Ben Claytona1924732019-02-28 18:42:10 +0000136 if (storageClass == spv::StorageClassInput || storageClass == spv::StorageClassOutput)
Chris Forbesc25b8072018-12-10 15:10:39 -0800137 {
Ben Claytona1924732019-02-28 18:42:10 +0000138 ProcessInterfaceVariable(object);
Chris Forbesc25b8072018-12-10 15:10:39 -0800139 }
Chris Forbes4a979dc2019-01-17 09:36:46 -0800140 break;
141 }
Chris Forbes296aa252018-12-27 11:48:21 -0800142
Chris Forbesbc3a0ee2018-12-27 16:02:58 -0800143 case spv::OpConstant:
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800144 CreateConstant(insn).constantValue[0] = insn.word(3);
145 break;
Chris Forbesbc3a0ee2018-12-27 16:02:58 -0800146 case spv::OpConstantFalse:
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800147 CreateConstant(insn).constantValue[0] = 0; // represent boolean false as zero
148 break;
Chris Forbesbc3a0ee2018-12-27 16:02:58 -0800149 case spv::OpConstantTrue:
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800150 CreateConstant(insn).constantValue[0] = ~0u; // represent boolean true as all bits set
151 break;
Chris Forbesbc3a0ee2018-12-27 16:02:58 -0800152 case spv::OpConstantNull:
153 {
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800154 // OpConstantNull forms a constant of arbitrary type, all zeros.
Ben Clayton9a162482019-02-25 11:54:43 +0000155 auto &object = CreateConstant(insn);
156 auto &objectTy = getType(object.type);
157 for (auto i = 0u; i < objectTy.sizeInComponents; i++)
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800158 {
159 object.constantValue[i] = 0;
160 }
161 break;
162 }
163 case spv::OpConstantComposite:
164 {
165 auto &object = CreateConstant(insn);
166 auto offset = 0u;
167 for (auto i = 0u; i < insn.wordCount() - 3; i++)
168 {
Ben Clayton9a162482019-02-25 11:54:43 +0000169 auto &constituent = getObject(insn.word(i + 3));
170 auto &constituentTy = getType(constituent.type);
171 for (auto j = 0u; j < constituentTy.sizeInComponents; j++)
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800172 object.constantValue[offset++] = constituent.constantValue[j];
173 }
Chris Forbesbc3a0ee2018-12-27 16:02:58 -0800174 break;
175 }
176
Chris Forbesbde34082018-12-28 12:03:10 -0800177 case spv::OpCapability:
178 // Various capabilities will be declared, but none affect our code generation at this point.
179 case spv::OpMemoryModel:
180 // Memory model does not affect our code generation until we decide to do Vulkan Memory Model support.
181 case spv::OpEntryPoint:
Chris Forbes7edf5342019-02-10 22:41:21 +0000182 case spv::OpFunction:
183 case spv::OpFunctionEnd:
184 // Due to preprocessing, the entrypoint and its function provide no value.
185 break;
186 case spv::OpExtInstImport:
187 // We will only support the GLSL 450 extended instruction set, so no point in tracking the ID we assign it.
188 // Valid shaders will not attempt to import any other instruction sets.
Chris Forbes1776af72019-02-22 17:39:57 -0800189 case spv::OpName:
190 case spv::OpMemberName:
191 case spv::OpSource:
192 case spv::OpSourceContinued:
193 case spv::OpSourceExtension:
194 // No semantic impact
Chris Forbes7edf5342019-02-10 22:41:21 +0000195 break;
196
197 case spv::OpFunctionParameter:
198 case spv::OpFunctionCall:
199 case spv::OpSpecConstant:
200 case spv::OpSpecConstantComposite:
201 case spv::OpSpecConstantFalse:
202 case spv::OpSpecConstantOp:
203 case spv::OpSpecConstantTrue:
204 // These should have all been removed by preprocessing passes. If we see them here,
205 // our assumptions are wrong and we will probably generate wrong code.
206 UNIMPLEMENTED("These instructions should have already been lowered.");
207 break;
208
Chris Forbesa71b8e92019-02-10 22:42:42 +0000209 case spv::OpLoad:
210 case spv::OpAccessChain:
Chris Forbesb97a9572019-02-21 16:51:42 -0800211 case spv::OpCompositeConstruct:
Chris Forbes1bc1acf2019-02-21 18:40:33 -0800212 case spv::OpCompositeInsert:
Chris Forbesb12846d2019-02-21 18:53:58 -0800213 case spv::OpCompositeExtract:
Chris Forbes83fc5442019-02-26 22:16:07 -0800214 case spv::OpVectorShuffle:
Ben Claytondd1e37e2019-02-28 19:59:15 +0000215 case spv::OpNot: // Unary ops
216 case spv::OpSNegate:
217 case spv::OpFNegate:
218 case spv::OpLogicalNot:
219 case spv::OpIAdd: // Binary ops
220 case spv::OpISub:
221 case spv::OpIMul:
222 case spv::OpSDiv:
223 case spv::OpUDiv:
224 case spv::OpFAdd:
225 case spv::OpFSub:
226 case spv::OpFDiv:
227 case spv::OpUMod:
228 case spv::OpShiftRightLogical:
229 case spv::OpShiftRightArithmetic:
230 case spv::OpShiftLeftLogical:
231 case spv::OpBitwiseOr:
232 case spv::OpBitwiseXor:
233 case spv::OpBitwiseAnd:
234 case spv::OpLogicalOr:
235 case spv::OpLogicalAnd:
Chris Forbesa71b8e92019-02-10 22:42:42 +0000236 // Instructions that yield an ssavalue.
237 {
Ben Claytonab51bbf2019-02-20 14:36:27 +0000238 TypeID typeId = insn.word(1);
239 ObjectID resultId = insn.word(2);
Chris Forbesa71b8e92019-02-10 22:42:42 +0000240 auto &object = defs[resultId];
Ben Clayton9a162482019-02-25 11:54:43 +0000241 object.type = typeId;
Chris Forbesa71b8e92019-02-10 22:42:42 +0000242 object.kind = Object::Kind::Value;
243 object.definition = insn;
Chris Forbesa71b8e92019-02-10 22:42:42 +0000244
245 if (insn.opcode() == spv::OpAccessChain)
246 {
247 // interior ptr has two parts:
248 // - logical base ptr, common across all lanes and known at compile time
249 // - per-lane offset
Ben Clayton9a162482019-02-25 11:54:43 +0000250 ObjectID baseId = insn.word(3);
251 object.pointerBase = getObject(baseId).pointerBase;
Chris Forbesa71b8e92019-02-10 22:42:42 +0000252 }
253 break;
254 }
255
Chris Forbes7edf5342019-02-10 22:41:21 +0000256 case spv::OpStore:
257 case spv::OpReturn:
258 // Don't need to do anything during analysis pass
259 break;
260
261 case spv::OpKill:
262 modes.ContainsKill = true;
Chris Forbesbde34082018-12-28 12:03:10 -0800263 break;
264
Chris Forbes4a979dc2019-01-17 09:36:46 -0800265 default:
Ben Claytond4e4c662019-02-26 11:54:34 +0000266 printf("Warning: ignored opcode %s\n", OpcodeName(insn.opcode()).c_str());
Chris Forbes4a979dc2019-01-17 09:36:46 -0800267 break; // This is OK, these passes are intentionally partial
Chris Forbesaf4ed532018-12-06 18:33:27 -0800268 }
269 }
270 }
271
Ben Clayton0bb83b82019-02-26 11:41:07 +0000272 void SpirvShader::DeclareType(InsnIterator insn)
273 {
274 TypeID resultId = insn.word(1);
275
276 auto &type = types[resultId];
277 type.definition = insn;
278 type.sizeInComponents = ComputeTypeSize(insn);
279
280 // A structure is a builtin block if it has a builtin
281 // member. All members of such a structure are builtins.
282 switch (insn.opcode())
283 {
284 case spv::OpTypeStruct:
285 {
286 auto d = memberDecorations.find(resultId);
287 if (d != memberDecorations.end())
288 {
289 for (auto &m : d->second)
290 {
291 if (m.HasBuiltIn)
292 {
293 type.isBuiltInBlock = true;
294 break;
295 }
296 }
297 }
298 break;
299 }
300 case spv::OpTypePointer:
301 {
302 TypeID elementTypeId = insn.word(3);
303 type.element = elementTypeId;
304 type.isBuiltInBlock = getType(elementTypeId).isBuiltInBlock;
305 type.storageClass = static_cast<spv::StorageClass>(insn.word(2));
306 break;
307 }
308 case spv::OpTypeVector:
309 case spv::OpTypeMatrix:
310 case spv::OpTypeArray:
311 case spv::OpTypeRuntimeArray:
312 {
313 TypeID elementTypeId = insn.word(2);
314 type.element = elementTypeId;
315 break;
316 }
317 default:
318 break;
319 }
320 }
321
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800322 SpirvShader::Object& SpirvShader::CreateConstant(InsnIterator insn)
323 {
Ben Claytonab51bbf2019-02-20 14:36:27 +0000324 TypeID typeId = insn.word(1);
325 ObjectID resultId = insn.word(2);
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800326 auto &object = defs[resultId];
Ben Clayton9a162482019-02-25 11:54:43 +0000327 auto &objectTy = getType(typeId);
328 object.type = typeId;
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800329 object.kind = Object::Kind::Constant;
330 object.definition = insn;
Ben Clayton9a162482019-02-25 11:54:43 +0000331 object.constantValue = std::unique_ptr<uint32_t[]>(new uint32_t[objectTy.sizeInComponents]);
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800332 return object;
333 }
334
Chris Forbes049ff382019-02-02 15:16:43 -0800335 void SpirvShader::ProcessInterfaceVariable(Object &object)
Chris Forbesbde34082018-12-28 12:03:10 -0800336 {
Ben Clayton9a162482019-02-25 11:54:43 +0000337 auto &objectTy = getType(object.type);
Ben Clayton6fae32c2019-02-28 20:06:42 +0000338 ASSERT(objectTy.storageClass == spv::StorageClassInput || objectTy.storageClass == spv::StorageClassOutput);
Chris Forbesbde34082018-12-28 12:03:10 -0800339
Ben Clayton6fae32c2019-02-28 20:06:42 +0000340 ASSERT(objectTy.definition.opcode() == spv::OpTypePointer);
Ben Clayton9a162482019-02-25 11:54:43 +0000341 auto pointeeTy = getType(objectTy.element);
Chris Forbesbde34082018-12-28 12:03:10 -0800342
Ben Clayton9a162482019-02-25 11:54:43 +0000343 auto &builtinInterface = (objectTy.storageClass == spv::StorageClassInput) ? inputBuiltins : outputBuiltins;
344 auto &userDefinedInterface = (objectTy.storageClass == spv::StorageClassInput) ? inputs : outputs;
345
Ben Clayton6fae32c2019-02-28 20:06:42 +0000346 ASSERT(object.definition.opcode() == spv::OpVariable);
Ben Claytonab51bbf2019-02-20 14:36:27 +0000347 ObjectID resultId = object.definition.word(2);
Ben Clayton9a162482019-02-25 11:54:43 +0000348
349 if (objectTy.isBuiltInBlock)
Chris Forbesbde34082018-12-28 12:03:10 -0800350 {
351 // walk the builtin block, registering each of its members separately.
Ben Clayton9a162482019-02-25 11:54:43 +0000352 auto m = memberDecorations.find(objectTy.element);
Ben Clayton6fae32c2019-02-28 20:06:42 +0000353 ASSERT(m != memberDecorations.end()); // otherwise we wouldn't have marked the type chain
Ben Clayton9a162482019-02-25 11:54:43 +0000354 auto &structType = pointeeTy.definition;
Chris Forbesbde34082018-12-28 12:03:10 -0800355 auto offset = 0u;
356 auto word = 2u;
357 for (auto &member : m->second)
358 {
Chris Forbes840809a2019-01-14 14:30:20 -0800359 auto &memberType = getType(structType.word(word));
Chris Forbesbde34082018-12-28 12:03:10 -0800360
361 if (member.HasBuiltIn)
362 {
363 builtinInterface[member.BuiltIn] = {resultId, offset, memberType.sizeInComponents};
364 }
365
366 offset += memberType.sizeInComponents;
367 ++word;
368 }
369 return;
370 }
371
372 auto d = decorations.find(resultId);
373 if (d != decorations.end() && d->second.HasBuiltIn)
374 {
Ben Clayton9a162482019-02-25 11:54:43 +0000375 builtinInterface[d->second.BuiltIn] = {resultId, 0, pointeeTy.sizeInComponents};
Chris Forbesbde34082018-12-28 12:03:10 -0800376 }
377 else
378 {
Chris Forbes049ff382019-02-02 15:16:43 -0800379 object.kind = Object::Kind::InterfaceVariable;
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800380 VisitInterface(resultId,
381 [&userDefinedInterface](Decorations const &d, AttribType type) {
382 // Populate a single scalar slot in the interface from a collection of decorations and the intended component type.
383 auto scalarSlot = (d.Location << 2) | d.Component;
Ben Clayton6fae32c2019-02-28 20:06:42 +0000384 ASSERT(scalarSlot >= 0 &&
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800385 scalarSlot < static_cast<int32_t>(userDefinedInterface.size()));
386
387 auto &slot = userDefinedInterface[scalarSlot];
388 slot.Type = type;
389 slot.Flat = d.Flat;
390 slot.NoPerspective = d.NoPerspective;
391 slot.Centroid = d.Centroid;
392 });
Chris Forbesbde34082018-12-28 12:03:10 -0800393 }
394 }
395
Chris Forbesaf4ed532018-12-06 18:33:27 -0800396 void SpirvShader::ProcessExecutionMode(InsnIterator insn)
397 {
398 auto mode = static_cast<spv::ExecutionMode>(insn.word(2));
Chris Forbes4a979dc2019-01-17 09:36:46 -0800399 switch (mode)
400 {
401 case spv::ExecutionModeEarlyFragmentTests:
402 modes.EarlyFragmentTests = true;
403 break;
404 case spv::ExecutionModeDepthReplacing:
405 modes.DepthReplacing = true;
406 break;
407 case spv::ExecutionModeDepthGreater:
408 modes.DepthGreater = true;
409 break;
410 case spv::ExecutionModeDepthLess:
411 modes.DepthLess = true;
412 break;
413 case spv::ExecutionModeDepthUnchanged:
414 modes.DepthUnchanged = true;
415 break;
416 case spv::ExecutionModeLocalSize:
417 modes.LocalSizeX = insn.word(3);
418 modes.LocalSizeZ = insn.word(5);
419 modes.LocalSizeY = insn.word(4);
420 break;
421 case spv::ExecutionModeOriginUpperLeft:
422 // This is always the case for a Vulkan shader. Do nothing.
423 break;
424 default:
425 UNIMPLEMENTED("No other execution modes are permitted");
Chris Forbesaf4ed532018-12-06 18:33:27 -0800426 }
427 }
Chris Forbes739a7fb2018-12-08 13:09:40 -0800428
429 uint32_t SpirvShader::ComputeTypeSize(sw::SpirvShader::InsnIterator insn)
430 {
431 // Types are always built from the bottom up (with the exception of forward ptrs, which
432 // don't appear in Vulkan shaders. Therefore, we can always assume our component parts have
433 // already been described (and so their sizes determined)
434 switch (insn.opcode())
435 {
436 case spv::OpTypeVoid:
437 case spv::OpTypeSampler:
438 case spv::OpTypeImage:
439 case spv::OpTypeSampledImage:
440 case spv::OpTypeFunction:
441 case spv::OpTypeRuntimeArray:
442 // Objects that don't consume any space.
443 // Descriptor-backed objects currently only need exist at compile-time.
444 // Runtime arrays don't appear in places where their size would be interesting
445 return 0;
446
447 case spv::OpTypeBool:
448 case spv::OpTypeFloat:
449 case spv::OpTypeInt:
450 // All the fundamental types are 1 component. If we ever add support for 8/16/64-bit components,
451 // we might need to change this, but only 32 bit components are required for Vulkan 1.1.
452 return 1;
453
454 case spv::OpTypeVector:
455 case spv::OpTypeMatrix:
456 // Vectors and matrices both consume element count * element size.
Chris Forbes840809a2019-01-14 14:30:20 -0800457 return getType(insn.word(2)).sizeInComponents * insn.word(3);
Chris Forbes739a7fb2018-12-08 13:09:40 -0800458
459 case spv::OpTypeArray:
Chris Forbes5be4d702018-12-27 16:12:31 -0800460 {
461 // Element count * element size. Array sizes come from constant ids.
462 auto arraySize = GetConstantInt(insn.word(3));
Chris Forbes840809a2019-01-14 14:30:20 -0800463 return getType(insn.word(2)).sizeInComponents * arraySize;
Chris Forbes5be4d702018-12-27 16:12:31 -0800464 }
Chris Forbes739a7fb2018-12-08 13:09:40 -0800465
466 case spv::OpTypeStruct:
467 {
468 uint32_t size = 0;
469 for (uint32_t i = 2u; i < insn.wordCount(); i++)
470 {
Chris Forbes840809a2019-01-14 14:30:20 -0800471 size += getType(insn.word(i)).sizeInComponents;
Chris Forbes739a7fb2018-12-08 13:09:40 -0800472 }
473 return size;
474 }
475
476 case spv::OpTypePointer:
Chris Forbes0f59a2c2019-02-10 23:03:12 +0000477 // Runtime representation of a pointer is a per-lane index.
478 // Note: clients are expected to look through the pointer if they want the pointee size instead.
479 return 1;
Chris Forbes739a7fb2018-12-08 13:09:40 -0800480
481 default:
482 // Some other random insn.
483 UNIMPLEMENTED("Only types are supported");
Ben Clayton60a3d6f2019-02-26 17:24:46 +0000484 return 0;
Chris Forbes739a7fb2018-12-08 13:09:40 -0800485 }
486 }
Chris Forbesc25b8072018-12-10 15:10:39 -0800487
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800488 template<typename F>
Ben Claytonab51bbf2019-02-20 14:36:27 +0000489 int SpirvShader::VisitInterfaceInner(TypeID id, Decorations d, F f) const
Chris Forbes5839dcf2018-12-10 19:02:58 -0800490 {
491 // Recursively walks variable definition and its type tree, taking into account
492 // any explicit Location or Component decorations encountered; where explicit
493 // Locations or Components are not specified, assigns them sequentially.
494 // Collected decorations are carried down toward the leaves and across
495 // siblings; Effect of decorations intentionally does not flow back up the tree.
496 //
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800497 // F is a functor to be called with the effective decoration set for every component.
498 //
499 // Returns the next available location, and calls f().
Chris Forbes5839dcf2018-12-10 19:02:58 -0800500
501 // This covers the rules in Vulkan 1.1 spec, 14.1.4 Location Assignment.
502
Chris Forbes49d664d2019-02-12 19:24:50 +0000503 ApplyDecorationsForId(&d, id);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800504
Chris Forbes840809a2019-01-14 14:30:20 -0800505 auto const &obj = getType(id);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800506 switch (obj.definition.opcode())
507 {
Chris Forbes5839dcf2018-12-10 19:02:58 -0800508 case spv::OpTypePointer:
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800509 return VisitInterfaceInner<F>(obj.definition.word(3), d, f);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800510 case spv::OpTypeMatrix:
511 for (auto i = 0u; i < obj.definition.word(3); i++, d.Location++)
512 {
513 // consumes same components of N consecutive locations
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800514 VisitInterfaceInner<F>(obj.definition.word(2), d, f);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800515 }
516 return d.Location;
517 case spv::OpTypeVector:
518 for (auto i = 0u; i < obj.definition.word(3); i++, d.Component++)
519 {
520 // consumes N consecutive components in the same location
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800521 VisitInterfaceInner<F>(obj.definition.word(2), d, f);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800522 }
523 return d.Location + 1;
524 case spv::OpTypeFloat:
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800525 f(d, ATTRIBTYPE_FLOAT);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800526 return d.Location + 1;
527 case spv::OpTypeInt:
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800528 f(d, obj.definition.word(3) ? ATTRIBTYPE_INT : ATTRIBTYPE_UINT);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800529 return d.Location + 1;
530 case spv::OpTypeBool:
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800531 f(d, ATTRIBTYPE_UINT);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800532 return d.Location + 1;
533 case spv::OpTypeStruct:
534 {
Chris Forbes5839dcf2018-12-10 19:02:58 -0800535 // iterate over members, which may themselves have Location/Component decorations
536 for (auto i = 0u; i < obj.definition.wordCount() - 2; i++)
537 {
Chris Forbes49d664d2019-02-12 19:24:50 +0000538 ApplyDecorationsForIdMember(&d, id, i);
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800539 d.Location = VisitInterfaceInner<F>(obj.definition.word(i + 2), d, f);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800540 d.Component = 0; // Implicit locations always have component=0
541 }
542 return d.Location;
543 }
Chris Forbes5be4d702018-12-27 16:12:31 -0800544 case spv::OpTypeArray:
545 {
546 auto arraySize = GetConstantInt(obj.definition.word(3));
547 for (auto i = 0u; i < arraySize; i++)
548 {
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800549 d.Location = VisitInterfaceInner<F>(obj.definition.word(2), d, f);
Chris Forbes5be4d702018-12-27 16:12:31 -0800550 }
551 return d.Location;
552 }
Chris Forbes5839dcf2018-12-10 19:02:58 -0800553 default:
554 // Intentionally partial; most opcodes do not participate in type hierarchies
555 return 0;
556 }
557 }
558
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800559 template<typename F>
Ben Claytonab51bbf2019-02-20 14:36:27 +0000560 void SpirvShader::VisitInterface(ObjectID id, F f) const
Chris Forbes5839dcf2018-12-10 19:02:58 -0800561 {
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800562 // Walk a variable definition and call f for each component in it.
Chris Forbes5839dcf2018-12-10 19:02:58 -0800563 Decorations d{};
Chris Forbes49d664d2019-02-12 19:24:50 +0000564 ApplyDecorationsForId(&d, id);
Chris Forbes1c658232019-02-01 17:12:25 -0800565
566 auto def = getObject(id).definition;
Ben Clayton6fae32c2019-02-28 20:06:42 +0000567 ASSERT(def.opcode() == spv::OpVariable);
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800568 VisitInterfaceInner<F>(def.word(1), d, f);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800569 }
570
Ben Clayton24ea5152019-02-26 11:02:42 +0000571 SIMD::Int SpirvShader::WalkAccessChain(ObjectID id, uint32_t numIndexes, uint32_t const *indexIds, SpirvRoutine *routine) const
Chris Forbes38f85b32019-02-12 20:10:05 +0000572 {
Chris Forbes38f85b32019-02-12 20:10:05 +0000573 // TODO: think about explicit layout (UBO/SSBO) storage classes
574 // TODO: avoid doing per-lane work in some cases if we can?
575
Chris Forbes6397ed02019-02-15 16:39:17 -0800576 int constantOffset = 0;
Ben Clayton24ea5152019-02-26 11:02:42 +0000577 SIMD::Int dynamicOffset = SIMD::Int(0);
Ben Clayton9a162482019-02-25 11:54:43 +0000578 auto &baseObject = getObject(id);
579 TypeID typeId = getType(baseObject.type).element;
Chris Forbes38f85b32019-02-12 20:10:05 +0000580
Chris Forbese4ef5f72019-02-15 16:00:08 -0800581 // The <base> operand is an intermediate value itself, ie produced by a previous OpAccessChain.
582 // Start with its offset and build from there.
Chris Forbes38f85b32019-02-12 20:10:05 +0000583 if (baseObject.kind == Object::Kind::Value)
Ben Clayton24ea5152019-02-26 11:02:42 +0000584 dynamicOffset += As<SIMD::Int>(routine->getIntermediate(id)[0]);
Chris Forbes38f85b32019-02-12 20:10:05 +0000585
586 for (auto i = 0u; i < numIndexes; i++)
587 {
588 auto & type = getType(typeId);
589 switch (type.definition.opcode())
590 {
591 case spv::OpTypeStruct:
592 {
593 int memberIndex = GetConstantInt(indexIds[i]);
594 int offsetIntoStruct = 0;
595 for (auto j = 0; j < memberIndex; j++) {
Chris Forbes58bee562019-02-19 17:41:41 -0800596 auto memberType = type.definition.word(2u + j);
597 offsetIntoStruct += getType(memberType).sizeInComponents;
Chris Forbes38f85b32019-02-12 20:10:05 +0000598 }
Chris Forbes6397ed02019-02-15 16:39:17 -0800599 constantOffset += offsetIntoStruct;
Chris Forbes58bee562019-02-19 17:41:41 -0800600 typeId = type.definition.word(2u + memberIndex);
Chris Forbes38f85b32019-02-12 20:10:05 +0000601 break;
602 }
603
604 case spv::OpTypeVector:
605 case spv::OpTypeMatrix:
606 case spv::OpTypeArray:
607 {
Ben Clayton9a162482019-02-25 11:54:43 +0000608 auto stride = getType(type.element).sizeInComponents;
Chris Forbes38f85b32019-02-12 20:10:05 +0000609 auto & obj = getObject(indexIds[i]);
610 if (obj.kind == Object::Kind::Constant)
Chris Forbes6397ed02019-02-15 16:39:17 -0800611 constantOffset += stride * GetConstantInt(indexIds[i]);
Chris Forbes38f85b32019-02-12 20:10:05 +0000612 else
Ben Clayton24ea5152019-02-26 11:02:42 +0000613 dynamicOffset += SIMD::Int(stride) * As<SIMD::Int>(routine->getIntermediate(indexIds[i])[0]);
Ben Clayton9a162482019-02-25 11:54:43 +0000614 typeId = type.element;
Chris Forbes38f85b32019-02-12 20:10:05 +0000615 break;
616 }
617
618 default:
Ben Claytond4e4c662019-02-26 11:54:34 +0000619 UNIMPLEMENTED("Unexpected type '%s' in WalkAccessChain", OpcodeName(type.definition.opcode()).c_str());
Chris Forbes38f85b32019-02-12 20:10:05 +0000620 }
621 }
622
Ben Clayton24ea5152019-02-26 11:02:42 +0000623 return dynamicOffset + SIMD::Int(constantOffset);
Chris Forbes38f85b32019-02-12 20:10:05 +0000624 }
625
Chris Forbes9638b942019-02-21 18:39:31 -0800626 uint32_t SpirvShader::WalkLiteralAccessChain(TypeID typeId, uint32_t numIndexes, uint32_t const *indexes) const
627 {
628 uint32_t constantOffset = 0;
629
630 for (auto i = 0u; i < numIndexes; i++)
631 {
632 auto & type = getType(typeId);
633 switch (type.definition.opcode())
634 {
635 case spv::OpTypeStruct:
636 {
637 int memberIndex = indexes[i];
638 int offsetIntoStruct = 0;
639 for (auto j = 0; j < memberIndex; j++) {
640 auto memberType = type.definition.word(2u + j);
641 offsetIntoStruct += getType(memberType).sizeInComponents;
642 }
643 constantOffset += offsetIntoStruct;
644 typeId = type.definition.word(2u + memberIndex);
645 break;
646 }
647
648 case spv::OpTypeVector:
649 case spv::OpTypeMatrix:
650 case spv::OpTypeArray:
651 {
652 auto elementType = type.definition.word(2);
653 auto stride = getType(elementType).sizeInComponents;
654 constantOffset += stride * indexes[i];
655 typeId = elementType;
656 break;
657 }
658
659 default:
660 UNIMPLEMENTED("Unexpected type in WalkLiteralAccessChain");
661 }
662 }
663
664 return constantOffset;
665 }
666
Chris Forbesc25b8072018-12-10 15:10:39 -0800667 void SpirvShader::Decorations::Apply(spv::Decoration decoration, uint32_t arg)
668 {
669 switch (decoration)
670 {
671 case spv::DecorationLocation:
672 HasLocation = true;
673 Location = static_cast<int32_t>(arg);
674 break;
675 case spv::DecorationComponent:
676 HasComponent = true;
677 Component = arg;
678 break;
Ben Claytond073d8e2019-02-26 11:06:50 +0000679 case spv::DecorationDescriptorSet:
680 HasDescriptorSet = true;
681 DescriptorSet = arg;
682 break;
683 case spv::DecorationBinding:
684 HasBinding = true;
685 Binding = arg;
686 break;
Chris Forbesc25b8072018-12-10 15:10:39 -0800687 case spv::DecorationBuiltIn:
688 HasBuiltIn = true;
689 BuiltIn = static_cast<spv::BuiltIn>(arg);
690 break;
691 case spv::DecorationFlat:
692 Flat = true;
693 break;
694 case spv::DecorationNoPerspective:
Chris Forbes5839dcf2018-12-10 19:02:58 -0800695 NoPerspective = true;
Chris Forbesc25b8072018-12-10 15:10:39 -0800696 break;
697 case spv::DecorationCentroid:
698 Centroid = true;
699 break;
700 case spv::DecorationBlock:
701 Block = true;
702 break;
703 case spv::DecorationBufferBlock:
704 BufferBlock = true;
705 break;
706 default:
707 // Intentionally partial, there are many decorations we just don't care about.
708 break;
709 }
710 }
711
712 void SpirvShader::Decorations::Apply(const sw::SpirvShader::Decorations &src)
713 {
714 // Apply a decoration group to this set of decorations
715 if (src.HasBuiltIn)
716 {
717 HasBuiltIn = true;
718 BuiltIn = src.BuiltIn;
719 }
720
721 if (src.HasLocation)
722 {
723 HasLocation = true;
724 Location = src.Location;
725 }
726
727 if (src.HasComponent)
728 {
729 HasComponent = true;
730 Component = src.Component;
731 }
732
Ben Claytond073d8e2019-02-26 11:06:50 +0000733 if (src.HasDescriptorSet)
734 {
735 HasDescriptorSet = true;
736 DescriptorSet = src.DescriptorSet;
737 }
738
739 if (src.HasBinding)
740 {
741 HasBinding = true;
742 Binding = src.Binding;
743 }
744
Chris Forbesc25b8072018-12-10 15:10:39 -0800745 Flat |= src.Flat;
Chris Forbes5839dcf2018-12-10 19:02:58 -0800746 NoPerspective |= src.NoPerspective;
Chris Forbesc25b8072018-12-10 15:10:39 -0800747 Centroid |= src.Centroid;
748 Block |= src.Block;
749 BufferBlock |= src.BufferBlock;
750 }
Chris Forbesbc3a0ee2018-12-27 16:02:58 -0800751
Ben Claytonab51bbf2019-02-20 14:36:27 +0000752 void SpirvShader::ApplyDecorationsForId(Decorations *d, TypeOrObjectID id) const
Chris Forbes49d664d2019-02-12 19:24:50 +0000753 {
754 auto it = decorations.find(id);
755 if (it != decorations.end())
756 d->Apply(it->second);
757 }
758
Ben Claytonab51bbf2019-02-20 14:36:27 +0000759 void SpirvShader::ApplyDecorationsForIdMember(Decorations *d, TypeID id, uint32_t member) const
Chris Forbes49d664d2019-02-12 19:24:50 +0000760 {
761 auto it = memberDecorations.find(id);
762 if (it != memberDecorations.end() && member < it->second.size())
763 {
764 d->Apply(it->second[member]);
765 }
766 }
767
Ben Claytonab51bbf2019-02-20 14:36:27 +0000768 uint32_t SpirvShader::GetConstantInt(ObjectID id) const
Chris Forbesbc3a0ee2018-12-27 16:02:58 -0800769 {
770 // Slightly hackish access to constants very early in translation.
771 // General consumption of constants by other instructions should
772 // probably be just lowered to Reactor.
773
774 // TODO: not encountered yet since we only use this for array sizes etc,
775 // but is possible to construct integer constant 0 via OpConstantNull.
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800776 auto insn = getObject(id).definition;
Ben Clayton6fae32c2019-02-28 20:06:42 +0000777 ASSERT(insn.opcode() == spv::OpConstant);
778 ASSERT(getType(insn.word(1)).definition.opcode() == spv::OpTypeInt);
Chris Forbesbc3a0ee2018-12-27 16:02:58 -0800779 return insn.word(3);
780 }
Chris Forbesd5aed492019-02-02 15:18:52 -0800781
782 // emit-time
783
Chris Forbesc61271e2019-02-19 17:01:28 -0800784 void SpirvShader::emitProlog(SpirvRoutine *routine) const
Chris Forbesd5aed492019-02-02 15:18:52 -0800785 {
786 for (auto insn : *this)
787 {
788 switch (insn.opcode())
789 {
790 case spv::OpVariable:
791 {
Ben Claytonab51bbf2019-02-20 14:36:27 +0000792 ObjectID resultId = insn.word(2);
Chris Forbes0eba65b2019-02-13 12:24:35 -0800793 auto &object = getObject(resultId);
Ben Clayton9a162482019-02-25 11:54:43 +0000794 auto &objectTy = getType(object.type);
795 auto &pointeeTy = getType(objectTy.element);
Chris Forbesd5aed492019-02-02 15:18:52 -0800796 // TODO: what to do about zero-slot objects?
Ben Clayton9a162482019-02-25 11:54:43 +0000797 if (pointeeTy.sizeInComponents > 0)
Chris Forbesd5aed492019-02-02 15:18:52 -0800798 {
Ben Clayton9a162482019-02-25 11:54:43 +0000799 routine->createLvalue(insn.word(2), pointeeTy.sizeInComponents);
Chris Forbesd5aed492019-02-02 15:18:52 -0800800 }
801 break;
802 }
803 default:
Chris Forbese9f8f5b2019-02-11 00:20:16 +0000804 // Nothing else produces interface variables, so can all be safely ignored.
Chris Forbesd5aed492019-02-02 15:18:52 -0800805 break;
806 }
807 }
808 }
809
810 void SpirvShader::emit(SpirvRoutine *routine) const
811 {
Chris Forbesd5aed492019-02-02 15:18:52 -0800812 for (auto insn : *this)
813 {
814 switch (insn.opcode())
815 {
Chris Forbese53533d2019-02-21 16:49:51 -0800816 case spv::OpTypeVoid:
817 case spv::OpTypeInt:
818 case spv::OpTypeFloat:
819 case spv::OpTypeBool:
820 case spv::OpTypeVector:
821 case spv::OpTypeArray:
822 case spv::OpTypeRuntimeArray:
823 case spv::OpTypeMatrix:
824 case spv::OpTypeStruct:
825 case spv::OpTypePointer:
826 case spv::OpTypeFunction:
827 case spv::OpExecutionMode:
828 case spv::OpMemoryModel:
829 case spv::OpFunction:
830 case spv::OpFunctionEnd:
831 case spv::OpConstant:
832 case spv::OpConstantNull:
833 case spv::OpConstantTrue:
834 case spv::OpConstantFalse:
835 case spv::OpConstantComposite:
836 case spv::OpExtension:
837 case spv::OpCapability:
838 case spv::OpEntryPoint:
839 case spv::OpExtInstImport:
840 case spv::OpDecorate:
841 case spv::OpMemberDecorate:
842 case spv::OpGroupDecorate:
843 case spv::OpGroupMemberDecorate:
844 case spv::OpDecorationGroup:
Chris Forbes1776af72019-02-22 17:39:57 -0800845 case spv::OpName:
846 case spv::OpMemberName:
847 case spv::OpSource:
848 case spv::OpSourceContinued:
849 case spv::OpSourceExtension:
Chris Forbese53533d2019-02-21 16:49:51 -0800850 // Nothing to do at emit time. These are either fully handled at analysis time,
851 // or don't require any work at all.
852 break;
853
Chris Forbes0eba65b2019-02-13 12:24:35 -0800854 case spv::OpVariable:
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000855 EmitVariable(insn, routine);
Chris Forbes0eba65b2019-02-13 12:24:35 -0800856 break;
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000857
Chris Forbese9f8f5b2019-02-11 00:20:16 +0000858 case spv::OpLoad:
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000859 EmitLoad(insn, routine);
Chris Forbese9f8f5b2019-02-11 00:20:16 +0000860 break;
Chris Forbes38f85b32019-02-12 20:10:05 +0000861
Chris Forbes1c588002019-02-12 18:56:38 +0000862 case spv::OpStore:
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000863 EmitStore(insn, routine);
Chris Forbes1c588002019-02-12 18:56:38 +0000864 break;
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000865
866 case spv::OpAccessChain:
867 EmitAccessChain(insn, routine);
868 break;
869
Chris Forbesb97a9572019-02-21 16:51:42 -0800870 case spv::OpCompositeConstruct:
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000871 EmitCompositeConstruct(insn, routine);
Chris Forbesb97a9572019-02-21 16:51:42 -0800872 break;
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000873
Chris Forbes1bc1acf2019-02-21 18:40:33 -0800874 case spv::OpCompositeInsert:
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000875 EmitCompositeInsert(insn, routine);
Chris Forbes1bc1acf2019-02-21 18:40:33 -0800876 break;
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000877
Chris Forbesb12846d2019-02-21 18:53:58 -0800878 case spv::OpCompositeExtract:
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000879 EmitCompositeExtract(insn, routine);
Chris Forbesb12846d2019-02-21 18:53:58 -0800880 break;
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000881
Chris Forbes83fc5442019-02-26 22:16:07 -0800882 case spv::OpVectorShuffle:
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000883 EmitVectorShuffle(insn, routine);
Chris Forbes83fc5442019-02-26 22:16:07 -0800884 break;
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000885
Ben Claytondd1e37e2019-02-28 19:59:15 +0000886 case spv::OpNot:
887 case spv::OpSNegate:
888 case spv::OpFNegate:
889 case spv::OpLogicalNot:
890 EmitUnaryOp(insn, routine);
891 break;
892
893 case spv::OpIAdd:
894 case spv::OpISub:
895 case spv::OpIMul:
896 case spv::OpSDiv:
897 case spv::OpUDiv:
898 case spv::OpFAdd:
899 case spv::OpFSub:
900 case spv::OpFDiv:
901 case spv::OpUMod:
902 case spv::OpShiftRightLogical:
903 case spv::OpShiftRightArithmetic:
904 case spv::OpShiftLeftLogical:
905 case spv::OpBitwiseOr:
906 case spv::OpBitwiseXor:
907 case spv::OpBitwiseAnd:
908 case spv::OpLogicalOr:
909 case spv::OpLogicalAnd:
910 EmitBinaryOp(insn, routine);
911 break;
912
Chris Forbesd5aed492019-02-02 15:18:52 -0800913 default:
Ben Claytond4e4c662019-02-26 11:54:34 +0000914 printf("emit: ignoring opcode %s\n", OpcodeName(insn.opcode()).c_str());
Chris Forbesd5aed492019-02-02 15:18:52 -0800915 break;
916 }
917 }
918 }
Chris Forbesc61271e2019-02-19 17:01:28 -0800919
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000920 void SpirvShader::EmitVariable(InsnIterator insn, SpirvRoutine *routine) const
921 {
922 ObjectID resultId = insn.word(2);
923 auto &object = getObject(resultId);
924 auto &objectTy = getType(object.type);
925 if (object.kind == Object::Kind::InterfaceVariable && objectTy.storageClass == spv::StorageClassInput)
926 {
927 auto &dst = routine->getValue(resultId);
928 int offset = 0;
929 VisitInterface(resultId,
930 [&](Decorations const &d, AttribType type) {
931 auto scalarSlot = d.Location << 2 | d.Component;
932 dst[offset++] = routine->inputs[scalarSlot];
933 });
934 }
935 }
936
937 void SpirvShader::EmitLoad(InsnIterator insn, SpirvRoutine *routine) const
938 {
939 ObjectID objectId = insn.word(2);
940 ObjectID pointerId = insn.word(3);
941 auto &object = getObject(objectId);
942 auto &objectTy = getType(object.type);
943 auto &pointer = getObject(pointerId);
944 auto &pointerBase = getObject(pointer.pointerBase);
945 auto &pointerBaseTy = getType(pointerBase.type);
946
947 ASSERT(getType(pointer.type).element == object.type);
948 ASSERT(TypeID(insn.word(1)) == object.type);
949
950 if (pointerBaseTy.storageClass == spv::StorageClassImage ||
951 pointerBaseTy.storageClass == spv::StorageClassUniform ||
952 pointerBaseTy.storageClass == spv::StorageClassUniformConstant)
953 {
954 UNIMPLEMENTED("Descriptor-backed load not yet implemented");
955 }
956
957 auto &ptrBase = routine->getValue(pointer.pointerBase);
958 auto &dst = routine->createIntermediate(objectId, objectTy.sizeInComponents);
959
960 if (pointer.kind == Object::Kind::Value)
961 {
962 auto offsets = As<SIMD::Int>(routine->getIntermediate(insn.word(3))[0]);
963 for (auto i = 0u; i < objectTy.sizeInComponents; i++)
964 {
965 // i wish i had a Float,Float,Float,Float constructor here..
966 SIMD::Float v;
967 for (int j = 0; j < SIMD::Width; j++)
968 {
969 Int offset = Int(i) + Extract(offsets, j);
970 v = Insert(v, Extract(ptrBase[offset], j), j);
971 }
972 dst.emplace(i, v);
973 }
974 }
975 else
976 {
977 // no divergent offsets to worry about
978 for (auto i = 0u; i < objectTy.sizeInComponents; i++)
979 {
980 dst.emplace(i, ptrBase[i]);
981 }
982 }
983 }
984
985 void SpirvShader::EmitAccessChain(InsnIterator insn, SpirvRoutine *routine) const
986 {
987 TypeID typeId = insn.word(1);
988 ObjectID objectId = insn.word(2);
989 ObjectID baseId = insn.word(3);
990 auto &object = getObject(objectId);
991 auto &type = getType(typeId);
992 auto &pointerBase = getObject(object.pointerBase);
993 auto &pointerBaseTy = getType(pointerBase.type);
994 ASSERT(type.sizeInComponents == 1);
995 ASSERT(getObject(baseId).pointerBase == object.pointerBase);
996
997 if (pointerBaseTy.storageClass == spv::StorageClassImage ||
998 pointerBaseTy.storageClass == spv::StorageClassUniform ||
999 pointerBaseTy.storageClass == spv::StorageClassUniformConstant)
1000 {
1001 UNIMPLEMENTED("Descriptor-backed OpAccessChain not yet implemented");
1002 }
1003 auto &dst = routine->createIntermediate(objectId, type.sizeInComponents);
1004 dst.emplace(0, As<SIMD::Float>(WalkAccessChain(baseId, insn.wordCount() - 4, insn.wordPointer(4), routine)));
1005 }
1006
1007 void SpirvShader::EmitStore(InsnIterator insn, SpirvRoutine *routine) const
1008 {
1009 ObjectID pointerId = insn.word(1);
1010 ObjectID objectId = insn.word(2);
1011 auto &object = getObject(objectId);
1012 auto &pointer = getObject(pointerId);
1013 auto &pointerTy = getType(pointer.type);
1014 auto &elementTy = getType(pointerTy.element);
1015 auto &pointerBase = getObject(pointer.pointerBase);
1016 auto &pointerBaseTy = getType(pointerBase.type);
1017
1018 if (pointerBaseTy.storageClass == spv::StorageClassImage ||
1019 pointerBaseTy.storageClass == spv::StorageClassUniform ||
1020 pointerBaseTy.storageClass == spv::StorageClassUniformConstant)
1021 {
1022 UNIMPLEMENTED("Descriptor-backed store not yet implemented");
1023 }
1024
1025 auto &ptrBase = routine->getValue(pointer.pointerBase);
1026
1027 if (object.kind == Object::Kind::Constant)
1028 {
1029 auto src = reinterpret_cast<float *>(object.constantValue.get());
1030
1031 if (pointer.kind == Object::Kind::Value)
1032 {
1033 auto offsets = As<SIMD::Int>(routine->getIntermediate(pointerId)[0]);
1034 for (auto i = 0u; i < elementTy.sizeInComponents; i++)
1035 {
1036 // Scattered store
1037 for (int j = 0; j < SIMD::Width; j++)
1038 {
1039 auto dst = ptrBase[Int(i) + Extract(offsets, j)];
1040 dst = Insert(dst, Float(src[i]), j);
1041 }
1042 }
1043 }
1044 else
1045 {
1046 // no divergent offsets
1047 for (auto i = 0u; i < elementTy.sizeInComponents; i++)
1048 {
1049 ptrBase[i] = RValue<SIMD::Float>(src[i]);
1050 }
1051 }
1052 }
1053 else
1054 {
1055 auto &src = routine->getIntermediate(objectId);
1056
1057 if (pointer.kind == Object::Kind::Value)
1058 {
1059 auto offsets = As<SIMD::Int>(routine->getIntermediate(pointerId)[0]);
1060 for (auto i = 0u; i < elementTy.sizeInComponents; i++)
1061 {
1062 // Scattered store
1063 for (int j = 0; j < SIMD::Width; j++)
1064 {
1065 auto dst = ptrBase[Int(i) + Extract(offsets, j)];
1066 dst = Insert(dst, Extract(src[i], j), j);
1067 }
1068 }
1069 }
1070 else
1071 {
1072 // no divergent offsets
1073 for (auto i = 0u; i < elementTy.sizeInComponents; i++)
1074 {
1075 ptrBase[i] = src[i];
1076 }
1077 }
1078 }
1079 }
1080
1081 void SpirvShader::EmitCompositeConstruct(InsnIterator insn, SpirvRoutine *routine) const
1082 {
1083 auto &type = getType(insn.word(1));
1084 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
1085 auto offset = 0u;
1086
1087 for (auto i = 0u; i < insn.wordCount() - 3; i++)
1088 {
1089 ObjectID srcObjectId = insn.word(3u + i);
1090 auto & srcObject = getObject(srcObjectId);
1091 auto & srcObjectTy = getType(srcObject.type);
1092 GenericValue srcObjectAccess(this, routine, srcObjectId);
1093
1094 for (auto j = 0u; j < srcObjectTy.sizeInComponents; j++)
1095 dst.emplace(offset++, srcObjectAccess[j]);
1096 }
1097 }
1098
1099 void SpirvShader::EmitCompositeInsert(InsnIterator insn, SpirvRoutine *routine) const
1100 {
1101 TypeID resultTypeId = insn.word(1);
1102 auto &type = getType(resultTypeId);
1103 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
1104 auto &newPartObject = getObject(insn.word(3));
1105 auto &newPartObjectTy = getType(newPartObject.type);
1106 auto firstNewComponent = WalkLiteralAccessChain(resultTypeId, insn.wordCount() - 5, insn.wordPointer(5));
1107
1108 GenericValue srcObjectAccess(this, routine, insn.word(4));
1109 GenericValue newPartObjectAccess(this, routine, insn.word(3));
1110
1111 // old components before
1112 for (auto i = 0u; i < firstNewComponent; i++)
1113 {
1114 dst.emplace(i, srcObjectAccess[i]);
1115 }
1116 // new part
1117 for (auto i = 0u; i < newPartObjectTy.sizeInComponents; i++)
1118 {
1119 dst.emplace(firstNewComponent + i, newPartObjectAccess[i]);
1120 }
1121 // old components after
1122 for (auto i = firstNewComponent + newPartObjectTy.sizeInComponents; i < type.sizeInComponents; i++)
1123 {
1124 dst.emplace(i, srcObjectAccess[i]);
1125 }
1126 }
1127
1128 void SpirvShader::EmitCompositeExtract(InsnIterator insn, SpirvRoutine *routine) const
1129 {
1130 auto &type = getType(insn.word(1));
1131 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
1132 auto &compositeObject = getObject(insn.word(3));
1133 TypeID compositeTypeId = compositeObject.definition.word(1);
1134 auto firstComponent = WalkLiteralAccessChain(compositeTypeId, insn.wordCount() - 4, insn.wordPointer(4));
1135
1136 GenericValue compositeObjectAccess(this, routine, insn.word(3));
1137 for (auto i = 0u; i < type.sizeInComponents; i++)
1138 {
1139 dst.emplace(i, compositeObjectAccess[firstComponent + i]);
1140 }
1141 }
1142
1143 void SpirvShader::EmitVectorShuffle(InsnIterator insn, SpirvRoutine *routine) const
1144 {
1145 auto &type = getType(insn.word(1));
1146 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
1147
1148 GenericValue firstHalfAccess(this, routine, insn.word(3));
1149 GenericValue secondHalfAccess(this, routine, insn.word(4));
1150
1151 for (auto i = 0u; i < type.sizeInComponents; i++)
1152 {
1153 auto selector = insn.word(5 + i);
1154 if (selector == static_cast<uint32_t>(-1))
1155 {
1156 // Undefined value. Until we decide to do real undef values, zero is as good
1157 // a value as any
1158 dst.emplace(i, RValue<SIMD::Float>(0.0f));
1159 }
1160 else if (selector < type.sizeInComponents)
1161 {
1162 dst.emplace(i, firstHalfAccess[selector]);
1163 }
1164 else
1165 {
1166 dst.emplace(i, secondHalfAccess[selector - type.sizeInComponents]);
1167 }
1168 }
1169 }
1170
Ben Claytondd1e37e2019-02-28 19:59:15 +00001171 void SpirvShader::EmitUnaryOp(InsnIterator insn, SpirvRoutine *routine) const
1172 {
1173 auto &type = getType(insn.word(1));
1174 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
1175 auto src = GenericValue(this, routine, insn.word(3));
1176
1177 for (auto i = 0u; i < type.sizeInComponents; i++)
1178 {
1179 auto val = src[i];
1180
1181 switch (insn.opcode())
1182 {
1183 case spv::OpNot:
1184 case spv::OpLogicalNot: // logical not == bitwise not due to all-bits boolean representation
1185 dst.emplace(i, As<SIMD::Float>(~As<SIMD::UInt>(val)));
1186 break;
1187 case spv::OpSNegate:
1188 dst.emplace(i, As<SIMD::Float>(-As<SIMD::Int>(val)));
1189 break;
1190 case spv::OpFNegate:
1191 dst.emplace(i, -val);
1192 break;
1193 default:
1194 UNIMPLEMENTED("Unhandled unary operator %s", OpcodeName(insn.opcode()).c_str());
1195 }
1196 }
1197 }
1198
1199 void SpirvShader::EmitBinaryOp(InsnIterator insn, SpirvRoutine *routine) const
1200 {
1201 auto &type = getType(insn.word(1));
1202 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
1203 auto srcLHS = GenericValue(this, routine, insn.word(3));
1204 auto srcRHS = GenericValue(this, routine, insn.word(4));
1205
1206 for (auto i = 0u; i < type.sizeInComponents; i++)
1207 {
1208 auto lhs = srcLHS[i];
1209 auto rhs = srcRHS[i];
1210
1211 switch (insn.opcode())
1212 {
1213 case spv::OpIAdd:
1214 dst.emplace(i, As<SIMD::Float>(As<SIMD::Int>(lhs) + As<SIMD::Int>(rhs)));
1215 break;
1216 case spv::OpISub:
1217 dst.emplace(i, As<SIMD::Float>(As<SIMD::Int>(lhs) - As<SIMD::Int>(rhs)));
1218 break;
1219 case spv::OpIMul:
1220 dst.emplace(i, As<SIMD::Float>(As<SIMD::Int>(lhs) * As<SIMD::Int>(rhs)));
1221 break;
1222 case spv::OpSDiv:
1223 dst.emplace(i, As<SIMD::Float>(As<SIMD::Int>(lhs) / As<SIMD::Int>(rhs)));
1224 break;
1225 case spv::OpUDiv:
1226 dst.emplace(i, As<SIMD::Float>(As<SIMD::UInt>(lhs) / As<SIMD::UInt>(rhs)));
1227 break;
1228 case spv::OpUMod:
1229 dst.emplace(i, As<SIMD::Float>(As<SIMD::UInt>(lhs) % As<SIMD::UInt>(rhs)));
1230 break;
1231 case spv::OpFAdd:
1232 dst.emplace(i, lhs + rhs);
1233 break;
1234 case spv::OpFSub:
1235 dst.emplace(i, lhs - rhs);
1236 break;
1237 case spv::OpFDiv:
1238 dst.emplace(i, lhs / rhs);
1239 break;
1240 case spv::OpShiftRightLogical:
1241 dst.emplace(i, As<SIMD::Float>(As<SIMD::UInt>(lhs) >> As<SIMD::UInt>(rhs)));
1242 break;
1243 case spv::OpShiftRightArithmetic:
1244 dst.emplace(i, As<SIMD::Float>(As<SIMD::Int>(lhs) >> As<SIMD::Int>(rhs)));
1245 break;
1246 case spv::OpShiftLeftLogical:
1247 dst.emplace(i, As<SIMD::Float>(As<SIMD::UInt>(lhs) << As<SIMD::UInt>(rhs)));
1248 break;
1249 case spv::OpBitwiseOr:
1250 case spv::OpLogicalOr:
1251 dst.emplace(i, As<SIMD::Float>(As<SIMD::UInt>(lhs) | As<SIMD::UInt>(rhs)));
1252 break;
1253 case spv::OpBitwiseXor:
1254 dst.emplace(i, As<SIMD::Float>(As<SIMD::UInt>(lhs) ^ As<SIMD::UInt>(rhs)));
1255 break;
1256 case spv::OpBitwiseAnd:
1257 case spv::OpLogicalAnd:
1258 dst.emplace(i, As<SIMD::Float>(As<SIMD::UInt>(lhs) & As<SIMD::UInt>(rhs)));
1259 break;
1260 default:
1261 UNIMPLEMENTED("Unhandled binary operator %s", OpcodeName(insn.opcode()).c_str());
1262 }
1263 }
1264 }
1265
Chris Forbesc61271e2019-02-19 17:01:28 -08001266 void SpirvShader::emitEpilog(SpirvRoutine *routine) const
1267 {
1268 for (auto insn : *this)
1269 {
1270 switch (insn.opcode())
1271 {
1272 case spv::OpVariable:
1273 {
Ben Claytonab51bbf2019-02-20 14:36:27 +00001274 ObjectID resultId = insn.word(2);
Chris Forbesc61271e2019-02-19 17:01:28 -08001275 auto &object = getObject(resultId);
Ben Clayton9a162482019-02-25 11:54:43 +00001276 auto &objectTy = getType(object.type);
1277 if (object.kind == Object::Kind::InterfaceVariable && objectTy.storageClass == spv::StorageClassOutput)
Chris Forbesc61271e2019-02-19 17:01:28 -08001278 {
1279 auto &dst = routine->getValue(resultId);
1280 int offset = 0;
1281 VisitInterface(resultId,
1282 [&](Decorations const &d, AttribType type) {
1283 auto scalarSlot = d.Location << 2 | d.Component;
1284 routine->outputs[scalarSlot] = dst[offset++];
1285 });
1286 }
1287 break;
1288 }
1289 default:
1290 break;
1291 }
1292 }
1293 }
Chris Forbesc25b8072018-12-10 15:10:39 -08001294}