blob: ff5d7d6cbba6351769a749be95f761027e0bac3c [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"
Ben Clayton76e9bc02019-02-26 15:02:18 +000019#include "Vulkan/VkPipelineLayout.hpp"
Chris Forbesaf4ed532018-12-06 18:33:27 -080020#include "Device/Config.hpp"
21
22namespace sw
23{
24 volatile int SpirvShader::serialCounter = 1; // Start at 1, 0 is invalid shader.
25
Chris Forbes5839dcf2018-12-10 19:02:58 -080026 SpirvShader::SpirvShader(InsnStore const &insns)
27 : insns{insns}, inputs{MAX_INTERFACE_COMPONENTS},
28 outputs{MAX_INTERFACE_COMPONENTS},
29 serialID{serialCounter++}, modes{}
Chris Forbesaf4ed532018-12-06 18:33:27 -080030 {
Ben Clayton45faa082019-03-05 13:20:40 +000031 ASSERT(insns.size() > 0);
32
Chris Forbesaf4ed532018-12-06 18:33:27 -080033 // Simplifying assumptions (to be satisfied by earlier transformations)
Chris Forbesbde34082018-12-28 12:03:10 -080034 // - There is exactly one entrypoint in the module, and it's the one we want
Chris Forbesaf4ed532018-12-06 18:33:27 -080035 // - The only input/output OpVariables present are those used by the entrypoint
36
Chris Forbese57f10e2019-03-04 10:53:07 -080037 // TODO: Add real support for control flow. For now, track whether we've seen
38 // a label or a return already (if so, the shader does things we will mishandle).
39 // We expect there to be one of each in a simple shader -- the first and last instruction
40 // of the entrypoint function.
41 bool seenLabel = false;
42 bool seenReturn = false;
43
Chris Forbes4a979dc2019-01-17 09:36:46 -080044 for (auto insn : *this)
45 {
46 switch (insn.opcode())
47 {
48 case spv::OpExecutionMode:
49 ProcessExecutionMode(insn);
50 break;
Chris Forbesaf4ed532018-12-06 18:33:27 -080051
Chris Forbesc25b8072018-12-10 15:10:39 -080052 case spv::OpDecorate:
53 {
Ben Claytonab51bbf2019-02-20 14:36:27 +000054 TypeOrObjectID targetId = insn.word(1);
Chris Forbes93f70b32019-02-10 21:26:27 +000055 auto decoration = static_cast<spv::Decoration>(insn.word(2));
Chris Forbesc25b8072018-12-10 15:10:39 -080056 decorations[targetId].Apply(
Chris Forbes93f70b32019-02-10 21:26:27 +000057 decoration,
Chris Forbesc25b8072018-12-10 15:10:39 -080058 insn.wordCount() > 3 ? insn.word(3) : 0);
Chris Forbes93f70b32019-02-10 21:26:27 +000059
60 if (decoration == spv::DecorationCentroid)
61 modes.NeedsCentroid = true;
Chris Forbesc25b8072018-12-10 15:10:39 -080062 break;
63 }
64
65 case spv::OpMemberDecorate:
66 {
Ben Claytonab51bbf2019-02-20 14:36:27 +000067 TypeID targetId = insn.word(1);
Chris Forbesc25b8072018-12-10 15:10:39 -080068 auto memberIndex = insn.word(2);
69 auto &d = memberDecorations[targetId];
70 if (memberIndex >= d.size())
71 d.resize(memberIndex + 1); // on demand; exact size would require another pass...
Chris Forbes93f70b32019-02-10 21:26:27 +000072 auto decoration = static_cast<spv::Decoration>(insn.word(3));
Chris Forbesc25b8072018-12-10 15:10:39 -080073 d[memberIndex].Apply(
Chris Forbes93f70b32019-02-10 21:26:27 +000074 decoration,
Chris Forbesc25b8072018-12-10 15:10:39 -080075 insn.wordCount() > 4 ? insn.word(4) : 0);
Chris Forbes93f70b32019-02-10 21:26:27 +000076
77 if (decoration == spv::DecorationCentroid)
78 modes.NeedsCentroid = true;
Chris Forbesc25b8072018-12-10 15:10:39 -080079 break;
80 }
81
82 case spv::OpDecorationGroup:
83 // Nothing to do here. We don't need to record the definition of the group; we'll just have
84 // the bundle of decorations float around. If we were to ever walk the decorations directly,
85 // we might think about introducing this as a real Object.
86 break;
87
88 case spv::OpGroupDecorate:
89 {
90 auto const &srcDecorations = decorations[insn.word(1)];
91 for (auto i = 2u; i < insn.wordCount(); i++)
92 {
93 // remaining operands are targets to apply the group to.
94 decorations[insn.word(i)].Apply(srcDecorations);
95 }
96 break;
97 }
98
99 case spv::OpGroupMemberDecorate:
100 {
101 auto const &srcDecorations = decorations[insn.word(1)];
102 for (auto i = 2u; i < insn.wordCount(); i += 2)
103 {
104 // remaining operands are pairs of <id>, literal for members to apply to.
105 auto &d = memberDecorations[insn.word(i)];
106 auto memberIndex = insn.word(i + 1);
107 if (memberIndex >= d.size())
108 d.resize(memberIndex + 1); // on demand resize, see above...
109 d[memberIndex].Apply(srcDecorations);
110 }
111 break;
112 }
113
Chris Forbese57f10e2019-03-04 10:53:07 -0800114 case spv::OpLabel:
115 if (seenLabel)
116 UNIMPLEMENTED("Shader contains multiple labels, has control flow");
117 seenLabel = true;
118 break;
119
120 case spv::OpReturn:
121 if (seenReturn)
122 UNIMPLEMENTED("Shader contains multiple returns, has control flow");
123 seenReturn = true;
124 break;
125
Chris Forbes4a979dc2019-01-17 09:36:46 -0800126 case spv::OpTypeVoid:
127 case spv::OpTypeBool:
128 case spv::OpTypeInt:
129 case spv::OpTypeFloat:
130 case spv::OpTypeVector:
131 case spv::OpTypeMatrix:
132 case spv::OpTypeImage:
133 case spv::OpTypeSampler:
134 case spv::OpTypeSampledImage:
135 case spv::OpTypeArray:
136 case spv::OpTypeRuntimeArray:
137 case spv::OpTypeStruct:
138 case spv::OpTypePointer:
139 case spv::OpTypeFunction:
Ben Clayton0bb83b82019-02-26 11:41:07 +0000140 DeclareType(insn);
Chris Forbes4a979dc2019-01-17 09:36:46 -0800141 break;
Chris Forbes296aa252018-12-27 11:48:21 -0800142
Chris Forbes4a979dc2019-01-17 09:36:46 -0800143 case spv::OpVariable:
144 {
Ben Claytonab51bbf2019-02-20 14:36:27 +0000145 TypeID typeId = insn.word(1);
146 ObjectID resultId = insn.word(2);
Chris Forbes4a979dc2019-01-17 09:36:46 -0800147 auto storageClass = static_cast<spv::StorageClass>(insn.word(3));
148 if (insn.wordCount() > 4)
149 UNIMPLEMENTED("Variable initializers not yet supported");
Chris Forbes296aa252018-12-27 11:48:21 -0800150
Chris Forbes4a979dc2019-01-17 09:36:46 -0800151 auto &object = defs[resultId];
152 object.kind = Object::Kind::Variable;
153 object.definition = insn;
Ben Clayton9a162482019-02-25 11:54:43 +0000154 object.type = typeId;
Chris Forbese9f8f5b2019-02-11 00:20:16 +0000155 object.pointerBase = insn.word(2); // base is itself
Chris Forbesc25b8072018-12-10 15:10:39 -0800156
157 // Register builtins
Ben Claytona1924732019-02-28 18:42:10 +0000158 if (storageClass == spv::StorageClassInput || storageClass == spv::StorageClassOutput)
Chris Forbesc25b8072018-12-10 15:10:39 -0800159 {
Ben Claytona1924732019-02-28 18:42:10 +0000160 ProcessInterfaceVariable(object);
Chris Forbesc25b8072018-12-10 15:10:39 -0800161 }
Chris Forbes4a979dc2019-01-17 09:36:46 -0800162 break;
163 }
Chris Forbes296aa252018-12-27 11:48:21 -0800164
Chris Forbesbc3a0ee2018-12-27 16:02:58 -0800165 case spv::OpConstant:
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800166 CreateConstant(insn).constantValue[0] = insn.word(3);
167 break;
Chris Forbesbc3a0ee2018-12-27 16:02:58 -0800168 case spv::OpConstantFalse:
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800169 CreateConstant(insn).constantValue[0] = 0; // represent boolean false as zero
170 break;
Chris Forbesbc3a0ee2018-12-27 16:02:58 -0800171 case spv::OpConstantTrue:
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800172 CreateConstant(insn).constantValue[0] = ~0u; // represent boolean true as all bits set
173 break;
Chris Forbesbc3a0ee2018-12-27 16:02:58 -0800174 case spv::OpConstantNull:
175 {
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800176 // OpConstantNull forms a constant of arbitrary type, all zeros.
Ben Clayton9a162482019-02-25 11:54:43 +0000177 auto &object = CreateConstant(insn);
178 auto &objectTy = getType(object.type);
179 for (auto i = 0u; i < objectTy.sizeInComponents; i++)
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800180 {
181 object.constantValue[i] = 0;
182 }
183 break;
184 }
185 case spv::OpConstantComposite:
186 {
187 auto &object = CreateConstant(insn);
188 auto offset = 0u;
189 for (auto i = 0u; i < insn.wordCount() - 3; i++)
190 {
Ben Clayton9a162482019-02-25 11:54:43 +0000191 auto &constituent = getObject(insn.word(i + 3));
192 auto &constituentTy = getType(constituent.type);
193 for (auto j = 0u; j < constituentTy.sizeInComponents; j++)
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800194 object.constantValue[offset++] = constituent.constantValue[j];
195 }
Chris Forbesbc3a0ee2018-12-27 16:02:58 -0800196 break;
197 }
198
Chris Forbesbde34082018-12-28 12:03:10 -0800199 case spv::OpCapability:
200 // Various capabilities will be declared, but none affect our code generation at this point.
201 case spv::OpMemoryModel:
202 // Memory model does not affect our code generation until we decide to do Vulkan Memory Model support.
203 case spv::OpEntryPoint:
Chris Forbes7edf5342019-02-10 22:41:21 +0000204 case spv::OpFunction:
205 case spv::OpFunctionEnd:
206 // Due to preprocessing, the entrypoint and its function provide no value.
207 break;
208 case spv::OpExtInstImport:
209 // We will only support the GLSL 450 extended instruction set, so no point in tracking the ID we assign it.
210 // Valid shaders will not attempt to import any other instruction sets.
Chris Forbes1776af72019-02-22 17:39:57 -0800211 case spv::OpName:
212 case spv::OpMemberName:
213 case spv::OpSource:
214 case spv::OpSourceContinued:
215 case spv::OpSourceExtension:
216 // No semantic impact
Chris Forbes7edf5342019-02-10 22:41:21 +0000217 break;
218
219 case spv::OpFunctionParameter:
220 case spv::OpFunctionCall:
221 case spv::OpSpecConstant:
222 case spv::OpSpecConstantComposite:
223 case spv::OpSpecConstantFalse:
224 case spv::OpSpecConstantOp:
225 case spv::OpSpecConstantTrue:
226 // These should have all been removed by preprocessing passes. If we see them here,
227 // our assumptions are wrong and we will probably generate wrong code.
228 UNIMPLEMENTED("These instructions should have already been lowered.");
229 break;
230
Chris Forbes4d503052019-03-01 17:13:57 -0800231 case spv::OpFConvert:
232 case spv::OpSConvert:
233 case spv::OpUConvert:
234 UNIMPLEMENTED("No valid uses for Op*Convert until we support multiple bit widths");
235 break;
236
Chris Forbesa71b8e92019-02-10 22:42:42 +0000237 case spv::OpLoad:
238 case spv::OpAccessChain:
Chris Forbesb97a9572019-02-21 16:51:42 -0800239 case spv::OpCompositeConstruct:
Chris Forbes1bc1acf2019-02-21 18:40:33 -0800240 case spv::OpCompositeInsert:
Chris Forbesb12846d2019-02-21 18:53:58 -0800241 case spv::OpCompositeExtract:
Chris Forbes83fc5442019-02-26 22:16:07 -0800242 case spv::OpVectorShuffle:
Ben Claytondd1e37e2019-02-28 19:59:15 +0000243 case spv::OpNot: // Unary ops
244 case spv::OpSNegate:
245 case spv::OpFNegate:
246 case spv::OpLogicalNot:
247 case spv::OpIAdd: // Binary ops
248 case spv::OpISub:
249 case spv::OpIMul:
250 case spv::OpSDiv:
251 case spv::OpUDiv:
252 case spv::OpFAdd:
253 case spv::OpFSub:
254 case spv::OpFDiv:
Ben Claytonec1aeb82019-03-04 19:33:27 +0000255 case spv::OpFOrdEqual:
256 case spv::OpFUnordEqual:
257 case spv::OpFOrdNotEqual:
258 case spv::OpFUnordNotEqual:
259 case spv::OpFOrdLessThan:
260 case spv::OpFUnordLessThan:
261 case spv::OpFOrdGreaterThan:
262 case spv::OpFUnordGreaterThan:
263 case spv::OpFOrdLessThanEqual:
264 case spv::OpFUnordLessThanEqual:
265 case spv::OpFOrdGreaterThanEqual:
266 case spv::OpFUnordGreaterThanEqual:
Ben Claytondd1e37e2019-02-28 19:59:15 +0000267 case spv::OpUMod:
Ben Claytone95eeb12019-03-04 16:32:09 +0000268 case spv::OpIEqual:
269 case spv::OpINotEqual:
270 case spv::OpUGreaterThan:
271 case spv::OpSGreaterThan:
272 case spv::OpUGreaterThanEqual:
273 case spv::OpSGreaterThanEqual:
274 case spv::OpULessThan:
275 case spv::OpSLessThan:
276 case spv::OpULessThanEqual:
277 case spv::OpSLessThanEqual:
Ben Claytondd1e37e2019-02-28 19:59:15 +0000278 case spv::OpShiftRightLogical:
279 case spv::OpShiftRightArithmetic:
280 case spv::OpShiftLeftLogical:
281 case spv::OpBitwiseOr:
282 case spv::OpBitwiseXor:
283 case spv::OpBitwiseAnd:
284 case spv::OpLogicalOr:
285 case spv::OpLogicalAnd:
Chris Forbese86b6dc2019-03-01 09:08:47 -0800286 case spv::OpUMulExtended:
287 case spv::OpSMulExtended:
Chris Forbes2b287cc2019-03-01 13:24:17 -0800288 case spv::OpDot:
Chris Forbes4d503052019-03-01 17:13:57 -0800289 case spv::OpConvertFToU:
290 case spv::OpConvertFToS:
291 case spv::OpConvertSToF:
292 case spv::OpConvertUToF:
293 case spv::OpBitcast:
Ben Claytonbf943f62019-03-05 12:57:39 +0000294 case spv::OpSelect:
Chris Forbese86b6dc2019-03-01 09:08:47 -0800295 // Instructions that yield an intermediate value
Chris Forbesa71b8e92019-02-10 22:42:42 +0000296 {
Ben Claytonab51bbf2019-02-20 14:36:27 +0000297 TypeID typeId = insn.word(1);
298 ObjectID resultId = insn.word(2);
Chris Forbesa71b8e92019-02-10 22:42:42 +0000299 auto &object = defs[resultId];
Ben Clayton9a162482019-02-25 11:54:43 +0000300 object.type = typeId;
Chris Forbesa71b8e92019-02-10 22:42:42 +0000301 object.kind = Object::Kind::Value;
302 object.definition = insn;
Chris Forbesa71b8e92019-02-10 22:42:42 +0000303
304 if (insn.opcode() == spv::OpAccessChain)
305 {
306 // interior ptr has two parts:
307 // - logical base ptr, common across all lanes and known at compile time
308 // - per-lane offset
Ben Clayton9a162482019-02-25 11:54:43 +0000309 ObjectID baseId = insn.word(3);
310 object.pointerBase = getObject(baseId).pointerBase;
Chris Forbesa71b8e92019-02-10 22:42:42 +0000311 }
312 break;
313 }
314
Chris Forbes7edf5342019-02-10 22:41:21 +0000315 case spv::OpStore:
Chris Forbes7edf5342019-02-10 22:41:21 +0000316 // Don't need to do anything during analysis pass
317 break;
318
319 case spv::OpKill:
320 modes.ContainsKill = true;
Chris Forbesbde34082018-12-28 12:03:10 -0800321 break;
322
Chris Forbes4a979dc2019-01-17 09:36:46 -0800323 default:
Chris Forbese57f10e2019-03-04 10:53:07 -0800324 UNIMPLEMENTED(OpcodeName(insn.opcode()).c_str());
Chris Forbesaf4ed532018-12-06 18:33:27 -0800325 }
326 }
327 }
328
Ben Clayton0bb83b82019-02-26 11:41:07 +0000329 void SpirvShader::DeclareType(InsnIterator insn)
330 {
331 TypeID resultId = insn.word(1);
332
333 auto &type = types[resultId];
334 type.definition = insn;
335 type.sizeInComponents = ComputeTypeSize(insn);
336
337 // A structure is a builtin block if it has a builtin
338 // member. All members of such a structure are builtins.
339 switch (insn.opcode())
340 {
341 case spv::OpTypeStruct:
342 {
343 auto d = memberDecorations.find(resultId);
344 if (d != memberDecorations.end())
345 {
346 for (auto &m : d->second)
347 {
348 if (m.HasBuiltIn)
349 {
350 type.isBuiltInBlock = true;
351 break;
352 }
353 }
354 }
355 break;
356 }
357 case spv::OpTypePointer:
358 {
359 TypeID elementTypeId = insn.word(3);
360 type.element = elementTypeId;
361 type.isBuiltInBlock = getType(elementTypeId).isBuiltInBlock;
362 type.storageClass = static_cast<spv::StorageClass>(insn.word(2));
363 break;
364 }
365 case spv::OpTypeVector:
366 case spv::OpTypeMatrix:
367 case spv::OpTypeArray:
368 case spv::OpTypeRuntimeArray:
369 {
370 TypeID elementTypeId = insn.word(2);
371 type.element = elementTypeId;
372 break;
373 }
374 default:
375 break;
376 }
377 }
378
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800379 SpirvShader::Object& SpirvShader::CreateConstant(InsnIterator insn)
380 {
Ben Claytonab51bbf2019-02-20 14:36:27 +0000381 TypeID typeId = insn.word(1);
382 ObjectID resultId = insn.word(2);
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800383 auto &object = defs[resultId];
Ben Clayton9a162482019-02-25 11:54:43 +0000384 auto &objectTy = getType(typeId);
385 object.type = typeId;
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800386 object.kind = Object::Kind::Constant;
387 object.definition = insn;
Ben Clayton9a162482019-02-25 11:54:43 +0000388 object.constantValue = std::unique_ptr<uint32_t[]>(new uint32_t[objectTy.sizeInComponents]);
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800389 return object;
390 }
391
Chris Forbes049ff382019-02-02 15:16:43 -0800392 void SpirvShader::ProcessInterfaceVariable(Object &object)
Chris Forbesbde34082018-12-28 12:03:10 -0800393 {
Ben Clayton9a162482019-02-25 11:54:43 +0000394 auto &objectTy = getType(object.type);
Ben Clayton6fae32c2019-02-28 20:06:42 +0000395 ASSERT(objectTy.storageClass == spv::StorageClassInput || objectTy.storageClass == spv::StorageClassOutput);
Chris Forbesbde34082018-12-28 12:03:10 -0800396
Ben Clayton6fae32c2019-02-28 20:06:42 +0000397 ASSERT(objectTy.definition.opcode() == spv::OpTypePointer);
Ben Clayton9a162482019-02-25 11:54:43 +0000398 auto pointeeTy = getType(objectTy.element);
Chris Forbesbde34082018-12-28 12:03:10 -0800399
Ben Clayton9a162482019-02-25 11:54:43 +0000400 auto &builtinInterface = (objectTy.storageClass == spv::StorageClassInput) ? inputBuiltins : outputBuiltins;
401 auto &userDefinedInterface = (objectTy.storageClass == spv::StorageClassInput) ? inputs : outputs;
402
Ben Clayton6fae32c2019-02-28 20:06:42 +0000403 ASSERT(object.definition.opcode() == spv::OpVariable);
Ben Claytonab51bbf2019-02-20 14:36:27 +0000404 ObjectID resultId = object.definition.word(2);
Ben Clayton9a162482019-02-25 11:54:43 +0000405
406 if (objectTy.isBuiltInBlock)
Chris Forbesbde34082018-12-28 12:03:10 -0800407 {
408 // walk the builtin block, registering each of its members separately.
Ben Clayton9a162482019-02-25 11:54:43 +0000409 auto m = memberDecorations.find(objectTy.element);
Ben Clayton6fae32c2019-02-28 20:06:42 +0000410 ASSERT(m != memberDecorations.end()); // otherwise we wouldn't have marked the type chain
Ben Clayton9a162482019-02-25 11:54:43 +0000411 auto &structType = pointeeTy.definition;
Chris Forbesbde34082018-12-28 12:03:10 -0800412 auto offset = 0u;
413 auto word = 2u;
414 for (auto &member : m->second)
415 {
Chris Forbes840809a2019-01-14 14:30:20 -0800416 auto &memberType = getType(structType.word(word));
Chris Forbesbde34082018-12-28 12:03:10 -0800417
418 if (member.HasBuiltIn)
419 {
420 builtinInterface[member.BuiltIn] = {resultId, offset, memberType.sizeInComponents};
421 }
422
423 offset += memberType.sizeInComponents;
424 ++word;
425 }
426 return;
427 }
428
429 auto d = decorations.find(resultId);
430 if (d != decorations.end() && d->second.HasBuiltIn)
431 {
Ben Clayton9a162482019-02-25 11:54:43 +0000432 builtinInterface[d->second.BuiltIn] = {resultId, 0, pointeeTy.sizeInComponents};
Chris Forbesbde34082018-12-28 12:03:10 -0800433 }
434 else
435 {
Chris Forbes049ff382019-02-02 15:16:43 -0800436 object.kind = Object::Kind::InterfaceVariable;
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800437 VisitInterface(resultId,
438 [&userDefinedInterface](Decorations const &d, AttribType type) {
439 // Populate a single scalar slot in the interface from a collection of decorations and the intended component type.
440 auto scalarSlot = (d.Location << 2) | d.Component;
Ben Clayton6fae32c2019-02-28 20:06:42 +0000441 ASSERT(scalarSlot >= 0 &&
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800442 scalarSlot < static_cast<int32_t>(userDefinedInterface.size()));
443
444 auto &slot = userDefinedInterface[scalarSlot];
445 slot.Type = type;
446 slot.Flat = d.Flat;
447 slot.NoPerspective = d.NoPerspective;
448 slot.Centroid = d.Centroid;
449 });
Chris Forbesbde34082018-12-28 12:03:10 -0800450 }
451 }
452
Chris Forbesaf4ed532018-12-06 18:33:27 -0800453 void SpirvShader::ProcessExecutionMode(InsnIterator insn)
454 {
455 auto mode = static_cast<spv::ExecutionMode>(insn.word(2));
Chris Forbes4a979dc2019-01-17 09:36:46 -0800456 switch (mode)
457 {
458 case spv::ExecutionModeEarlyFragmentTests:
459 modes.EarlyFragmentTests = true;
460 break;
461 case spv::ExecutionModeDepthReplacing:
462 modes.DepthReplacing = true;
463 break;
464 case spv::ExecutionModeDepthGreater:
465 modes.DepthGreater = true;
466 break;
467 case spv::ExecutionModeDepthLess:
468 modes.DepthLess = true;
469 break;
470 case spv::ExecutionModeDepthUnchanged:
471 modes.DepthUnchanged = true;
472 break;
473 case spv::ExecutionModeLocalSize:
474 modes.LocalSizeX = insn.word(3);
475 modes.LocalSizeZ = insn.word(5);
476 modes.LocalSizeY = insn.word(4);
477 break;
478 case spv::ExecutionModeOriginUpperLeft:
479 // This is always the case for a Vulkan shader. Do nothing.
480 break;
481 default:
482 UNIMPLEMENTED("No other execution modes are permitted");
Chris Forbesaf4ed532018-12-06 18:33:27 -0800483 }
484 }
Chris Forbes739a7fb2018-12-08 13:09:40 -0800485
486 uint32_t SpirvShader::ComputeTypeSize(sw::SpirvShader::InsnIterator insn)
487 {
488 // Types are always built from the bottom up (with the exception of forward ptrs, which
489 // don't appear in Vulkan shaders. Therefore, we can always assume our component parts have
490 // already been described (and so their sizes determined)
491 switch (insn.opcode())
492 {
493 case spv::OpTypeVoid:
494 case spv::OpTypeSampler:
495 case spv::OpTypeImage:
496 case spv::OpTypeSampledImage:
497 case spv::OpTypeFunction:
498 case spv::OpTypeRuntimeArray:
499 // Objects that don't consume any space.
500 // Descriptor-backed objects currently only need exist at compile-time.
501 // Runtime arrays don't appear in places where their size would be interesting
502 return 0;
503
504 case spv::OpTypeBool:
505 case spv::OpTypeFloat:
506 case spv::OpTypeInt:
507 // All the fundamental types are 1 component. If we ever add support for 8/16/64-bit components,
508 // we might need to change this, but only 32 bit components are required for Vulkan 1.1.
509 return 1;
510
511 case spv::OpTypeVector:
512 case spv::OpTypeMatrix:
513 // Vectors and matrices both consume element count * element size.
Chris Forbes840809a2019-01-14 14:30:20 -0800514 return getType(insn.word(2)).sizeInComponents * insn.word(3);
Chris Forbes739a7fb2018-12-08 13:09:40 -0800515
516 case spv::OpTypeArray:
Chris Forbes5be4d702018-12-27 16:12:31 -0800517 {
518 // Element count * element size. Array sizes come from constant ids.
519 auto arraySize = GetConstantInt(insn.word(3));
Chris Forbes840809a2019-01-14 14:30:20 -0800520 return getType(insn.word(2)).sizeInComponents * arraySize;
Chris Forbes5be4d702018-12-27 16:12:31 -0800521 }
Chris Forbes739a7fb2018-12-08 13:09:40 -0800522
523 case spv::OpTypeStruct:
524 {
525 uint32_t size = 0;
526 for (uint32_t i = 2u; i < insn.wordCount(); i++)
527 {
Chris Forbes840809a2019-01-14 14:30:20 -0800528 size += getType(insn.word(i)).sizeInComponents;
Chris Forbes739a7fb2018-12-08 13:09:40 -0800529 }
530 return size;
531 }
532
533 case spv::OpTypePointer:
Chris Forbes0f59a2c2019-02-10 23:03:12 +0000534 // Runtime representation of a pointer is a per-lane index.
535 // Note: clients are expected to look through the pointer if they want the pointee size instead.
536 return 1;
Chris Forbes739a7fb2018-12-08 13:09:40 -0800537
538 default:
539 // Some other random insn.
540 UNIMPLEMENTED("Only types are supported");
Ben Clayton60a3d6f2019-02-26 17:24:46 +0000541 return 0;
Chris Forbes739a7fb2018-12-08 13:09:40 -0800542 }
543 }
Chris Forbesc25b8072018-12-10 15:10:39 -0800544
Ben Clayton831db962019-02-27 14:57:18 +0000545 bool SpirvShader::IsStorageInterleavedByLane(spv::StorageClass storageClass)
546 {
547 switch (storageClass)
548 {
549 case spv::StorageClassUniform:
550 case spv::StorageClassStorageBuffer:
551 return false;
552 default:
553 return true;
554 }
555 }
556
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800557 template<typename F>
Ben Claytonab51bbf2019-02-20 14:36:27 +0000558 int SpirvShader::VisitInterfaceInner(TypeID id, Decorations d, F f) const
Chris Forbes5839dcf2018-12-10 19:02:58 -0800559 {
560 // Recursively walks variable definition and its type tree, taking into account
561 // any explicit Location or Component decorations encountered; where explicit
562 // Locations or Components are not specified, assigns them sequentially.
563 // Collected decorations are carried down toward the leaves and across
564 // siblings; Effect of decorations intentionally does not flow back up the tree.
565 //
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800566 // F is a functor to be called with the effective decoration set for every component.
567 //
568 // Returns the next available location, and calls f().
Chris Forbes5839dcf2018-12-10 19:02:58 -0800569
570 // This covers the rules in Vulkan 1.1 spec, 14.1.4 Location Assignment.
571
Chris Forbes49d664d2019-02-12 19:24:50 +0000572 ApplyDecorationsForId(&d, id);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800573
Chris Forbes840809a2019-01-14 14:30:20 -0800574 auto const &obj = getType(id);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800575 switch (obj.definition.opcode())
576 {
Chris Forbes5839dcf2018-12-10 19:02:58 -0800577 case spv::OpTypePointer:
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800578 return VisitInterfaceInner<F>(obj.definition.word(3), d, f);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800579 case spv::OpTypeMatrix:
580 for (auto i = 0u; i < obj.definition.word(3); i++, d.Location++)
581 {
582 // consumes same components of N consecutive locations
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800583 VisitInterfaceInner<F>(obj.definition.word(2), d, f);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800584 }
585 return d.Location;
586 case spv::OpTypeVector:
587 for (auto i = 0u; i < obj.definition.word(3); i++, d.Component++)
588 {
589 // consumes N consecutive components in the same location
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800590 VisitInterfaceInner<F>(obj.definition.word(2), d, f);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800591 }
592 return d.Location + 1;
593 case spv::OpTypeFloat:
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800594 f(d, ATTRIBTYPE_FLOAT);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800595 return d.Location + 1;
596 case spv::OpTypeInt:
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800597 f(d, obj.definition.word(3) ? ATTRIBTYPE_INT : ATTRIBTYPE_UINT);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800598 return d.Location + 1;
599 case spv::OpTypeBool:
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800600 f(d, ATTRIBTYPE_UINT);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800601 return d.Location + 1;
602 case spv::OpTypeStruct:
603 {
Chris Forbes5839dcf2018-12-10 19:02:58 -0800604 // iterate over members, which may themselves have Location/Component decorations
605 for (auto i = 0u; i < obj.definition.wordCount() - 2; i++)
606 {
Chris Forbes49d664d2019-02-12 19:24:50 +0000607 ApplyDecorationsForIdMember(&d, id, i);
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800608 d.Location = VisitInterfaceInner<F>(obj.definition.word(i + 2), d, f);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800609 d.Component = 0; // Implicit locations always have component=0
610 }
611 return d.Location;
612 }
Chris Forbes5be4d702018-12-27 16:12:31 -0800613 case spv::OpTypeArray:
614 {
615 auto arraySize = GetConstantInt(obj.definition.word(3));
616 for (auto i = 0u; i < arraySize; i++)
617 {
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800618 d.Location = VisitInterfaceInner<F>(obj.definition.word(2), d, f);
Chris Forbes5be4d702018-12-27 16:12:31 -0800619 }
620 return d.Location;
621 }
Chris Forbes5839dcf2018-12-10 19:02:58 -0800622 default:
623 // Intentionally partial; most opcodes do not participate in type hierarchies
624 return 0;
625 }
626 }
627
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800628 template<typename F>
Ben Claytonab51bbf2019-02-20 14:36:27 +0000629 void SpirvShader::VisitInterface(ObjectID id, F f) const
Chris Forbes5839dcf2018-12-10 19:02:58 -0800630 {
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800631 // Walk a variable definition and call f for each component in it.
Chris Forbes5839dcf2018-12-10 19:02:58 -0800632 Decorations d{};
Chris Forbes49d664d2019-02-12 19:24:50 +0000633 ApplyDecorationsForId(&d, id);
Chris Forbes1c658232019-02-01 17:12:25 -0800634
635 auto def = getObject(id).definition;
Ben Clayton6fae32c2019-02-28 20:06:42 +0000636 ASSERT(def.opcode() == spv::OpVariable);
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800637 VisitInterfaceInner<F>(def.word(1), d, f);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800638 }
639
Ben Clayton24ea5152019-02-26 11:02:42 +0000640 SIMD::Int SpirvShader::WalkAccessChain(ObjectID id, uint32_t numIndexes, uint32_t const *indexIds, SpirvRoutine *routine) const
Chris Forbes38f85b32019-02-12 20:10:05 +0000641 {
Chris Forbes38f85b32019-02-12 20:10:05 +0000642 // TODO: think about explicit layout (UBO/SSBO) storage classes
643 // TODO: avoid doing per-lane work in some cases if we can?
644
Chris Forbes6397ed02019-02-15 16:39:17 -0800645 int constantOffset = 0;
Ben Clayton24ea5152019-02-26 11:02:42 +0000646 SIMD::Int dynamicOffset = SIMD::Int(0);
Ben Clayton9a162482019-02-25 11:54:43 +0000647 auto &baseObject = getObject(id);
648 TypeID typeId = getType(baseObject.type).element;
Chris Forbes38f85b32019-02-12 20:10:05 +0000649
Chris Forbese4ef5f72019-02-15 16:00:08 -0800650 // The <base> operand is an intermediate value itself, ie produced by a previous OpAccessChain.
651 // Start with its offset and build from there.
Chris Forbes38f85b32019-02-12 20:10:05 +0000652 if (baseObject.kind == Object::Kind::Value)
Ben Clayton24ea5152019-02-26 11:02:42 +0000653 dynamicOffset += As<SIMD::Int>(routine->getIntermediate(id)[0]);
Chris Forbes38f85b32019-02-12 20:10:05 +0000654
655 for (auto i = 0u; i < numIndexes; i++)
656 {
657 auto & type = getType(typeId);
658 switch (type.definition.opcode())
659 {
660 case spv::OpTypeStruct:
661 {
662 int memberIndex = GetConstantInt(indexIds[i]);
663 int offsetIntoStruct = 0;
664 for (auto j = 0; j < memberIndex; j++) {
Chris Forbes58bee562019-02-19 17:41:41 -0800665 auto memberType = type.definition.word(2u + j);
666 offsetIntoStruct += getType(memberType).sizeInComponents;
Chris Forbes38f85b32019-02-12 20:10:05 +0000667 }
Chris Forbes6397ed02019-02-15 16:39:17 -0800668 constantOffset += offsetIntoStruct;
Chris Forbes58bee562019-02-19 17:41:41 -0800669 typeId = type.definition.word(2u + memberIndex);
Chris Forbes38f85b32019-02-12 20:10:05 +0000670 break;
671 }
672
673 case spv::OpTypeVector:
674 case spv::OpTypeMatrix:
675 case spv::OpTypeArray:
676 {
Ben Clayton9a162482019-02-25 11:54:43 +0000677 auto stride = getType(type.element).sizeInComponents;
Chris Forbes38f85b32019-02-12 20:10:05 +0000678 auto & obj = getObject(indexIds[i]);
679 if (obj.kind == Object::Kind::Constant)
Chris Forbes6397ed02019-02-15 16:39:17 -0800680 constantOffset += stride * GetConstantInt(indexIds[i]);
Chris Forbes38f85b32019-02-12 20:10:05 +0000681 else
Ben Clayton24ea5152019-02-26 11:02:42 +0000682 dynamicOffset += SIMD::Int(stride) * As<SIMD::Int>(routine->getIntermediate(indexIds[i])[0]);
Ben Clayton9a162482019-02-25 11:54:43 +0000683 typeId = type.element;
Chris Forbes38f85b32019-02-12 20:10:05 +0000684 break;
685 }
686
687 default:
Ben Claytond4e4c662019-02-26 11:54:34 +0000688 UNIMPLEMENTED("Unexpected type '%s' in WalkAccessChain", OpcodeName(type.definition.opcode()).c_str());
Chris Forbes38f85b32019-02-12 20:10:05 +0000689 }
690 }
691
Ben Clayton24ea5152019-02-26 11:02:42 +0000692 return dynamicOffset + SIMD::Int(constantOffset);
Chris Forbes38f85b32019-02-12 20:10:05 +0000693 }
694
Chris Forbes9638b942019-02-21 18:39:31 -0800695 uint32_t SpirvShader::WalkLiteralAccessChain(TypeID typeId, uint32_t numIndexes, uint32_t const *indexes) const
696 {
697 uint32_t constantOffset = 0;
698
699 for (auto i = 0u; i < numIndexes; i++)
700 {
701 auto & type = getType(typeId);
702 switch (type.definition.opcode())
703 {
704 case spv::OpTypeStruct:
705 {
706 int memberIndex = indexes[i];
707 int offsetIntoStruct = 0;
708 for (auto j = 0; j < memberIndex; j++) {
709 auto memberType = type.definition.word(2u + j);
710 offsetIntoStruct += getType(memberType).sizeInComponents;
711 }
712 constantOffset += offsetIntoStruct;
713 typeId = type.definition.word(2u + memberIndex);
714 break;
715 }
716
717 case spv::OpTypeVector:
718 case spv::OpTypeMatrix:
719 case spv::OpTypeArray:
720 {
721 auto elementType = type.definition.word(2);
722 auto stride = getType(elementType).sizeInComponents;
723 constantOffset += stride * indexes[i];
724 typeId = elementType;
725 break;
726 }
727
728 default:
729 UNIMPLEMENTED("Unexpected type in WalkLiteralAccessChain");
730 }
731 }
732
733 return constantOffset;
734 }
735
Chris Forbesc25b8072018-12-10 15:10:39 -0800736 void SpirvShader::Decorations::Apply(spv::Decoration decoration, uint32_t arg)
737 {
738 switch (decoration)
739 {
740 case spv::DecorationLocation:
741 HasLocation = true;
742 Location = static_cast<int32_t>(arg);
743 break;
744 case spv::DecorationComponent:
745 HasComponent = true;
746 Component = arg;
747 break;
Ben Claytond073d8e2019-02-26 11:06:50 +0000748 case spv::DecorationDescriptorSet:
749 HasDescriptorSet = true;
750 DescriptorSet = arg;
751 break;
752 case spv::DecorationBinding:
753 HasBinding = true;
754 Binding = arg;
755 break;
Chris Forbesc25b8072018-12-10 15:10:39 -0800756 case spv::DecorationBuiltIn:
757 HasBuiltIn = true;
758 BuiltIn = static_cast<spv::BuiltIn>(arg);
759 break;
760 case spv::DecorationFlat:
761 Flat = true;
762 break;
763 case spv::DecorationNoPerspective:
Chris Forbes5839dcf2018-12-10 19:02:58 -0800764 NoPerspective = true;
Chris Forbesc25b8072018-12-10 15:10:39 -0800765 break;
766 case spv::DecorationCentroid:
767 Centroid = true;
768 break;
769 case spv::DecorationBlock:
770 Block = true;
771 break;
772 case spv::DecorationBufferBlock:
773 BufferBlock = true;
774 break;
775 default:
776 // Intentionally partial, there are many decorations we just don't care about.
777 break;
778 }
779 }
780
781 void SpirvShader::Decorations::Apply(const sw::SpirvShader::Decorations &src)
782 {
783 // Apply a decoration group to this set of decorations
784 if (src.HasBuiltIn)
785 {
786 HasBuiltIn = true;
787 BuiltIn = src.BuiltIn;
788 }
789
790 if (src.HasLocation)
791 {
792 HasLocation = true;
793 Location = src.Location;
794 }
795
796 if (src.HasComponent)
797 {
798 HasComponent = true;
799 Component = src.Component;
800 }
801
Ben Claytond073d8e2019-02-26 11:06:50 +0000802 if (src.HasDescriptorSet)
803 {
804 HasDescriptorSet = true;
805 DescriptorSet = src.DescriptorSet;
806 }
807
808 if (src.HasBinding)
809 {
810 HasBinding = true;
811 Binding = src.Binding;
812 }
813
Chris Forbesc25b8072018-12-10 15:10:39 -0800814 Flat |= src.Flat;
Chris Forbes5839dcf2018-12-10 19:02:58 -0800815 NoPerspective |= src.NoPerspective;
Chris Forbesc25b8072018-12-10 15:10:39 -0800816 Centroid |= src.Centroid;
817 Block |= src.Block;
818 BufferBlock |= src.BufferBlock;
819 }
Chris Forbesbc3a0ee2018-12-27 16:02:58 -0800820
Ben Claytonab51bbf2019-02-20 14:36:27 +0000821 void SpirvShader::ApplyDecorationsForId(Decorations *d, TypeOrObjectID id) const
Chris Forbes49d664d2019-02-12 19:24:50 +0000822 {
823 auto it = decorations.find(id);
824 if (it != decorations.end())
825 d->Apply(it->second);
826 }
827
Ben Claytonab51bbf2019-02-20 14:36:27 +0000828 void SpirvShader::ApplyDecorationsForIdMember(Decorations *d, TypeID id, uint32_t member) const
Chris Forbes49d664d2019-02-12 19:24:50 +0000829 {
830 auto it = memberDecorations.find(id);
831 if (it != memberDecorations.end() && member < it->second.size())
832 {
833 d->Apply(it->second[member]);
834 }
835 }
836
Ben Claytonab51bbf2019-02-20 14:36:27 +0000837 uint32_t SpirvShader::GetConstantInt(ObjectID id) const
Chris Forbesbc3a0ee2018-12-27 16:02:58 -0800838 {
839 // Slightly hackish access to constants very early in translation.
840 // General consumption of constants by other instructions should
841 // probably be just lowered to Reactor.
842
843 // TODO: not encountered yet since we only use this for array sizes etc,
844 // but is possible to construct integer constant 0 via OpConstantNull.
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800845 auto insn = getObject(id).definition;
Ben Clayton6fae32c2019-02-28 20:06:42 +0000846 ASSERT(insn.opcode() == spv::OpConstant);
847 ASSERT(getType(insn.word(1)).definition.opcode() == spv::OpTypeInt);
Chris Forbesbc3a0ee2018-12-27 16:02:58 -0800848 return insn.word(3);
849 }
Chris Forbesd5aed492019-02-02 15:18:52 -0800850
851 // emit-time
852
Chris Forbesc61271e2019-02-19 17:01:28 -0800853 void SpirvShader::emitProlog(SpirvRoutine *routine) const
Chris Forbesd5aed492019-02-02 15:18:52 -0800854 {
855 for (auto insn : *this)
856 {
857 switch (insn.opcode())
858 {
859 case spv::OpVariable:
860 {
Ben Claytonab51bbf2019-02-20 14:36:27 +0000861 ObjectID resultId = insn.word(2);
Chris Forbes0eba65b2019-02-13 12:24:35 -0800862 auto &object = getObject(resultId);
Ben Clayton9a162482019-02-25 11:54:43 +0000863 auto &objectTy = getType(object.type);
864 auto &pointeeTy = getType(objectTy.element);
Chris Forbesd5aed492019-02-02 15:18:52 -0800865 // TODO: what to do about zero-slot objects?
Ben Clayton9a162482019-02-25 11:54:43 +0000866 if (pointeeTy.sizeInComponents > 0)
Chris Forbesd5aed492019-02-02 15:18:52 -0800867 {
Ben Clayton9a162482019-02-25 11:54:43 +0000868 routine->createLvalue(insn.word(2), pointeeTy.sizeInComponents);
Chris Forbesd5aed492019-02-02 15:18:52 -0800869 }
870 break;
871 }
872 default:
Chris Forbese9f8f5b2019-02-11 00:20:16 +0000873 // Nothing else produces interface variables, so can all be safely ignored.
Chris Forbesd5aed492019-02-02 15:18:52 -0800874 break;
875 }
876 }
877 }
878
879 void SpirvShader::emit(SpirvRoutine *routine) const
880 {
Chris Forbesd5aed492019-02-02 15:18:52 -0800881 for (auto insn : *this)
882 {
883 switch (insn.opcode())
884 {
Chris Forbese53533d2019-02-21 16:49:51 -0800885 case spv::OpTypeVoid:
886 case spv::OpTypeInt:
887 case spv::OpTypeFloat:
888 case spv::OpTypeBool:
889 case spv::OpTypeVector:
890 case spv::OpTypeArray:
891 case spv::OpTypeRuntimeArray:
892 case spv::OpTypeMatrix:
893 case spv::OpTypeStruct:
894 case spv::OpTypePointer:
895 case spv::OpTypeFunction:
896 case spv::OpExecutionMode:
897 case spv::OpMemoryModel:
898 case spv::OpFunction:
899 case spv::OpFunctionEnd:
900 case spv::OpConstant:
901 case spv::OpConstantNull:
902 case spv::OpConstantTrue:
903 case spv::OpConstantFalse:
904 case spv::OpConstantComposite:
905 case spv::OpExtension:
906 case spv::OpCapability:
907 case spv::OpEntryPoint:
908 case spv::OpExtInstImport:
909 case spv::OpDecorate:
910 case spv::OpMemberDecorate:
911 case spv::OpGroupDecorate:
912 case spv::OpGroupMemberDecorate:
913 case spv::OpDecorationGroup:
Chris Forbes1776af72019-02-22 17:39:57 -0800914 case spv::OpName:
915 case spv::OpMemberName:
916 case spv::OpSource:
917 case spv::OpSourceContinued:
918 case spv::OpSourceExtension:
Chris Forbese53533d2019-02-21 16:49:51 -0800919 // Nothing to do at emit time. These are either fully handled at analysis time,
920 // or don't require any work at all.
921 break;
922
Chris Forbese57f10e2019-03-04 10:53:07 -0800923 case spv::OpLabel:
924 case spv::OpReturn:
925 // TODO: when we do control flow, will need to do some work here.
926 // Until then, there is nothing to do -- we expect there to be an initial OpLabel
927 // in the entrypoint function, for which we do nothing; and a final OpReturn at the
928 // end of the entrypoint function, for which we do nothing.
929 break;
930
Chris Forbes0eba65b2019-02-13 12:24:35 -0800931 case spv::OpVariable:
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000932 EmitVariable(insn, routine);
Chris Forbes0eba65b2019-02-13 12:24:35 -0800933 break;
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000934
Chris Forbese9f8f5b2019-02-11 00:20:16 +0000935 case spv::OpLoad:
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000936 EmitLoad(insn, routine);
Chris Forbese9f8f5b2019-02-11 00:20:16 +0000937 break;
Chris Forbes38f85b32019-02-12 20:10:05 +0000938
Chris Forbes1c588002019-02-12 18:56:38 +0000939 case spv::OpStore:
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000940 EmitStore(insn, routine);
Chris Forbes1c588002019-02-12 18:56:38 +0000941 break;
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000942
943 case spv::OpAccessChain:
944 EmitAccessChain(insn, routine);
945 break;
946
Chris Forbesb97a9572019-02-21 16:51:42 -0800947 case spv::OpCompositeConstruct:
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000948 EmitCompositeConstruct(insn, routine);
Chris Forbesb97a9572019-02-21 16:51:42 -0800949 break;
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000950
Chris Forbes1bc1acf2019-02-21 18:40:33 -0800951 case spv::OpCompositeInsert:
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000952 EmitCompositeInsert(insn, routine);
Chris Forbes1bc1acf2019-02-21 18:40:33 -0800953 break;
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000954
Chris Forbesb12846d2019-02-21 18:53:58 -0800955 case spv::OpCompositeExtract:
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000956 EmitCompositeExtract(insn, routine);
Chris Forbesb12846d2019-02-21 18:53:58 -0800957 break;
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000958
Chris Forbes83fc5442019-02-26 22:16:07 -0800959 case spv::OpVectorShuffle:
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000960 EmitVectorShuffle(insn, routine);
Chris Forbes83fc5442019-02-26 22:16:07 -0800961 break;
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000962
Ben Claytondd1e37e2019-02-28 19:59:15 +0000963 case spv::OpNot:
964 case spv::OpSNegate:
965 case spv::OpFNegate:
966 case spv::OpLogicalNot:
Chris Forbes4d503052019-03-01 17:13:57 -0800967 case spv::OpConvertFToU:
968 case spv::OpConvertFToS:
969 case spv::OpConvertSToF:
970 case spv::OpConvertUToF:
971 case spv::OpBitcast:
Ben Claytondd1e37e2019-02-28 19:59:15 +0000972 EmitUnaryOp(insn, routine);
973 break;
974
975 case spv::OpIAdd:
976 case spv::OpISub:
977 case spv::OpIMul:
978 case spv::OpSDiv:
979 case spv::OpUDiv:
980 case spv::OpFAdd:
981 case spv::OpFSub:
982 case spv::OpFDiv:
Ben Claytonec1aeb82019-03-04 19:33:27 +0000983 case spv::OpFOrdEqual:
984 case spv::OpFUnordEqual:
985 case spv::OpFOrdNotEqual:
986 case spv::OpFUnordNotEqual:
987 case spv::OpFOrdLessThan:
988 case spv::OpFUnordLessThan:
989 case spv::OpFOrdGreaterThan:
990 case spv::OpFUnordGreaterThan:
991 case spv::OpFOrdLessThanEqual:
992 case spv::OpFUnordLessThanEqual:
993 case spv::OpFOrdGreaterThanEqual:
994 case spv::OpFUnordGreaterThanEqual:
Ben Claytondd1e37e2019-02-28 19:59:15 +0000995 case spv::OpUMod:
Ben Claytone95eeb12019-03-04 16:32:09 +0000996 case spv::OpIEqual:
997 case spv::OpINotEqual:
998 case spv::OpUGreaterThan:
999 case spv::OpSGreaterThan:
1000 case spv::OpUGreaterThanEqual:
1001 case spv::OpSGreaterThanEqual:
1002 case spv::OpULessThan:
1003 case spv::OpSLessThan:
1004 case spv::OpULessThanEqual:
1005 case spv::OpSLessThanEqual:
Ben Claytondd1e37e2019-02-28 19:59:15 +00001006 case spv::OpShiftRightLogical:
1007 case spv::OpShiftRightArithmetic:
1008 case spv::OpShiftLeftLogical:
1009 case spv::OpBitwiseOr:
1010 case spv::OpBitwiseXor:
1011 case spv::OpBitwiseAnd:
1012 case spv::OpLogicalOr:
1013 case spv::OpLogicalAnd:
Chris Forbese86b6dc2019-03-01 09:08:47 -08001014 case spv::OpUMulExtended:
1015 case spv::OpSMulExtended:
Ben Claytondd1e37e2019-02-28 19:59:15 +00001016 EmitBinaryOp(insn, routine);
1017 break;
1018
Chris Forbes2b287cc2019-03-01 13:24:17 -08001019 case spv::OpDot:
1020 EmitDot(insn, routine);
1021 break;
1022
Ben Claytonbf943f62019-03-05 12:57:39 +00001023 case spv::OpSelect:
1024 EmitSelect(insn, routine);
1025 break;
1026
Chris Forbesd5aed492019-02-02 15:18:52 -08001027 default:
Chris Forbese57f10e2019-03-04 10:53:07 -08001028 UNIMPLEMENTED(OpcodeName(insn.opcode()).c_str());
Chris Forbesd5aed492019-02-02 15:18:52 -08001029 break;
1030 }
1031 }
1032 }
Chris Forbesc61271e2019-02-19 17:01:28 -08001033
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001034 void SpirvShader::EmitVariable(InsnIterator insn, SpirvRoutine *routine) const
1035 {
1036 ObjectID resultId = insn.word(2);
1037 auto &object = getObject(resultId);
1038 auto &objectTy = getType(object.type);
1039 if (object.kind == Object::Kind::InterfaceVariable && objectTy.storageClass == spv::StorageClassInput)
1040 {
1041 auto &dst = routine->getValue(resultId);
1042 int offset = 0;
1043 VisitInterface(resultId,
1044 [&](Decorations const &d, AttribType type) {
1045 auto scalarSlot = d.Location << 2 | d.Component;
1046 dst[offset++] = routine->inputs[scalarSlot];
1047 });
1048 }
1049 }
1050
1051 void SpirvShader::EmitLoad(InsnIterator insn, SpirvRoutine *routine) const
1052 {
1053 ObjectID objectId = insn.word(2);
1054 ObjectID pointerId = insn.word(3);
1055 auto &object = getObject(objectId);
1056 auto &objectTy = getType(object.type);
1057 auto &pointer = getObject(pointerId);
1058 auto &pointerBase = getObject(pointer.pointerBase);
1059 auto &pointerBaseTy = getType(pointerBase.type);
1060
1061 ASSERT(getType(pointer.type).element == object.type);
1062 ASSERT(TypeID(insn.word(1)) == object.type);
1063
1064 if (pointerBaseTy.storageClass == spv::StorageClassImage ||
1065 pointerBaseTy.storageClass == spv::StorageClassUniform ||
1066 pointerBaseTy.storageClass == spv::StorageClassUniformConstant)
1067 {
1068 UNIMPLEMENTED("Descriptor-backed load not yet implemented");
1069 }
1070
Ben Clayton831db962019-02-27 14:57:18 +00001071 Pointer<Float> ptrBase;
1072 if (pointerBase.kind == Object::Kind::PhysicalPointer)
1073 {
1074 ptrBase = routine->getPhysicalPointer(pointer.pointerBase);
1075 }
1076 else
1077 {
1078 ptrBase = &routine->getValue(pointer.pointerBase)[0];
1079 }
1080
1081 bool interleavedByLane = IsStorageInterleavedByLane(pointerBaseTy.storageClass);
1082
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001083 auto &dst = routine->createIntermediate(objectId, objectTy.sizeInComponents);
1084
1085 if (pointer.kind == Object::Kind::Value)
1086 {
Ben Clayton831db962019-02-27 14:57:18 +00001087 // Divergent offsets.
1088 auto offsets = As<SIMD::Int>(routine->getIntermediate(pointerId)[0]);
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001089 for (auto i = 0u; i < objectTy.sizeInComponents; i++)
1090 {
1091 // i wish i had a Float,Float,Float,Float constructor here..
1092 SIMD::Float v;
1093 for (int j = 0; j < SIMD::Width; j++)
1094 {
1095 Int offset = Int(i) + Extract(offsets, j);
Ben Clayton831db962019-02-27 14:57:18 +00001096 if (interleavedByLane) { offset = offset * SIMD::Width + j; }
1097 v = Insert(v, ptrBase[offset], j);
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001098 }
1099 dst.emplace(i, v);
1100 }
1101 }
Ben Clayton831db962019-02-27 14:57:18 +00001102 else if (interleavedByLane)
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001103 {
Ben Clayton831db962019-02-27 14:57:18 +00001104 // Lane-interleaved data. No divergent offsets.
1105 Pointer<SIMD::Float> src = ptrBase;
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001106 for (auto i = 0u; i < objectTy.sizeInComponents; i++)
1107 {
Ben Clayton831db962019-02-27 14:57:18 +00001108 dst.emplace(i, src[i]);
1109 }
1110 }
1111 else
1112 {
1113 // Non-interleaved data. No divergent offsets.
1114 for (auto i = 0u; i < objectTy.sizeInComponents; i++)
1115 {
1116 dst.emplace(i, RValue<SIMD::Float>(ptrBase[i]));
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001117 }
1118 }
1119 }
1120
1121 void SpirvShader::EmitAccessChain(InsnIterator insn, SpirvRoutine *routine) const
1122 {
1123 TypeID typeId = insn.word(1);
1124 ObjectID objectId = insn.word(2);
1125 ObjectID baseId = insn.word(3);
1126 auto &object = getObject(objectId);
1127 auto &type = getType(typeId);
1128 auto &pointerBase = getObject(object.pointerBase);
1129 auto &pointerBaseTy = getType(pointerBase.type);
1130 ASSERT(type.sizeInComponents == 1);
1131 ASSERT(getObject(baseId).pointerBase == object.pointerBase);
1132
1133 if (pointerBaseTy.storageClass == spv::StorageClassImage ||
1134 pointerBaseTy.storageClass == spv::StorageClassUniform ||
1135 pointerBaseTy.storageClass == spv::StorageClassUniformConstant)
1136 {
1137 UNIMPLEMENTED("Descriptor-backed OpAccessChain not yet implemented");
1138 }
1139 auto &dst = routine->createIntermediate(objectId, type.sizeInComponents);
1140 dst.emplace(0, As<SIMD::Float>(WalkAccessChain(baseId, insn.wordCount() - 4, insn.wordPointer(4), routine)));
1141 }
1142
1143 void SpirvShader::EmitStore(InsnIterator insn, SpirvRoutine *routine) const
1144 {
1145 ObjectID pointerId = insn.word(1);
1146 ObjectID objectId = insn.word(2);
1147 auto &object = getObject(objectId);
1148 auto &pointer = getObject(pointerId);
1149 auto &pointerTy = getType(pointer.type);
1150 auto &elementTy = getType(pointerTy.element);
1151 auto &pointerBase = getObject(pointer.pointerBase);
1152 auto &pointerBaseTy = getType(pointerBase.type);
1153
1154 if (pointerBaseTy.storageClass == spv::StorageClassImage ||
1155 pointerBaseTy.storageClass == spv::StorageClassUniform ||
1156 pointerBaseTy.storageClass == spv::StorageClassUniformConstant)
1157 {
1158 UNIMPLEMENTED("Descriptor-backed store not yet implemented");
1159 }
1160
Ben Clayton831db962019-02-27 14:57:18 +00001161 Pointer<Float> ptrBase;
1162 if (pointerBase.kind == Object::Kind::PhysicalPointer)
1163 {
1164 ptrBase = routine->getPhysicalPointer(pointer.pointerBase);
1165 }
1166 else
1167 {
1168 ptrBase = &routine->getValue(pointer.pointerBase)[0];
1169 }
1170
1171 bool interleavedByLane = IsStorageInterleavedByLane(pointerBaseTy.storageClass);
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001172
1173 if (object.kind == Object::Kind::Constant)
1174 {
1175 auto src = reinterpret_cast<float *>(object.constantValue.get());
1176
1177 if (pointer.kind == Object::Kind::Value)
1178 {
Ben Clayton831db962019-02-27 14:57:18 +00001179 // Constant source data. Divergent offsets.
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001180 auto offsets = As<SIMD::Int>(routine->getIntermediate(pointerId)[0]);
1181 for (auto i = 0u; i < elementTy.sizeInComponents; i++)
1182 {
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001183 for (int j = 0; j < SIMD::Width; j++)
1184 {
Ben Clayton831db962019-02-27 14:57:18 +00001185 Int offset = Int(i) + Extract(offsets, j);
1186 if (interleavedByLane) { offset = offset * SIMD::Width + j; }
1187 ptrBase[offset] = RValue<Float>(src[i]);
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001188 }
1189 }
1190 }
1191 else
1192 {
Ben Clayton831db962019-02-27 14:57:18 +00001193 // Constant source data. No divergent offsets.
1194 Pointer<SIMD::Float> dst = ptrBase;
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001195 for (auto i = 0u; i < elementTy.sizeInComponents; i++)
1196 {
Ben Clayton831db962019-02-27 14:57:18 +00001197 dst[i] = RValue<SIMD::Float>(src[i]);
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001198 }
1199 }
1200 }
1201 else
1202 {
1203 auto &src = routine->getIntermediate(objectId);
1204
1205 if (pointer.kind == Object::Kind::Value)
1206 {
Ben Clayton831db962019-02-27 14:57:18 +00001207 // Intermediate source data. Divergent offsets.
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001208 auto offsets = As<SIMD::Int>(routine->getIntermediate(pointerId)[0]);
1209 for (auto i = 0u; i < elementTy.sizeInComponents; i++)
1210 {
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001211 for (int j = 0; j < SIMD::Width; j++)
1212 {
Ben Clayton831db962019-02-27 14:57:18 +00001213 Int offset = Int(i) + Extract(offsets, j);
1214 if (interleavedByLane) { offset = offset * SIMD::Width + j; }
1215 ptrBase[offset] = Extract(src[i], j);
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001216 }
1217 }
1218 }
Ben Clayton831db962019-02-27 14:57:18 +00001219 else if (interleavedByLane)
1220 {
1221 // Intermediate source data. Lane-interleaved data. No divergent offsets.
1222 Pointer<SIMD::Float> dst = ptrBase;
1223 for (auto i = 0u; i < elementTy.sizeInComponents; i++)
1224 {
1225 dst[i] = src[i];
1226 }
1227 }
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001228 else
1229 {
Ben Clayton831db962019-02-27 14:57:18 +00001230 // Intermediate source data. Non-interleaved data. No divergent offsets.
1231 Pointer<SIMD::Float> dst = ptrBase;
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001232 for (auto i = 0u; i < elementTy.sizeInComponents; i++)
1233 {
Ben Clayton831db962019-02-27 14:57:18 +00001234 dst[i] = SIMD::Float(src[i]);
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001235 }
1236 }
1237 }
1238 }
1239
1240 void SpirvShader::EmitCompositeConstruct(InsnIterator insn, SpirvRoutine *routine) const
1241 {
1242 auto &type = getType(insn.word(1));
1243 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
1244 auto offset = 0u;
1245
1246 for (auto i = 0u; i < insn.wordCount() - 3; i++)
1247 {
1248 ObjectID srcObjectId = insn.word(3u + i);
1249 auto & srcObject = getObject(srcObjectId);
1250 auto & srcObjectTy = getType(srcObject.type);
1251 GenericValue srcObjectAccess(this, routine, srcObjectId);
1252
1253 for (auto j = 0u; j < srcObjectTy.sizeInComponents; j++)
1254 dst.emplace(offset++, srcObjectAccess[j]);
1255 }
1256 }
1257
1258 void SpirvShader::EmitCompositeInsert(InsnIterator insn, SpirvRoutine *routine) const
1259 {
1260 TypeID resultTypeId = insn.word(1);
1261 auto &type = getType(resultTypeId);
1262 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
1263 auto &newPartObject = getObject(insn.word(3));
1264 auto &newPartObjectTy = getType(newPartObject.type);
1265 auto firstNewComponent = WalkLiteralAccessChain(resultTypeId, insn.wordCount() - 5, insn.wordPointer(5));
1266
1267 GenericValue srcObjectAccess(this, routine, insn.word(4));
1268 GenericValue newPartObjectAccess(this, routine, insn.word(3));
1269
1270 // old components before
1271 for (auto i = 0u; i < firstNewComponent; i++)
1272 {
1273 dst.emplace(i, srcObjectAccess[i]);
1274 }
1275 // new part
1276 for (auto i = 0u; i < newPartObjectTy.sizeInComponents; i++)
1277 {
1278 dst.emplace(firstNewComponent + i, newPartObjectAccess[i]);
1279 }
1280 // old components after
1281 for (auto i = firstNewComponent + newPartObjectTy.sizeInComponents; i < type.sizeInComponents; i++)
1282 {
1283 dst.emplace(i, srcObjectAccess[i]);
1284 }
1285 }
1286
1287 void SpirvShader::EmitCompositeExtract(InsnIterator insn, SpirvRoutine *routine) const
1288 {
1289 auto &type = getType(insn.word(1));
1290 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
1291 auto &compositeObject = getObject(insn.word(3));
1292 TypeID compositeTypeId = compositeObject.definition.word(1);
1293 auto firstComponent = WalkLiteralAccessChain(compositeTypeId, insn.wordCount() - 4, insn.wordPointer(4));
1294
1295 GenericValue compositeObjectAccess(this, routine, insn.word(3));
1296 for (auto i = 0u; i < type.sizeInComponents; i++)
1297 {
1298 dst.emplace(i, compositeObjectAccess[firstComponent + i]);
1299 }
1300 }
1301
1302 void SpirvShader::EmitVectorShuffle(InsnIterator insn, SpirvRoutine *routine) const
1303 {
1304 auto &type = getType(insn.word(1));
1305 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
1306
1307 GenericValue firstHalfAccess(this, routine, insn.word(3));
1308 GenericValue secondHalfAccess(this, routine, insn.word(4));
1309
1310 for (auto i = 0u; i < type.sizeInComponents; i++)
1311 {
1312 auto selector = insn.word(5 + i);
1313 if (selector == static_cast<uint32_t>(-1))
1314 {
1315 // Undefined value. Until we decide to do real undef values, zero is as good
1316 // a value as any
1317 dst.emplace(i, RValue<SIMD::Float>(0.0f));
1318 }
1319 else if (selector < type.sizeInComponents)
1320 {
1321 dst.emplace(i, firstHalfAccess[selector]);
1322 }
1323 else
1324 {
1325 dst.emplace(i, secondHalfAccess[selector - type.sizeInComponents]);
1326 }
1327 }
1328 }
1329
Ben Claytondd1e37e2019-02-28 19:59:15 +00001330 void SpirvShader::EmitUnaryOp(InsnIterator insn, SpirvRoutine *routine) const
1331 {
1332 auto &type = getType(insn.word(1));
1333 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
1334 auto src = GenericValue(this, routine, insn.word(3));
1335
1336 for (auto i = 0u; i < type.sizeInComponents; i++)
1337 {
1338 auto val = src[i];
1339
1340 switch (insn.opcode())
1341 {
1342 case spv::OpNot:
1343 case spv::OpLogicalNot: // logical not == bitwise not due to all-bits boolean representation
1344 dst.emplace(i, As<SIMD::Float>(~As<SIMD::UInt>(val)));
1345 break;
1346 case spv::OpSNegate:
1347 dst.emplace(i, As<SIMD::Float>(-As<SIMD::Int>(val)));
1348 break;
1349 case spv::OpFNegate:
1350 dst.emplace(i, -val);
1351 break;
Chris Forbes4d503052019-03-01 17:13:57 -08001352 case spv::OpConvertFToU:
1353 dst.emplace(i, As<SIMD::Float>(SIMD::UInt(val)));
1354 break;
1355 case spv::OpConvertFToS:
1356 dst.emplace(i, As<SIMD::Float>(SIMD::Int(val)));
1357 break;
1358 case spv::OpConvertSToF:
1359 dst.emplace(i, SIMD::Float(As<SIMD::Int>(val)));
1360 break;
1361 case spv::OpConvertUToF:
1362 dst.emplace(i, SIMD::Float(As<SIMD::UInt>(val)));
1363 break;
1364 case spv::OpBitcast:
1365 dst.emplace(i, val);
1366 break;
Ben Claytondd1e37e2019-02-28 19:59:15 +00001367 default:
1368 UNIMPLEMENTED("Unhandled unary operator %s", OpcodeName(insn.opcode()).c_str());
1369 }
1370 }
1371 }
1372
1373 void SpirvShader::EmitBinaryOp(InsnIterator insn, SpirvRoutine *routine) const
1374 {
1375 auto &type = getType(insn.word(1));
1376 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
Chris Forbese86b6dc2019-03-01 09:08:47 -08001377 auto &lhsType = getType(getObject(insn.word(3)).type);
Ben Claytondd1e37e2019-02-28 19:59:15 +00001378 auto srcLHS = GenericValue(this, routine, insn.word(3));
1379 auto srcRHS = GenericValue(this, routine, insn.word(4));
1380
Chris Forbese86b6dc2019-03-01 09:08:47 -08001381 for (auto i = 0u; i < lhsType.sizeInComponents; i++)
Ben Claytondd1e37e2019-02-28 19:59:15 +00001382 {
1383 auto lhs = srcLHS[i];
1384 auto rhs = srcRHS[i];
1385
1386 switch (insn.opcode())
1387 {
1388 case spv::OpIAdd:
1389 dst.emplace(i, As<SIMD::Float>(As<SIMD::Int>(lhs) + As<SIMD::Int>(rhs)));
1390 break;
1391 case spv::OpISub:
1392 dst.emplace(i, As<SIMD::Float>(As<SIMD::Int>(lhs) - As<SIMD::Int>(rhs)));
1393 break;
1394 case spv::OpIMul:
1395 dst.emplace(i, As<SIMD::Float>(As<SIMD::Int>(lhs) * As<SIMD::Int>(rhs)));
1396 break;
1397 case spv::OpSDiv:
1398 dst.emplace(i, As<SIMD::Float>(As<SIMD::Int>(lhs) / As<SIMD::Int>(rhs)));
1399 break;
1400 case spv::OpUDiv:
1401 dst.emplace(i, As<SIMD::Float>(As<SIMD::UInt>(lhs) / As<SIMD::UInt>(rhs)));
1402 break;
1403 case spv::OpUMod:
1404 dst.emplace(i, As<SIMD::Float>(As<SIMD::UInt>(lhs) % As<SIMD::UInt>(rhs)));
1405 break;
Ben Claytone95eeb12019-03-04 16:32:09 +00001406 case spv::OpIEqual:
1407 dst.emplace(i, As<SIMD::Float>(CmpEQ(As<SIMD::Int>(lhs), As<SIMD::Int>(rhs))));
1408 break;
1409 case spv::OpINotEqual:
1410 dst.emplace(i, As<SIMD::Float>(CmpNEQ(As<SIMD::Int>(lhs), As<SIMD::Int>(rhs))));
1411 break;
1412 case spv::OpUGreaterThan:
1413 dst.emplace(i, As<SIMD::Float>(CmpGT(As<SIMD::UInt>(lhs), As<SIMD::UInt>(rhs))));
1414 break;
1415 case spv::OpSGreaterThan:
1416 dst.emplace(i, As<SIMD::Float>(CmpGT(As<SIMD::Int>(lhs), As<SIMD::Int>(rhs))));
1417 break;
1418 case spv::OpUGreaterThanEqual:
1419 dst.emplace(i, As<SIMD::Float>(CmpGE(As<SIMD::UInt>(lhs), As<SIMD::UInt>(rhs))));
1420 break;
1421 case spv::OpSGreaterThanEqual:
1422 dst.emplace(i, As<SIMD::Float>(CmpGE(As<SIMD::Int>(lhs), As<SIMD::Int>(rhs))));
1423 break;
1424 case spv::OpULessThan:
1425 dst.emplace(i, As<SIMD::Float>(CmpLT(As<SIMD::UInt>(lhs), As<SIMD::UInt>(rhs))));
1426 break;
1427 case spv::OpSLessThan:
1428 dst.emplace(i, As<SIMD::Float>(CmpLT(As<SIMD::Int>(lhs), As<SIMD::Int>(rhs))));
1429 break;
1430 case spv::OpULessThanEqual:
1431 dst.emplace(i, As<SIMD::Float>(CmpLE(As<SIMD::UInt>(lhs), As<SIMD::UInt>(rhs))));
1432 break;
1433 case spv::OpSLessThanEqual:
1434 dst.emplace(i, As<SIMD::Float>(CmpLE(As<SIMD::Int>(lhs), As<SIMD::Int>(rhs))));
1435 break;
Ben Claytondd1e37e2019-02-28 19:59:15 +00001436 case spv::OpFAdd:
1437 dst.emplace(i, lhs + rhs);
1438 break;
1439 case spv::OpFSub:
1440 dst.emplace(i, lhs - rhs);
1441 break;
1442 case spv::OpFDiv:
1443 dst.emplace(i, lhs / rhs);
1444 break;
Ben Claytonec1aeb82019-03-04 19:33:27 +00001445 case spv::OpFOrdEqual:
1446 dst.emplace(i, As<SIMD::Float>(CmpEQ(lhs, rhs)));
1447 break;
1448 case spv::OpFUnordEqual:
1449 dst.emplace(i, As<SIMD::Float>(CmpUEQ(lhs, rhs)));
1450 break;
1451 case spv::OpFOrdNotEqual:
1452 dst.emplace(i, As<SIMD::Float>(CmpNEQ(lhs, rhs)));
1453 break;
1454 case spv::OpFUnordNotEqual:
1455 dst.emplace(i, As<SIMD::Float>(CmpUNEQ(lhs, rhs)));
1456 break;
1457 case spv::OpFOrdLessThan:
1458 dst.emplace(i, As<SIMD::Float>(CmpLT(lhs, rhs)));
1459 break;
1460 case spv::OpFUnordLessThan:
1461 dst.emplace(i, As<SIMD::Float>(CmpULT(lhs, rhs)));
1462 break;
1463 case spv::OpFOrdGreaterThan:
1464 dst.emplace(i, As<SIMD::Float>(CmpGT(lhs, rhs)));
1465 break;
1466 case spv::OpFUnordGreaterThan:
1467 dst.emplace(i, As<SIMD::Float>(CmpUGT(lhs, rhs)));
1468 break;
1469 case spv::OpFOrdLessThanEqual:
1470 dst.emplace(i, As<SIMD::Float>(CmpLE(lhs, rhs)));
1471 break;
1472 case spv::OpFUnordLessThanEqual:
1473 dst.emplace(i, As<SIMD::Float>(CmpULE(lhs, rhs)));
1474 break;
1475 case spv::OpFOrdGreaterThanEqual:
1476 dst.emplace(i, As<SIMD::Float>(CmpGE(lhs, rhs)));
1477 break;
1478 case spv::OpFUnordGreaterThanEqual:
1479 dst.emplace(i, As<SIMD::Float>(CmpUGE(lhs, rhs)));
1480 break;
Ben Claytondd1e37e2019-02-28 19:59:15 +00001481 case spv::OpShiftRightLogical:
1482 dst.emplace(i, As<SIMD::Float>(As<SIMD::UInt>(lhs) >> As<SIMD::UInt>(rhs)));
1483 break;
1484 case spv::OpShiftRightArithmetic:
1485 dst.emplace(i, As<SIMD::Float>(As<SIMD::Int>(lhs) >> As<SIMD::Int>(rhs)));
1486 break;
1487 case spv::OpShiftLeftLogical:
1488 dst.emplace(i, As<SIMD::Float>(As<SIMD::UInt>(lhs) << As<SIMD::UInt>(rhs)));
1489 break;
1490 case spv::OpBitwiseOr:
1491 case spv::OpLogicalOr:
1492 dst.emplace(i, As<SIMD::Float>(As<SIMD::UInt>(lhs) | As<SIMD::UInt>(rhs)));
1493 break;
1494 case spv::OpBitwiseXor:
1495 dst.emplace(i, As<SIMD::Float>(As<SIMD::UInt>(lhs) ^ As<SIMD::UInt>(rhs)));
1496 break;
1497 case spv::OpBitwiseAnd:
1498 case spv::OpLogicalAnd:
1499 dst.emplace(i, As<SIMD::Float>(As<SIMD::UInt>(lhs) & As<SIMD::UInt>(rhs)));
1500 break;
Chris Forbese86b6dc2019-03-01 09:08:47 -08001501 case spv::OpSMulExtended:
1502 // Extended ops: result is a structure containing two members of the same type as lhs & rhs.
1503 // In our flat view then, component i is the i'th component of the first member;
1504 // component i + N is the i'th component of the second member.
1505 dst.emplace(i, As<SIMD::Float>(As<SIMD::Int>(lhs) * As<SIMD::Int>(rhs)));
1506 dst.emplace(i + lhsType.sizeInComponents, As<SIMD::Float>(MulHigh(As<SIMD::Int>(lhs), As<SIMD::Int>(rhs))));
1507 break;
1508 case spv::OpUMulExtended:
1509 dst.emplace(i, As<SIMD::Float>(As<SIMD::UInt>(lhs) * As<SIMD::UInt>(rhs)));
1510 dst.emplace(i + lhsType.sizeInComponents, As<SIMD::Float>(MulHigh(As<SIMD::UInt>(lhs), As<SIMD::UInt>(rhs))));
1511 break;
Ben Claytondd1e37e2019-02-28 19:59:15 +00001512 default:
1513 UNIMPLEMENTED("Unhandled binary operator %s", OpcodeName(insn.opcode()).c_str());
1514 }
1515 }
1516 }
1517
Chris Forbes2b287cc2019-03-01 13:24:17 -08001518 void SpirvShader::EmitDot(InsnIterator insn, SpirvRoutine *routine) const
1519 {
1520 auto &type = getType(insn.word(1));
1521 assert(type.sizeInComponents == 1);
1522 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
1523 auto &lhsType = getType(getObject(insn.word(3)).type);
1524 auto srcLHS = GenericValue(this, routine, insn.word(3));
1525 auto srcRHS = GenericValue(this, routine, insn.word(4));
1526
1527 SIMD::Float result = srcLHS[0] * srcRHS[0];
1528
1529 for (auto i = 1u; i < lhsType.sizeInComponents; i++)
1530 {
1531 result += srcLHS[i] * srcRHS[i];
1532 }
1533
1534 dst.emplace(0, result);
1535 }
1536
Ben Claytonbf943f62019-03-05 12:57:39 +00001537 void SpirvShader::EmitSelect(InsnIterator insn, SpirvRoutine *routine) const
1538 {
1539 auto &type = getType(insn.word(1));
1540 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
1541 auto srcCond = GenericValue(this, routine, insn.word(3));
1542 auto srcLHS = GenericValue(this, routine, insn.word(4));
1543 auto srcRHS = GenericValue(this, routine, insn.word(5));
1544
1545 for (auto i = 0u; i < type.sizeInComponents; i++)
1546 {
1547 auto cond = As<SIMD::Int>(srcCond[i]);
1548 auto lhs = srcLHS[i];
1549 auto rhs = srcRHS[i];
1550 auto out = (cond & As<Int4>(lhs)) | (~cond & As<Int4>(rhs)); // FIXME: IfThenElse()
1551 dst.emplace(i, As<SIMD::Float>(out));
1552 }
1553 }
1554
Chris Forbesc61271e2019-02-19 17:01:28 -08001555 void SpirvShader::emitEpilog(SpirvRoutine *routine) const
1556 {
1557 for (auto insn : *this)
1558 {
1559 switch (insn.opcode())
1560 {
1561 case spv::OpVariable:
1562 {
Ben Claytonab51bbf2019-02-20 14:36:27 +00001563 ObjectID resultId = insn.word(2);
Chris Forbesc61271e2019-02-19 17:01:28 -08001564 auto &object = getObject(resultId);
Ben Clayton9a162482019-02-25 11:54:43 +00001565 auto &objectTy = getType(object.type);
1566 if (object.kind == Object::Kind::InterfaceVariable && objectTy.storageClass == spv::StorageClassOutput)
Chris Forbesc61271e2019-02-19 17:01:28 -08001567 {
1568 auto &dst = routine->getValue(resultId);
1569 int offset = 0;
1570 VisitInterface(resultId,
1571 [&](Decorations const &d, AttribType type) {
1572 auto scalarSlot = d.Location << 2 | d.Component;
1573 routine->outputs[scalarSlot] = dst[offset++];
1574 });
1575 }
1576 break;
1577 }
1578 default:
1579 break;
1580 }
1581 }
1582 }
Ben Clayton76e9bc02019-02-26 15:02:18 +00001583
1584 SpirvRoutine::SpirvRoutine(vk::PipelineLayout const *pipelineLayout) :
1585 pipelineLayout(pipelineLayout)
1586 {
1587 }
1588
Chris Forbesc25b8072018-12-10 15:10:39 -08001589}