blob: 3b17a072ec95e77d7dfc31f00d42bec257073767 [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 {
31 // Simplifying assumptions (to be satisfied by earlier transformations)
Chris Forbesbde34082018-12-28 12:03:10 -080032 // - There is exactly one entrypoint in the module, and it's the one we want
Chris Forbesaf4ed532018-12-06 18:33:27 -080033 // - The only input/output OpVariables present are those used by the entrypoint
34
Chris Forbese57f10e2019-03-04 10:53:07 -080035 // TODO: Add real support for control flow. For now, track whether we've seen
36 // a label or a return already (if so, the shader does things we will mishandle).
37 // We expect there to be one of each in a simple shader -- the first and last instruction
38 // of the entrypoint function.
39 bool seenLabel = false;
40 bool seenReturn = false;
41
Chris Forbes4a979dc2019-01-17 09:36:46 -080042 for (auto insn : *this)
43 {
44 switch (insn.opcode())
45 {
46 case spv::OpExecutionMode:
47 ProcessExecutionMode(insn);
48 break;
Chris Forbesaf4ed532018-12-06 18:33:27 -080049
Chris Forbesc25b8072018-12-10 15:10:39 -080050 case spv::OpDecorate:
51 {
Ben Claytonab51bbf2019-02-20 14:36:27 +000052 TypeOrObjectID targetId = insn.word(1);
Chris Forbes93f70b32019-02-10 21:26:27 +000053 auto decoration = static_cast<spv::Decoration>(insn.word(2));
Chris Forbesc25b8072018-12-10 15:10:39 -080054 decorations[targetId].Apply(
Chris Forbes93f70b32019-02-10 21:26:27 +000055 decoration,
Chris Forbesc25b8072018-12-10 15:10:39 -080056 insn.wordCount() > 3 ? insn.word(3) : 0);
Chris Forbes93f70b32019-02-10 21:26:27 +000057
58 if (decoration == spv::DecorationCentroid)
59 modes.NeedsCentroid = true;
Chris Forbesc25b8072018-12-10 15:10:39 -080060 break;
61 }
62
63 case spv::OpMemberDecorate:
64 {
Ben Claytonab51bbf2019-02-20 14:36:27 +000065 TypeID targetId = insn.word(1);
Chris Forbesc25b8072018-12-10 15:10:39 -080066 auto memberIndex = insn.word(2);
67 auto &d = memberDecorations[targetId];
68 if (memberIndex >= d.size())
69 d.resize(memberIndex + 1); // on demand; exact size would require another pass...
Chris Forbes93f70b32019-02-10 21:26:27 +000070 auto decoration = static_cast<spv::Decoration>(insn.word(3));
Chris Forbesc25b8072018-12-10 15:10:39 -080071 d[memberIndex].Apply(
Chris Forbes93f70b32019-02-10 21:26:27 +000072 decoration,
Chris Forbesc25b8072018-12-10 15:10:39 -080073 insn.wordCount() > 4 ? insn.word(4) : 0);
Chris Forbes93f70b32019-02-10 21:26:27 +000074
75 if (decoration == spv::DecorationCentroid)
76 modes.NeedsCentroid = true;
Chris Forbesc25b8072018-12-10 15:10:39 -080077 break;
78 }
79
80 case spv::OpDecorationGroup:
81 // Nothing to do here. We don't need to record the definition of the group; we'll just have
82 // the bundle of decorations float around. If we were to ever walk the decorations directly,
83 // we might think about introducing this as a real Object.
84 break;
85
86 case spv::OpGroupDecorate:
87 {
88 auto const &srcDecorations = decorations[insn.word(1)];
89 for (auto i = 2u; i < insn.wordCount(); i++)
90 {
91 // remaining operands are targets to apply the group to.
92 decorations[insn.word(i)].Apply(srcDecorations);
93 }
94 break;
95 }
96
97 case spv::OpGroupMemberDecorate:
98 {
99 auto const &srcDecorations = decorations[insn.word(1)];
100 for (auto i = 2u; i < insn.wordCount(); i += 2)
101 {
102 // remaining operands are pairs of <id>, literal for members to apply to.
103 auto &d = memberDecorations[insn.word(i)];
104 auto memberIndex = insn.word(i + 1);
105 if (memberIndex >= d.size())
106 d.resize(memberIndex + 1); // on demand resize, see above...
107 d[memberIndex].Apply(srcDecorations);
108 }
109 break;
110 }
111
Chris Forbese57f10e2019-03-04 10:53:07 -0800112 case spv::OpLabel:
113 if (seenLabel)
114 UNIMPLEMENTED("Shader contains multiple labels, has control flow");
115 seenLabel = true;
116 break;
117
118 case spv::OpReturn:
119 if (seenReturn)
120 UNIMPLEMENTED("Shader contains multiple returns, has control flow");
121 seenReturn = true;
122 break;
123
Chris Forbes4a979dc2019-01-17 09:36:46 -0800124 case spv::OpTypeVoid:
125 case spv::OpTypeBool:
126 case spv::OpTypeInt:
127 case spv::OpTypeFloat:
128 case spv::OpTypeVector:
129 case spv::OpTypeMatrix:
130 case spv::OpTypeImage:
131 case spv::OpTypeSampler:
132 case spv::OpTypeSampledImage:
133 case spv::OpTypeArray:
134 case spv::OpTypeRuntimeArray:
135 case spv::OpTypeStruct:
136 case spv::OpTypePointer:
137 case spv::OpTypeFunction:
Ben Clayton0bb83b82019-02-26 11:41:07 +0000138 DeclareType(insn);
Chris Forbes4a979dc2019-01-17 09:36:46 -0800139 break;
Chris Forbes296aa252018-12-27 11:48:21 -0800140
Chris Forbes4a979dc2019-01-17 09:36:46 -0800141 case spv::OpVariable:
142 {
Ben Claytonab51bbf2019-02-20 14:36:27 +0000143 TypeID typeId = insn.word(1);
144 ObjectID resultId = insn.word(2);
Chris Forbes4a979dc2019-01-17 09:36:46 -0800145 auto storageClass = static_cast<spv::StorageClass>(insn.word(3));
146 if (insn.wordCount() > 4)
147 UNIMPLEMENTED("Variable initializers not yet supported");
Chris Forbes296aa252018-12-27 11:48:21 -0800148
Chris Forbes4a979dc2019-01-17 09:36:46 -0800149 auto &object = defs[resultId];
150 object.kind = Object::Kind::Variable;
151 object.definition = insn;
Ben Clayton9a162482019-02-25 11:54:43 +0000152 object.type = typeId;
Chris Forbese9f8f5b2019-02-11 00:20:16 +0000153 object.pointerBase = insn.word(2); // base is itself
Chris Forbesc25b8072018-12-10 15:10:39 -0800154
155 // Register builtins
Ben Claytona1924732019-02-28 18:42:10 +0000156 if (storageClass == spv::StorageClassInput || storageClass == spv::StorageClassOutput)
Chris Forbesc25b8072018-12-10 15:10:39 -0800157 {
Ben Claytona1924732019-02-28 18:42:10 +0000158 ProcessInterfaceVariable(object);
Chris Forbesc25b8072018-12-10 15:10:39 -0800159 }
Chris Forbes4a979dc2019-01-17 09:36:46 -0800160 break;
161 }
Chris Forbes296aa252018-12-27 11:48:21 -0800162
Chris Forbesbc3a0ee2018-12-27 16:02:58 -0800163 case spv::OpConstant:
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800164 CreateConstant(insn).constantValue[0] = insn.word(3);
165 break;
Chris Forbesbc3a0ee2018-12-27 16:02:58 -0800166 case spv::OpConstantFalse:
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800167 CreateConstant(insn).constantValue[0] = 0; // represent boolean false as zero
168 break;
Chris Forbesbc3a0ee2018-12-27 16:02:58 -0800169 case spv::OpConstantTrue:
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800170 CreateConstant(insn).constantValue[0] = ~0u; // represent boolean true as all bits set
171 break;
Chris Forbesbc3a0ee2018-12-27 16:02:58 -0800172 case spv::OpConstantNull:
173 {
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800174 // OpConstantNull forms a constant of arbitrary type, all zeros.
Ben Clayton9a162482019-02-25 11:54:43 +0000175 auto &object = CreateConstant(insn);
176 auto &objectTy = getType(object.type);
177 for (auto i = 0u; i < objectTy.sizeInComponents; i++)
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800178 {
179 object.constantValue[i] = 0;
180 }
181 break;
182 }
183 case spv::OpConstantComposite:
184 {
185 auto &object = CreateConstant(insn);
186 auto offset = 0u;
187 for (auto i = 0u; i < insn.wordCount() - 3; i++)
188 {
Ben Clayton9a162482019-02-25 11:54:43 +0000189 auto &constituent = getObject(insn.word(i + 3));
190 auto &constituentTy = getType(constituent.type);
191 for (auto j = 0u; j < constituentTy.sizeInComponents; j++)
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800192 object.constantValue[offset++] = constituent.constantValue[j];
193 }
Chris Forbesbc3a0ee2018-12-27 16:02:58 -0800194 break;
195 }
196
Chris Forbesbde34082018-12-28 12:03:10 -0800197 case spv::OpCapability:
198 // Various capabilities will be declared, but none affect our code generation at this point.
199 case spv::OpMemoryModel:
200 // Memory model does not affect our code generation until we decide to do Vulkan Memory Model support.
201 case spv::OpEntryPoint:
Chris Forbes7edf5342019-02-10 22:41:21 +0000202 case spv::OpFunction:
203 case spv::OpFunctionEnd:
204 // Due to preprocessing, the entrypoint and its function provide no value.
205 break;
206 case spv::OpExtInstImport:
207 // We will only support the GLSL 450 extended instruction set, so no point in tracking the ID we assign it.
208 // Valid shaders will not attempt to import any other instruction sets.
Chris Forbes1776af72019-02-22 17:39:57 -0800209 case spv::OpName:
210 case spv::OpMemberName:
211 case spv::OpSource:
212 case spv::OpSourceContinued:
213 case spv::OpSourceExtension:
214 // No semantic impact
Chris Forbes7edf5342019-02-10 22:41:21 +0000215 break;
216
217 case spv::OpFunctionParameter:
218 case spv::OpFunctionCall:
219 case spv::OpSpecConstant:
220 case spv::OpSpecConstantComposite:
221 case spv::OpSpecConstantFalse:
222 case spv::OpSpecConstantOp:
223 case spv::OpSpecConstantTrue:
224 // These should have all been removed by preprocessing passes. If we see them here,
225 // our assumptions are wrong and we will probably generate wrong code.
226 UNIMPLEMENTED("These instructions should have already been lowered.");
227 break;
228
Chris Forbes4d503052019-03-01 17:13:57 -0800229 case spv::OpFConvert:
230 case spv::OpSConvert:
231 case spv::OpUConvert:
232 UNIMPLEMENTED("No valid uses for Op*Convert until we support multiple bit widths");
233 break;
234
Chris Forbesa71b8e92019-02-10 22:42:42 +0000235 case spv::OpLoad:
236 case spv::OpAccessChain:
Chris Forbesb97a9572019-02-21 16:51:42 -0800237 case spv::OpCompositeConstruct:
Chris Forbes1bc1acf2019-02-21 18:40:33 -0800238 case spv::OpCompositeInsert:
Chris Forbesb12846d2019-02-21 18:53:58 -0800239 case spv::OpCompositeExtract:
Chris Forbes83fc5442019-02-26 22:16:07 -0800240 case spv::OpVectorShuffle:
Ben Claytondd1e37e2019-02-28 19:59:15 +0000241 case spv::OpNot: // Unary ops
242 case spv::OpSNegate:
243 case spv::OpFNegate:
244 case spv::OpLogicalNot:
245 case spv::OpIAdd: // Binary ops
246 case spv::OpISub:
247 case spv::OpIMul:
248 case spv::OpSDiv:
249 case spv::OpUDiv:
250 case spv::OpFAdd:
251 case spv::OpFSub:
252 case spv::OpFDiv:
Ben Claytonec1aeb82019-03-04 19:33:27 +0000253 case spv::OpFOrdEqual:
254 case spv::OpFUnordEqual:
255 case spv::OpFOrdNotEqual:
256 case spv::OpFUnordNotEqual:
257 case spv::OpFOrdLessThan:
258 case spv::OpFUnordLessThan:
259 case spv::OpFOrdGreaterThan:
260 case spv::OpFUnordGreaterThan:
261 case spv::OpFOrdLessThanEqual:
262 case spv::OpFUnordLessThanEqual:
263 case spv::OpFOrdGreaterThanEqual:
264 case spv::OpFUnordGreaterThanEqual:
Ben Claytondd1e37e2019-02-28 19:59:15 +0000265 case spv::OpUMod:
Ben Claytone95eeb12019-03-04 16:32:09 +0000266 case spv::OpIEqual:
267 case spv::OpINotEqual:
268 case spv::OpUGreaterThan:
269 case spv::OpSGreaterThan:
270 case spv::OpUGreaterThanEqual:
271 case spv::OpSGreaterThanEqual:
272 case spv::OpULessThan:
273 case spv::OpSLessThan:
274 case spv::OpULessThanEqual:
275 case spv::OpSLessThanEqual:
Ben Claytondd1e37e2019-02-28 19:59:15 +0000276 case spv::OpShiftRightLogical:
277 case spv::OpShiftRightArithmetic:
278 case spv::OpShiftLeftLogical:
279 case spv::OpBitwiseOr:
280 case spv::OpBitwiseXor:
281 case spv::OpBitwiseAnd:
282 case spv::OpLogicalOr:
283 case spv::OpLogicalAnd:
Chris Forbese86b6dc2019-03-01 09:08:47 -0800284 case spv::OpUMulExtended:
285 case spv::OpSMulExtended:
Chris Forbes2b287cc2019-03-01 13:24:17 -0800286 case spv::OpDot:
Chris Forbes4d503052019-03-01 17:13:57 -0800287 case spv::OpConvertFToU:
288 case spv::OpConvertFToS:
289 case spv::OpConvertSToF:
290 case spv::OpConvertUToF:
291 case spv::OpBitcast:
Ben Claytonbf943f62019-03-05 12:57:39 +0000292 case spv::OpSelect:
Chris Forbese86b6dc2019-03-01 09:08:47 -0800293 // Instructions that yield an intermediate value
Chris Forbesa71b8e92019-02-10 22:42:42 +0000294 {
Ben Claytonab51bbf2019-02-20 14:36:27 +0000295 TypeID typeId = insn.word(1);
296 ObjectID resultId = insn.word(2);
Chris Forbesa71b8e92019-02-10 22:42:42 +0000297 auto &object = defs[resultId];
Ben Clayton9a162482019-02-25 11:54:43 +0000298 object.type = typeId;
Chris Forbesa71b8e92019-02-10 22:42:42 +0000299 object.kind = Object::Kind::Value;
300 object.definition = insn;
Chris Forbesa71b8e92019-02-10 22:42:42 +0000301
302 if (insn.opcode() == spv::OpAccessChain)
303 {
304 // interior ptr has two parts:
305 // - logical base ptr, common across all lanes and known at compile time
306 // - per-lane offset
Ben Clayton9a162482019-02-25 11:54:43 +0000307 ObjectID baseId = insn.word(3);
308 object.pointerBase = getObject(baseId).pointerBase;
Chris Forbesa71b8e92019-02-10 22:42:42 +0000309 }
310 break;
311 }
312
Chris Forbes7edf5342019-02-10 22:41:21 +0000313 case spv::OpStore:
Chris Forbes7edf5342019-02-10 22:41:21 +0000314 // Don't need to do anything during analysis pass
315 break;
316
317 case spv::OpKill:
318 modes.ContainsKill = true;
Chris Forbesbde34082018-12-28 12:03:10 -0800319 break;
320
Chris Forbes4a979dc2019-01-17 09:36:46 -0800321 default:
Chris Forbese57f10e2019-03-04 10:53:07 -0800322 UNIMPLEMENTED(OpcodeName(insn.opcode()).c_str());
Chris Forbesaf4ed532018-12-06 18:33:27 -0800323 }
324 }
325 }
326
Ben Clayton0bb83b82019-02-26 11:41:07 +0000327 void SpirvShader::DeclareType(InsnIterator insn)
328 {
329 TypeID resultId = insn.word(1);
330
331 auto &type = types[resultId];
332 type.definition = insn;
333 type.sizeInComponents = ComputeTypeSize(insn);
334
335 // A structure is a builtin block if it has a builtin
336 // member. All members of such a structure are builtins.
337 switch (insn.opcode())
338 {
339 case spv::OpTypeStruct:
340 {
341 auto d = memberDecorations.find(resultId);
342 if (d != memberDecorations.end())
343 {
344 for (auto &m : d->second)
345 {
346 if (m.HasBuiltIn)
347 {
348 type.isBuiltInBlock = true;
349 break;
350 }
351 }
352 }
353 break;
354 }
355 case spv::OpTypePointer:
356 {
357 TypeID elementTypeId = insn.word(3);
358 type.element = elementTypeId;
359 type.isBuiltInBlock = getType(elementTypeId).isBuiltInBlock;
360 type.storageClass = static_cast<spv::StorageClass>(insn.word(2));
361 break;
362 }
363 case spv::OpTypeVector:
364 case spv::OpTypeMatrix:
365 case spv::OpTypeArray:
366 case spv::OpTypeRuntimeArray:
367 {
368 TypeID elementTypeId = insn.word(2);
369 type.element = elementTypeId;
370 break;
371 }
372 default:
373 break;
374 }
375 }
376
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800377 SpirvShader::Object& SpirvShader::CreateConstant(InsnIterator insn)
378 {
Ben Claytonab51bbf2019-02-20 14:36:27 +0000379 TypeID typeId = insn.word(1);
380 ObjectID resultId = insn.word(2);
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800381 auto &object = defs[resultId];
Ben Clayton9a162482019-02-25 11:54:43 +0000382 auto &objectTy = getType(typeId);
383 object.type = typeId;
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800384 object.kind = Object::Kind::Constant;
385 object.definition = insn;
Ben Clayton9a162482019-02-25 11:54:43 +0000386 object.constantValue = std::unique_ptr<uint32_t[]>(new uint32_t[objectTy.sizeInComponents]);
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800387 return object;
388 }
389
Chris Forbes049ff382019-02-02 15:16:43 -0800390 void SpirvShader::ProcessInterfaceVariable(Object &object)
Chris Forbesbde34082018-12-28 12:03:10 -0800391 {
Ben Clayton9a162482019-02-25 11:54:43 +0000392 auto &objectTy = getType(object.type);
Ben Clayton6fae32c2019-02-28 20:06:42 +0000393 ASSERT(objectTy.storageClass == spv::StorageClassInput || objectTy.storageClass == spv::StorageClassOutput);
Chris Forbesbde34082018-12-28 12:03:10 -0800394
Ben Clayton6fae32c2019-02-28 20:06:42 +0000395 ASSERT(objectTy.definition.opcode() == spv::OpTypePointer);
Ben Clayton9a162482019-02-25 11:54:43 +0000396 auto pointeeTy = getType(objectTy.element);
Chris Forbesbde34082018-12-28 12:03:10 -0800397
Ben Clayton9a162482019-02-25 11:54:43 +0000398 auto &builtinInterface = (objectTy.storageClass == spv::StorageClassInput) ? inputBuiltins : outputBuiltins;
399 auto &userDefinedInterface = (objectTy.storageClass == spv::StorageClassInput) ? inputs : outputs;
400
Ben Clayton6fae32c2019-02-28 20:06:42 +0000401 ASSERT(object.definition.opcode() == spv::OpVariable);
Ben Claytonab51bbf2019-02-20 14:36:27 +0000402 ObjectID resultId = object.definition.word(2);
Ben Clayton9a162482019-02-25 11:54:43 +0000403
404 if (objectTy.isBuiltInBlock)
Chris Forbesbde34082018-12-28 12:03:10 -0800405 {
406 // walk the builtin block, registering each of its members separately.
Ben Clayton9a162482019-02-25 11:54:43 +0000407 auto m = memberDecorations.find(objectTy.element);
Ben Clayton6fae32c2019-02-28 20:06:42 +0000408 ASSERT(m != memberDecorations.end()); // otherwise we wouldn't have marked the type chain
Ben Clayton9a162482019-02-25 11:54:43 +0000409 auto &structType = pointeeTy.definition;
Chris Forbesbde34082018-12-28 12:03:10 -0800410 auto offset = 0u;
411 auto word = 2u;
412 for (auto &member : m->second)
413 {
Chris Forbes840809a2019-01-14 14:30:20 -0800414 auto &memberType = getType(structType.word(word));
Chris Forbesbde34082018-12-28 12:03:10 -0800415
416 if (member.HasBuiltIn)
417 {
418 builtinInterface[member.BuiltIn] = {resultId, offset, memberType.sizeInComponents};
419 }
420
421 offset += memberType.sizeInComponents;
422 ++word;
423 }
424 return;
425 }
426
427 auto d = decorations.find(resultId);
428 if (d != decorations.end() && d->second.HasBuiltIn)
429 {
Ben Clayton9a162482019-02-25 11:54:43 +0000430 builtinInterface[d->second.BuiltIn] = {resultId, 0, pointeeTy.sizeInComponents};
Chris Forbesbde34082018-12-28 12:03:10 -0800431 }
432 else
433 {
Chris Forbes049ff382019-02-02 15:16:43 -0800434 object.kind = Object::Kind::InterfaceVariable;
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800435 VisitInterface(resultId,
436 [&userDefinedInterface](Decorations const &d, AttribType type) {
437 // Populate a single scalar slot in the interface from a collection of decorations and the intended component type.
438 auto scalarSlot = (d.Location << 2) | d.Component;
Ben Clayton6fae32c2019-02-28 20:06:42 +0000439 ASSERT(scalarSlot >= 0 &&
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800440 scalarSlot < static_cast<int32_t>(userDefinedInterface.size()));
441
442 auto &slot = userDefinedInterface[scalarSlot];
443 slot.Type = type;
444 slot.Flat = d.Flat;
445 slot.NoPerspective = d.NoPerspective;
446 slot.Centroid = d.Centroid;
447 });
Chris Forbesbde34082018-12-28 12:03:10 -0800448 }
449 }
450
Chris Forbesaf4ed532018-12-06 18:33:27 -0800451 void SpirvShader::ProcessExecutionMode(InsnIterator insn)
452 {
453 auto mode = static_cast<spv::ExecutionMode>(insn.word(2));
Chris Forbes4a979dc2019-01-17 09:36:46 -0800454 switch (mode)
455 {
456 case spv::ExecutionModeEarlyFragmentTests:
457 modes.EarlyFragmentTests = true;
458 break;
459 case spv::ExecutionModeDepthReplacing:
460 modes.DepthReplacing = true;
461 break;
462 case spv::ExecutionModeDepthGreater:
463 modes.DepthGreater = true;
464 break;
465 case spv::ExecutionModeDepthLess:
466 modes.DepthLess = true;
467 break;
468 case spv::ExecutionModeDepthUnchanged:
469 modes.DepthUnchanged = true;
470 break;
471 case spv::ExecutionModeLocalSize:
472 modes.LocalSizeX = insn.word(3);
473 modes.LocalSizeZ = insn.word(5);
474 modes.LocalSizeY = insn.word(4);
475 break;
476 case spv::ExecutionModeOriginUpperLeft:
477 // This is always the case for a Vulkan shader. Do nothing.
478 break;
479 default:
480 UNIMPLEMENTED("No other execution modes are permitted");
Chris Forbesaf4ed532018-12-06 18:33:27 -0800481 }
482 }
Chris Forbes739a7fb2018-12-08 13:09:40 -0800483
484 uint32_t SpirvShader::ComputeTypeSize(sw::SpirvShader::InsnIterator insn)
485 {
486 // Types are always built from the bottom up (with the exception of forward ptrs, which
487 // don't appear in Vulkan shaders. Therefore, we can always assume our component parts have
488 // already been described (and so their sizes determined)
489 switch (insn.opcode())
490 {
491 case spv::OpTypeVoid:
492 case spv::OpTypeSampler:
493 case spv::OpTypeImage:
494 case spv::OpTypeSampledImage:
495 case spv::OpTypeFunction:
496 case spv::OpTypeRuntimeArray:
497 // Objects that don't consume any space.
498 // Descriptor-backed objects currently only need exist at compile-time.
499 // Runtime arrays don't appear in places where their size would be interesting
500 return 0;
501
502 case spv::OpTypeBool:
503 case spv::OpTypeFloat:
504 case spv::OpTypeInt:
505 // All the fundamental types are 1 component. If we ever add support for 8/16/64-bit components,
506 // we might need to change this, but only 32 bit components are required for Vulkan 1.1.
507 return 1;
508
509 case spv::OpTypeVector:
510 case spv::OpTypeMatrix:
511 // Vectors and matrices both consume element count * element size.
Chris Forbes840809a2019-01-14 14:30:20 -0800512 return getType(insn.word(2)).sizeInComponents * insn.word(3);
Chris Forbes739a7fb2018-12-08 13:09:40 -0800513
514 case spv::OpTypeArray:
Chris Forbes5be4d702018-12-27 16:12:31 -0800515 {
516 // Element count * element size. Array sizes come from constant ids.
517 auto arraySize = GetConstantInt(insn.word(3));
Chris Forbes840809a2019-01-14 14:30:20 -0800518 return getType(insn.word(2)).sizeInComponents * arraySize;
Chris Forbes5be4d702018-12-27 16:12:31 -0800519 }
Chris Forbes739a7fb2018-12-08 13:09:40 -0800520
521 case spv::OpTypeStruct:
522 {
523 uint32_t size = 0;
524 for (uint32_t i = 2u; i < insn.wordCount(); i++)
525 {
Chris Forbes840809a2019-01-14 14:30:20 -0800526 size += getType(insn.word(i)).sizeInComponents;
Chris Forbes739a7fb2018-12-08 13:09:40 -0800527 }
528 return size;
529 }
530
531 case spv::OpTypePointer:
Chris Forbes0f59a2c2019-02-10 23:03:12 +0000532 // Runtime representation of a pointer is a per-lane index.
533 // Note: clients are expected to look through the pointer if they want the pointee size instead.
534 return 1;
Chris Forbes739a7fb2018-12-08 13:09:40 -0800535
536 default:
537 // Some other random insn.
538 UNIMPLEMENTED("Only types are supported");
Ben Clayton60a3d6f2019-02-26 17:24:46 +0000539 return 0;
Chris Forbes739a7fb2018-12-08 13:09:40 -0800540 }
541 }
Chris Forbesc25b8072018-12-10 15:10:39 -0800542
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800543 template<typename F>
Ben Claytonab51bbf2019-02-20 14:36:27 +0000544 int SpirvShader::VisitInterfaceInner(TypeID id, Decorations d, F f) const
Chris Forbes5839dcf2018-12-10 19:02:58 -0800545 {
546 // Recursively walks variable definition and its type tree, taking into account
547 // any explicit Location or Component decorations encountered; where explicit
548 // Locations or Components are not specified, assigns them sequentially.
549 // Collected decorations are carried down toward the leaves and across
550 // siblings; Effect of decorations intentionally does not flow back up the tree.
551 //
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800552 // F is a functor to be called with the effective decoration set for every component.
553 //
554 // Returns the next available location, and calls f().
Chris Forbes5839dcf2018-12-10 19:02:58 -0800555
556 // This covers the rules in Vulkan 1.1 spec, 14.1.4 Location Assignment.
557
Chris Forbes49d664d2019-02-12 19:24:50 +0000558 ApplyDecorationsForId(&d, id);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800559
Chris Forbes840809a2019-01-14 14:30:20 -0800560 auto const &obj = getType(id);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800561 switch (obj.definition.opcode())
562 {
Chris Forbes5839dcf2018-12-10 19:02:58 -0800563 case spv::OpTypePointer:
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800564 return VisitInterfaceInner<F>(obj.definition.word(3), d, f);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800565 case spv::OpTypeMatrix:
566 for (auto i = 0u; i < obj.definition.word(3); i++, d.Location++)
567 {
568 // consumes same components of N consecutive locations
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800569 VisitInterfaceInner<F>(obj.definition.word(2), d, f);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800570 }
571 return d.Location;
572 case spv::OpTypeVector:
573 for (auto i = 0u; i < obj.definition.word(3); i++, d.Component++)
574 {
575 // consumes N consecutive components in the same location
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800576 VisitInterfaceInner<F>(obj.definition.word(2), d, f);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800577 }
578 return d.Location + 1;
579 case spv::OpTypeFloat:
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800580 f(d, ATTRIBTYPE_FLOAT);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800581 return d.Location + 1;
582 case spv::OpTypeInt:
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800583 f(d, obj.definition.word(3) ? ATTRIBTYPE_INT : ATTRIBTYPE_UINT);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800584 return d.Location + 1;
585 case spv::OpTypeBool:
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800586 f(d, ATTRIBTYPE_UINT);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800587 return d.Location + 1;
588 case spv::OpTypeStruct:
589 {
Chris Forbes5839dcf2018-12-10 19:02:58 -0800590 // iterate over members, which may themselves have Location/Component decorations
591 for (auto i = 0u; i < obj.definition.wordCount() - 2; i++)
592 {
Chris Forbes49d664d2019-02-12 19:24:50 +0000593 ApplyDecorationsForIdMember(&d, id, i);
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800594 d.Location = VisitInterfaceInner<F>(obj.definition.word(i + 2), d, f);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800595 d.Component = 0; // Implicit locations always have component=0
596 }
597 return d.Location;
598 }
Chris Forbes5be4d702018-12-27 16:12:31 -0800599 case spv::OpTypeArray:
600 {
601 auto arraySize = GetConstantInt(obj.definition.word(3));
602 for (auto i = 0u; i < arraySize; i++)
603 {
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800604 d.Location = VisitInterfaceInner<F>(obj.definition.word(2), d, f);
Chris Forbes5be4d702018-12-27 16:12:31 -0800605 }
606 return d.Location;
607 }
Chris Forbes5839dcf2018-12-10 19:02:58 -0800608 default:
609 // Intentionally partial; most opcodes do not participate in type hierarchies
610 return 0;
611 }
612 }
613
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800614 template<typename F>
Ben Claytonab51bbf2019-02-20 14:36:27 +0000615 void SpirvShader::VisitInterface(ObjectID id, F f) const
Chris Forbes5839dcf2018-12-10 19:02:58 -0800616 {
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800617 // Walk a variable definition and call f for each component in it.
Chris Forbes5839dcf2018-12-10 19:02:58 -0800618 Decorations d{};
Chris Forbes49d664d2019-02-12 19:24:50 +0000619 ApplyDecorationsForId(&d, id);
Chris Forbes1c658232019-02-01 17:12:25 -0800620
621 auto def = getObject(id).definition;
Ben Clayton6fae32c2019-02-28 20:06:42 +0000622 ASSERT(def.opcode() == spv::OpVariable);
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800623 VisitInterfaceInner<F>(def.word(1), d, f);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800624 }
625
Ben Clayton24ea5152019-02-26 11:02:42 +0000626 SIMD::Int SpirvShader::WalkAccessChain(ObjectID id, uint32_t numIndexes, uint32_t const *indexIds, SpirvRoutine *routine) const
Chris Forbes38f85b32019-02-12 20:10:05 +0000627 {
Chris Forbes38f85b32019-02-12 20:10:05 +0000628 // TODO: think about explicit layout (UBO/SSBO) storage classes
629 // TODO: avoid doing per-lane work in some cases if we can?
630
Chris Forbes6397ed02019-02-15 16:39:17 -0800631 int constantOffset = 0;
Ben Clayton24ea5152019-02-26 11:02:42 +0000632 SIMD::Int dynamicOffset = SIMD::Int(0);
Ben Clayton9a162482019-02-25 11:54:43 +0000633 auto &baseObject = getObject(id);
634 TypeID typeId = getType(baseObject.type).element;
Chris Forbes38f85b32019-02-12 20:10:05 +0000635
Chris Forbese4ef5f72019-02-15 16:00:08 -0800636 // The <base> operand is an intermediate value itself, ie produced by a previous OpAccessChain.
637 // Start with its offset and build from there.
Chris Forbes38f85b32019-02-12 20:10:05 +0000638 if (baseObject.kind == Object::Kind::Value)
Ben Clayton24ea5152019-02-26 11:02:42 +0000639 dynamicOffset += As<SIMD::Int>(routine->getIntermediate(id)[0]);
Chris Forbes38f85b32019-02-12 20:10:05 +0000640
641 for (auto i = 0u; i < numIndexes; i++)
642 {
643 auto & type = getType(typeId);
644 switch (type.definition.opcode())
645 {
646 case spv::OpTypeStruct:
647 {
648 int memberIndex = GetConstantInt(indexIds[i]);
649 int offsetIntoStruct = 0;
650 for (auto j = 0; j < memberIndex; j++) {
Chris Forbes58bee562019-02-19 17:41:41 -0800651 auto memberType = type.definition.word(2u + j);
652 offsetIntoStruct += getType(memberType).sizeInComponents;
Chris Forbes38f85b32019-02-12 20:10:05 +0000653 }
Chris Forbes6397ed02019-02-15 16:39:17 -0800654 constantOffset += offsetIntoStruct;
Chris Forbes58bee562019-02-19 17:41:41 -0800655 typeId = type.definition.word(2u + memberIndex);
Chris Forbes38f85b32019-02-12 20:10:05 +0000656 break;
657 }
658
659 case spv::OpTypeVector:
660 case spv::OpTypeMatrix:
661 case spv::OpTypeArray:
662 {
Ben Clayton9a162482019-02-25 11:54:43 +0000663 auto stride = getType(type.element).sizeInComponents;
Chris Forbes38f85b32019-02-12 20:10:05 +0000664 auto & obj = getObject(indexIds[i]);
665 if (obj.kind == Object::Kind::Constant)
Chris Forbes6397ed02019-02-15 16:39:17 -0800666 constantOffset += stride * GetConstantInt(indexIds[i]);
Chris Forbes38f85b32019-02-12 20:10:05 +0000667 else
Ben Clayton24ea5152019-02-26 11:02:42 +0000668 dynamicOffset += SIMD::Int(stride) * As<SIMD::Int>(routine->getIntermediate(indexIds[i])[0]);
Ben Clayton9a162482019-02-25 11:54:43 +0000669 typeId = type.element;
Chris Forbes38f85b32019-02-12 20:10:05 +0000670 break;
671 }
672
673 default:
Ben Claytond4e4c662019-02-26 11:54:34 +0000674 UNIMPLEMENTED("Unexpected type '%s' in WalkAccessChain", OpcodeName(type.definition.opcode()).c_str());
Chris Forbes38f85b32019-02-12 20:10:05 +0000675 }
676 }
677
Ben Clayton24ea5152019-02-26 11:02:42 +0000678 return dynamicOffset + SIMD::Int(constantOffset);
Chris Forbes38f85b32019-02-12 20:10:05 +0000679 }
680
Chris Forbes9638b942019-02-21 18:39:31 -0800681 uint32_t SpirvShader::WalkLiteralAccessChain(TypeID typeId, uint32_t numIndexes, uint32_t const *indexes) const
682 {
683 uint32_t constantOffset = 0;
684
685 for (auto i = 0u; i < numIndexes; i++)
686 {
687 auto & type = getType(typeId);
688 switch (type.definition.opcode())
689 {
690 case spv::OpTypeStruct:
691 {
692 int memberIndex = indexes[i];
693 int offsetIntoStruct = 0;
694 for (auto j = 0; j < memberIndex; j++) {
695 auto memberType = type.definition.word(2u + j);
696 offsetIntoStruct += getType(memberType).sizeInComponents;
697 }
698 constantOffset += offsetIntoStruct;
699 typeId = type.definition.word(2u + memberIndex);
700 break;
701 }
702
703 case spv::OpTypeVector:
704 case spv::OpTypeMatrix:
705 case spv::OpTypeArray:
706 {
707 auto elementType = type.definition.word(2);
708 auto stride = getType(elementType).sizeInComponents;
709 constantOffset += stride * indexes[i];
710 typeId = elementType;
711 break;
712 }
713
714 default:
715 UNIMPLEMENTED("Unexpected type in WalkLiteralAccessChain");
716 }
717 }
718
719 return constantOffset;
720 }
721
Chris Forbesc25b8072018-12-10 15:10:39 -0800722 void SpirvShader::Decorations::Apply(spv::Decoration decoration, uint32_t arg)
723 {
724 switch (decoration)
725 {
726 case spv::DecorationLocation:
727 HasLocation = true;
728 Location = static_cast<int32_t>(arg);
729 break;
730 case spv::DecorationComponent:
731 HasComponent = true;
732 Component = arg;
733 break;
Ben Claytond073d8e2019-02-26 11:06:50 +0000734 case spv::DecorationDescriptorSet:
735 HasDescriptorSet = true;
736 DescriptorSet = arg;
737 break;
738 case spv::DecorationBinding:
739 HasBinding = true;
740 Binding = arg;
741 break;
Chris Forbesc25b8072018-12-10 15:10:39 -0800742 case spv::DecorationBuiltIn:
743 HasBuiltIn = true;
744 BuiltIn = static_cast<spv::BuiltIn>(arg);
745 break;
746 case spv::DecorationFlat:
747 Flat = true;
748 break;
749 case spv::DecorationNoPerspective:
Chris Forbes5839dcf2018-12-10 19:02:58 -0800750 NoPerspective = true;
Chris Forbesc25b8072018-12-10 15:10:39 -0800751 break;
752 case spv::DecorationCentroid:
753 Centroid = true;
754 break;
755 case spv::DecorationBlock:
756 Block = true;
757 break;
758 case spv::DecorationBufferBlock:
759 BufferBlock = true;
760 break;
761 default:
762 // Intentionally partial, there are many decorations we just don't care about.
763 break;
764 }
765 }
766
767 void SpirvShader::Decorations::Apply(const sw::SpirvShader::Decorations &src)
768 {
769 // Apply a decoration group to this set of decorations
770 if (src.HasBuiltIn)
771 {
772 HasBuiltIn = true;
773 BuiltIn = src.BuiltIn;
774 }
775
776 if (src.HasLocation)
777 {
778 HasLocation = true;
779 Location = src.Location;
780 }
781
782 if (src.HasComponent)
783 {
784 HasComponent = true;
785 Component = src.Component;
786 }
787
Ben Claytond073d8e2019-02-26 11:06:50 +0000788 if (src.HasDescriptorSet)
789 {
790 HasDescriptorSet = true;
791 DescriptorSet = src.DescriptorSet;
792 }
793
794 if (src.HasBinding)
795 {
796 HasBinding = true;
797 Binding = src.Binding;
798 }
799
Chris Forbesc25b8072018-12-10 15:10:39 -0800800 Flat |= src.Flat;
Chris Forbes5839dcf2018-12-10 19:02:58 -0800801 NoPerspective |= src.NoPerspective;
Chris Forbesc25b8072018-12-10 15:10:39 -0800802 Centroid |= src.Centroid;
803 Block |= src.Block;
804 BufferBlock |= src.BufferBlock;
805 }
Chris Forbesbc3a0ee2018-12-27 16:02:58 -0800806
Ben Claytonab51bbf2019-02-20 14:36:27 +0000807 void SpirvShader::ApplyDecorationsForId(Decorations *d, TypeOrObjectID id) const
Chris Forbes49d664d2019-02-12 19:24:50 +0000808 {
809 auto it = decorations.find(id);
810 if (it != decorations.end())
811 d->Apply(it->second);
812 }
813
Ben Claytonab51bbf2019-02-20 14:36:27 +0000814 void SpirvShader::ApplyDecorationsForIdMember(Decorations *d, TypeID id, uint32_t member) const
Chris Forbes49d664d2019-02-12 19:24:50 +0000815 {
816 auto it = memberDecorations.find(id);
817 if (it != memberDecorations.end() && member < it->second.size())
818 {
819 d->Apply(it->second[member]);
820 }
821 }
822
Ben Claytonab51bbf2019-02-20 14:36:27 +0000823 uint32_t SpirvShader::GetConstantInt(ObjectID id) const
Chris Forbesbc3a0ee2018-12-27 16:02:58 -0800824 {
825 // Slightly hackish access to constants very early in translation.
826 // General consumption of constants by other instructions should
827 // probably be just lowered to Reactor.
828
829 // TODO: not encountered yet since we only use this for array sizes etc,
830 // but is possible to construct integer constant 0 via OpConstantNull.
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800831 auto insn = getObject(id).definition;
Ben Clayton6fae32c2019-02-28 20:06:42 +0000832 ASSERT(insn.opcode() == spv::OpConstant);
833 ASSERT(getType(insn.word(1)).definition.opcode() == spv::OpTypeInt);
Chris Forbesbc3a0ee2018-12-27 16:02:58 -0800834 return insn.word(3);
835 }
Chris Forbesd5aed492019-02-02 15:18:52 -0800836
837 // emit-time
838
Chris Forbesc61271e2019-02-19 17:01:28 -0800839 void SpirvShader::emitProlog(SpirvRoutine *routine) const
Chris Forbesd5aed492019-02-02 15:18:52 -0800840 {
841 for (auto insn : *this)
842 {
843 switch (insn.opcode())
844 {
845 case spv::OpVariable:
846 {
Ben Claytonab51bbf2019-02-20 14:36:27 +0000847 ObjectID resultId = insn.word(2);
Chris Forbes0eba65b2019-02-13 12:24:35 -0800848 auto &object = getObject(resultId);
Ben Clayton9a162482019-02-25 11:54:43 +0000849 auto &objectTy = getType(object.type);
850 auto &pointeeTy = getType(objectTy.element);
Chris Forbesd5aed492019-02-02 15:18:52 -0800851 // TODO: what to do about zero-slot objects?
Ben Clayton9a162482019-02-25 11:54:43 +0000852 if (pointeeTy.sizeInComponents > 0)
Chris Forbesd5aed492019-02-02 15:18:52 -0800853 {
Ben Clayton9a162482019-02-25 11:54:43 +0000854 routine->createLvalue(insn.word(2), pointeeTy.sizeInComponents);
Chris Forbesd5aed492019-02-02 15:18:52 -0800855 }
856 break;
857 }
858 default:
Chris Forbese9f8f5b2019-02-11 00:20:16 +0000859 // Nothing else produces interface variables, so can all be safely ignored.
Chris Forbesd5aed492019-02-02 15:18:52 -0800860 break;
861 }
862 }
863 }
864
865 void SpirvShader::emit(SpirvRoutine *routine) const
866 {
Chris Forbesd5aed492019-02-02 15:18:52 -0800867 for (auto insn : *this)
868 {
869 switch (insn.opcode())
870 {
Chris Forbese53533d2019-02-21 16:49:51 -0800871 case spv::OpTypeVoid:
872 case spv::OpTypeInt:
873 case spv::OpTypeFloat:
874 case spv::OpTypeBool:
875 case spv::OpTypeVector:
876 case spv::OpTypeArray:
877 case spv::OpTypeRuntimeArray:
878 case spv::OpTypeMatrix:
879 case spv::OpTypeStruct:
880 case spv::OpTypePointer:
881 case spv::OpTypeFunction:
882 case spv::OpExecutionMode:
883 case spv::OpMemoryModel:
884 case spv::OpFunction:
885 case spv::OpFunctionEnd:
886 case spv::OpConstant:
887 case spv::OpConstantNull:
888 case spv::OpConstantTrue:
889 case spv::OpConstantFalse:
890 case spv::OpConstantComposite:
891 case spv::OpExtension:
892 case spv::OpCapability:
893 case spv::OpEntryPoint:
894 case spv::OpExtInstImport:
895 case spv::OpDecorate:
896 case spv::OpMemberDecorate:
897 case spv::OpGroupDecorate:
898 case spv::OpGroupMemberDecorate:
899 case spv::OpDecorationGroup:
Chris Forbes1776af72019-02-22 17:39:57 -0800900 case spv::OpName:
901 case spv::OpMemberName:
902 case spv::OpSource:
903 case spv::OpSourceContinued:
904 case spv::OpSourceExtension:
Chris Forbese53533d2019-02-21 16:49:51 -0800905 // Nothing to do at emit time. These are either fully handled at analysis time,
906 // or don't require any work at all.
907 break;
908
Chris Forbese57f10e2019-03-04 10:53:07 -0800909 case spv::OpLabel:
910 case spv::OpReturn:
911 // TODO: when we do control flow, will need to do some work here.
912 // Until then, there is nothing to do -- we expect there to be an initial OpLabel
913 // in the entrypoint function, for which we do nothing; and a final OpReturn at the
914 // end of the entrypoint function, for which we do nothing.
915 break;
916
Chris Forbes0eba65b2019-02-13 12:24:35 -0800917 case spv::OpVariable:
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000918 EmitVariable(insn, routine);
Chris Forbes0eba65b2019-02-13 12:24:35 -0800919 break;
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000920
Chris Forbese9f8f5b2019-02-11 00:20:16 +0000921 case spv::OpLoad:
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000922 EmitLoad(insn, routine);
Chris Forbese9f8f5b2019-02-11 00:20:16 +0000923 break;
Chris Forbes38f85b32019-02-12 20:10:05 +0000924
Chris Forbes1c588002019-02-12 18:56:38 +0000925 case spv::OpStore:
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000926 EmitStore(insn, routine);
Chris Forbes1c588002019-02-12 18:56:38 +0000927 break;
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000928
929 case spv::OpAccessChain:
930 EmitAccessChain(insn, routine);
931 break;
932
Chris Forbesb97a9572019-02-21 16:51:42 -0800933 case spv::OpCompositeConstruct:
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000934 EmitCompositeConstruct(insn, routine);
Chris Forbesb97a9572019-02-21 16:51:42 -0800935 break;
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000936
Chris Forbes1bc1acf2019-02-21 18:40:33 -0800937 case spv::OpCompositeInsert:
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000938 EmitCompositeInsert(insn, routine);
Chris Forbes1bc1acf2019-02-21 18:40:33 -0800939 break;
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000940
Chris Forbesb12846d2019-02-21 18:53:58 -0800941 case spv::OpCompositeExtract:
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000942 EmitCompositeExtract(insn, routine);
Chris Forbesb12846d2019-02-21 18:53:58 -0800943 break;
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000944
Chris Forbes83fc5442019-02-26 22:16:07 -0800945 case spv::OpVectorShuffle:
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000946 EmitVectorShuffle(insn, routine);
Chris Forbes83fc5442019-02-26 22:16:07 -0800947 break;
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000948
Ben Claytondd1e37e2019-02-28 19:59:15 +0000949 case spv::OpNot:
950 case spv::OpSNegate:
951 case spv::OpFNegate:
952 case spv::OpLogicalNot:
Chris Forbes4d503052019-03-01 17:13:57 -0800953 case spv::OpConvertFToU:
954 case spv::OpConvertFToS:
955 case spv::OpConvertSToF:
956 case spv::OpConvertUToF:
957 case spv::OpBitcast:
Ben Claytondd1e37e2019-02-28 19:59:15 +0000958 EmitUnaryOp(insn, routine);
959 break;
960
961 case spv::OpIAdd:
962 case spv::OpISub:
963 case spv::OpIMul:
964 case spv::OpSDiv:
965 case spv::OpUDiv:
966 case spv::OpFAdd:
967 case spv::OpFSub:
968 case spv::OpFDiv:
Ben Claytonec1aeb82019-03-04 19:33:27 +0000969 case spv::OpFOrdEqual:
970 case spv::OpFUnordEqual:
971 case spv::OpFOrdNotEqual:
972 case spv::OpFUnordNotEqual:
973 case spv::OpFOrdLessThan:
974 case spv::OpFUnordLessThan:
975 case spv::OpFOrdGreaterThan:
976 case spv::OpFUnordGreaterThan:
977 case spv::OpFOrdLessThanEqual:
978 case spv::OpFUnordLessThanEqual:
979 case spv::OpFOrdGreaterThanEqual:
980 case spv::OpFUnordGreaterThanEqual:
Ben Claytondd1e37e2019-02-28 19:59:15 +0000981 case spv::OpUMod:
Ben Claytone95eeb12019-03-04 16:32:09 +0000982 case spv::OpIEqual:
983 case spv::OpINotEqual:
984 case spv::OpUGreaterThan:
985 case spv::OpSGreaterThan:
986 case spv::OpUGreaterThanEqual:
987 case spv::OpSGreaterThanEqual:
988 case spv::OpULessThan:
989 case spv::OpSLessThan:
990 case spv::OpULessThanEqual:
991 case spv::OpSLessThanEqual:
Ben Claytondd1e37e2019-02-28 19:59:15 +0000992 case spv::OpShiftRightLogical:
993 case spv::OpShiftRightArithmetic:
994 case spv::OpShiftLeftLogical:
995 case spv::OpBitwiseOr:
996 case spv::OpBitwiseXor:
997 case spv::OpBitwiseAnd:
998 case spv::OpLogicalOr:
999 case spv::OpLogicalAnd:
Chris Forbese86b6dc2019-03-01 09:08:47 -08001000 case spv::OpUMulExtended:
1001 case spv::OpSMulExtended:
Ben Claytondd1e37e2019-02-28 19:59:15 +00001002 EmitBinaryOp(insn, routine);
1003 break;
1004
Chris Forbes2b287cc2019-03-01 13:24:17 -08001005 case spv::OpDot:
1006 EmitDot(insn, routine);
1007 break;
1008
Ben Claytonbf943f62019-03-05 12:57:39 +00001009 case spv::OpSelect:
1010 EmitSelect(insn, routine);
1011 break;
1012
Chris Forbesd5aed492019-02-02 15:18:52 -08001013 default:
Chris Forbese57f10e2019-03-04 10:53:07 -08001014 UNIMPLEMENTED(OpcodeName(insn.opcode()).c_str());
Chris Forbesd5aed492019-02-02 15:18:52 -08001015 break;
1016 }
1017 }
1018 }
Chris Forbesc61271e2019-02-19 17:01:28 -08001019
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001020 void SpirvShader::EmitVariable(InsnIterator insn, SpirvRoutine *routine) const
1021 {
1022 ObjectID resultId = insn.word(2);
1023 auto &object = getObject(resultId);
1024 auto &objectTy = getType(object.type);
1025 if (object.kind == Object::Kind::InterfaceVariable && objectTy.storageClass == spv::StorageClassInput)
1026 {
1027 auto &dst = routine->getValue(resultId);
1028 int offset = 0;
1029 VisitInterface(resultId,
1030 [&](Decorations const &d, AttribType type) {
1031 auto scalarSlot = d.Location << 2 | d.Component;
1032 dst[offset++] = routine->inputs[scalarSlot];
1033 });
1034 }
1035 }
1036
1037 void SpirvShader::EmitLoad(InsnIterator insn, SpirvRoutine *routine) const
1038 {
1039 ObjectID objectId = insn.word(2);
1040 ObjectID pointerId = insn.word(3);
1041 auto &object = getObject(objectId);
1042 auto &objectTy = getType(object.type);
1043 auto &pointer = getObject(pointerId);
1044 auto &pointerBase = getObject(pointer.pointerBase);
1045 auto &pointerBaseTy = getType(pointerBase.type);
1046
1047 ASSERT(getType(pointer.type).element == object.type);
1048 ASSERT(TypeID(insn.word(1)) == object.type);
1049
1050 if (pointerBaseTy.storageClass == spv::StorageClassImage ||
1051 pointerBaseTy.storageClass == spv::StorageClassUniform ||
1052 pointerBaseTy.storageClass == spv::StorageClassUniformConstant)
1053 {
1054 UNIMPLEMENTED("Descriptor-backed load not yet implemented");
1055 }
1056
1057 auto &ptrBase = routine->getValue(pointer.pointerBase);
1058 auto &dst = routine->createIntermediate(objectId, objectTy.sizeInComponents);
1059
1060 if (pointer.kind == Object::Kind::Value)
1061 {
1062 auto offsets = As<SIMD::Int>(routine->getIntermediate(insn.word(3))[0]);
1063 for (auto i = 0u; i < objectTy.sizeInComponents; i++)
1064 {
1065 // i wish i had a Float,Float,Float,Float constructor here..
1066 SIMD::Float v;
1067 for (int j = 0; j < SIMD::Width; j++)
1068 {
1069 Int offset = Int(i) + Extract(offsets, j);
1070 v = Insert(v, Extract(ptrBase[offset], j), j);
1071 }
1072 dst.emplace(i, v);
1073 }
1074 }
1075 else
1076 {
1077 // no divergent offsets to worry about
1078 for (auto i = 0u; i < objectTy.sizeInComponents; i++)
1079 {
1080 dst.emplace(i, ptrBase[i]);
1081 }
1082 }
1083 }
1084
1085 void SpirvShader::EmitAccessChain(InsnIterator insn, SpirvRoutine *routine) const
1086 {
1087 TypeID typeId = insn.word(1);
1088 ObjectID objectId = insn.word(2);
1089 ObjectID baseId = insn.word(3);
1090 auto &object = getObject(objectId);
1091 auto &type = getType(typeId);
1092 auto &pointerBase = getObject(object.pointerBase);
1093 auto &pointerBaseTy = getType(pointerBase.type);
1094 ASSERT(type.sizeInComponents == 1);
1095 ASSERT(getObject(baseId).pointerBase == object.pointerBase);
1096
1097 if (pointerBaseTy.storageClass == spv::StorageClassImage ||
1098 pointerBaseTy.storageClass == spv::StorageClassUniform ||
1099 pointerBaseTy.storageClass == spv::StorageClassUniformConstant)
1100 {
1101 UNIMPLEMENTED("Descriptor-backed OpAccessChain not yet implemented");
1102 }
1103 auto &dst = routine->createIntermediate(objectId, type.sizeInComponents);
1104 dst.emplace(0, As<SIMD::Float>(WalkAccessChain(baseId, insn.wordCount() - 4, insn.wordPointer(4), routine)));
1105 }
1106
1107 void SpirvShader::EmitStore(InsnIterator insn, SpirvRoutine *routine) const
1108 {
1109 ObjectID pointerId = insn.word(1);
1110 ObjectID objectId = insn.word(2);
1111 auto &object = getObject(objectId);
1112 auto &pointer = getObject(pointerId);
1113 auto &pointerTy = getType(pointer.type);
1114 auto &elementTy = getType(pointerTy.element);
1115 auto &pointerBase = getObject(pointer.pointerBase);
1116 auto &pointerBaseTy = getType(pointerBase.type);
1117
1118 if (pointerBaseTy.storageClass == spv::StorageClassImage ||
1119 pointerBaseTy.storageClass == spv::StorageClassUniform ||
1120 pointerBaseTy.storageClass == spv::StorageClassUniformConstant)
1121 {
1122 UNIMPLEMENTED("Descriptor-backed store not yet implemented");
1123 }
1124
1125 auto &ptrBase = routine->getValue(pointer.pointerBase);
1126
1127 if (object.kind == Object::Kind::Constant)
1128 {
1129 auto src = reinterpret_cast<float *>(object.constantValue.get());
1130
1131 if (pointer.kind == Object::Kind::Value)
1132 {
1133 auto offsets = As<SIMD::Int>(routine->getIntermediate(pointerId)[0]);
1134 for (auto i = 0u; i < elementTy.sizeInComponents; i++)
1135 {
1136 // Scattered store
1137 for (int j = 0; j < SIMD::Width; j++)
1138 {
1139 auto dst = ptrBase[Int(i) + Extract(offsets, j)];
1140 dst = Insert(dst, Float(src[i]), j);
1141 }
1142 }
1143 }
1144 else
1145 {
1146 // no divergent offsets
1147 for (auto i = 0u; i < elementTy.sizeInComponents; i++)
1148 {
1149 ptrBase[i] = RValue<SIMD::Float>(src[i]);
1150 }
1151 }
1152 }
1153 else
1154 {
1155 auto &src = routine->getIntermediate(objectId);
1156
1157 if (pointer.kind == Object::Kind::Value)
1158 {
1159 auto offsets = As<SIMD::Int>(routine->getIntermediate(pointerId)[0]);
1160 for (auto i = 0u; i < elementTy.sizeInComponents; i++)
1161 {
1162 // Scattered store
1163 for (int j = 0; j < SIMD::Width; j++)
1164 {
1165 auto dst = ptrBase[Int(i) + Extract(offsets, j)];
1166 dst = Insert(dst, Extract(src[i], j), j);
1167 }
1168 }
1169 }
1170 else
1171 {
1172 // no divergent offsets
1173 for (auto i = 0u; i < elementTy.sizeInComponents; i++)
1174 {
1175 ptrBase[i] = src[i];
1176 }
1177 }
1178 }
1179 }
1180
1181 void SpirvShader::EmitCompositeConstruct(InsnIterator insn, SpirvRoutine *routine) const
1182 {
1183 auto &type = getType(insn.word(1));
1184 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
1185 auto offset = 0u;
1186
1187 for (auto i = 0u; i < insn.wordCount() - 3; i++)
1188 {
1189 ObjectID srcObjectId = insn.word(3u + i);
1190 auto & srcObject = getObject(srcObjectId);
1191 auto & srcObjectTy = getType(srcObject.type);
1192 GenericValue srcObjectAccess(this, routine, srcObjectId);
1193
1194 for (auto j = 0u; j < srcObjectTy.sizeInComponents; j++)
1195 dst.emplace(offset++, srcObjectAccess[j]);
1196 }
1197 }
1198
1199 void SpirvShader::EmitCompositeInsert(InsnIterator insn, SpirvRoutine *routine) const
1200 {
1201 TypeID resultTypeId = insn.word(1);
1202 auto &type = getType(resultTypeId);
1203 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
1204 auto &newPartObject = getObject(insn.word(3));
1205 auto &newPartObjectTy = getType(newPartObject.type);
1206 auto firstNewComponent = WalkLiteralAccessChain(resultTypeId, insn.wordCount() - 5, insn.wordPointer(5));
1207
1208 GenericValue srcObjectAccess(this, routine, insn.word(4));
1209 GenericValue newPartObjectAccess(this, routine, insn.word(3));
1210
1211 // old components before
1212 for (auto i = 0u; i < firstNewComponent; i++)
1213 {
1214 dst.emplace(i, srcObjectAccess[i]);
1215 }
1216 // new part
1217 for (auto i = 0u; i < newPartObjectTy.sizeInComponents; i++)
1218 {
1219 dst.emplace(firstNewComponent + i, newPartObjectAccess[i]);
1220 }
1221 // old components after
1222 for (auto i = firstNewComponent + newPartObjectTy.sizeInComponents; i < type.sizeInComponents; i++)
1223 {
1224 dst.emplace(i, srcObjectAccess[i]);
1225 }
1226 }
1227
1228 void SpirvShader::EmitCompositeExtract(InsnIterator insn, SpirvRoutine *routine) const
1229 {
1230 auto &type = getType(insn.word(1));
1231 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
1232 auto &compositeObject = getObject(insn.word(3));
1233 TypeID compositeTypeId = compositeObject.definition.word(1);
1234 auto firstComponent = WalkLiteralAccessChain(compositeTypeId, insn.wordCount() - 4, insn.wordPointer(4));
1235
1236 GenericValue compositeObjectAccess(this, routine, insn.word(3));
1237 for (auto i = 0u; i < type.sizeInComponents; i++)
1238 {
1239 dst.emplace(i, compositeObjectAccess[firstComponent + i]);
1240 }
1241 }
1242
1243 void SpirvShader::EmitVectorShuffle(InsnIterator insn, SpirvRoutine *routine) const
1244 {
1245 auto &type = getType(insn.word(1));
1246 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
1247
1248 GenericValue firstHalfAccess(this, routine, insn.word(3));
1249 GenericValue secondHalfAccess(this, routine, insn.word(4));
1250
1251 for (auto i = 0u; i < type.sizeInComponents; i++)
1252 {
1253 auto selector = insn.word(5 + i);
1254 if (selector == static_cast<uint32_t>(-1))
1255 {
1256 // Undefined value. Until we decide to do real undef values, zero is as good
1257 // a value as any
1258 dst.emplace(i, RValue<SIMD::Float>(0.0f));
1259 }
1260 else if (selector < type.sizeInComponents)
1261 {
1262 dst.emplace(i, firstHalfAccess[selector]);
1263 }
1264 else
1265 {
1266 dst.emplace(i, secondHalfAccess[selector - type.sizeInComponents]);
1267 }
1268 }
1269 }
1270
Ben Claytondd1e37e2019-02-28 19:59:15 +00001271 void SpirvShader::EmitUnaryOp(InsnIterator insn, SpirvRoutine *routine) const
1272 {
1273 auto &type = getType(insn.word(1));
1274 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
1275 auto src = GenericValue(this, routine, insn.word(3));
1276
1277 for (auto i = 0u; i < type.sizeInComponents; i++)
1278 {
1279 auto val = src[i];
1280
1281 switch (insn.opcode())
1282 {
1283 case spv::OpNot:
1284 case spv::OpLogicalNot: // logical not == bitwise not due to all-bits boolean representation
1285 dst.emplace(i, As<SIMD::Float>(~As<SIMD::UInt>(val)));
1286 break;
1287 case spv::OpSNegate:
1288 dst.emplace(i, As<SIMD::Float>(-As<SIMD::Int>(val)));
1289 break;
1290 case spv::OpFNegate:
1291 dst.emplace(i, -val);
1292 break;
Chris Forbes4d503052019-03-01 17:13:57 -08001293 case spv::OpConvertFToU:
1294 dst.emplace(i, As<SIMD::Float>(SIMD::UInt(val)));
1295 break;
1296 case spv::OpConvertFToS:
1297 dst.emplace(i, As<SIMD::Float>(SIMD::Int(val)));
1298 break;
1299 case spv::OpConvertSToF:
1300 dst.emplace(i, SIMD::Float(As<SIMD::Int>(val)));
1301 break;
1302 case spv::OpConvertUToF:
1303 dst.emplace(i, SIMD::Float(As<SIMD::UInt>(val)));
1304 break;
1305 case spv::OpBitcast:
1306 dst.emplace(i, val);
1307 break;
Ben Claytondd1e37e2019-02-28 19:59:15 +00001308 default:
1309 UNIMPLEMENTED("Unhandled unary operator %s", OpcodeName(insn.opcode()).c_str());
1310 }
1311 }
1312 }
1313
1314 void SpirvShader::EmitBinaryOp(InsnIterator insn, SpirvRoutine *routine) const
1315 {
1316 auto &type = getType(insn.word(1));
1317 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
Chris Forbese86b6dc2019-03-01 09:08:47 -08001318 auto &lhsType = getType(getObject(insn.word(3)).type);
Ben Claytondd1e37e2019-02-28 19:59:15 +00001319 auto srcLHS = GenericValue(this, routine, insn.word(3));
1320 auto srcRHS = GenericValue(this, routine, insn.word(4));
1321
Chris Forbese86b6dc2019-03-01 09:08:47 -08001322 for (auto i = 0u; i < lhsType.sizeInComponents; i++)
Ben Claytondd1e37e2019-02-28 19:59:15 +00001323 {
1324 auto lhs = srcLHS[i];
1325 auto rhs = srcRHS[i];
1326
1327 switch (insn.opcode())
1328 {
1329 case spv::OpIAdd:
1330 dst.emplace(i, As<SIMD::Float>(As<SIMD::Int>(lhs) + As<SIMD::Int>(rhs)));
1331 break;
1332 case spv::OpISub:
1333 dst.emplace(i, As<SIMD::Float>(As<SIMD::Int>(lhs) - As<SIMD::Int>(rhs)));
1334 break;
1335 case spv::OpIMul:
1336 dst.emplace(i, As<SIMD::Float>(As<SIMD::Int>(lhs) * As<SIMD::Int>(rhs)));
1337 break;
1338 case spv::OpSDiv:
1339 dst.emplace(i, As<SIMD::Float>(As<SIMD::Int>(lhs) / As<SIMD::Int>(rhs)));
1340 break;
1341 case spv::OpUDiv:
1342 dst.emplace(i, As<SIMD::Float>(As<SIMD::UInt>(lhs) / As<SIMD::UInt>(rhs)));
1343 break;
1344 case spv::OpUMod:
1345 dst.emplace(i, As<SIMD::Float>(As<SIMD::UInt>(lhs) % As<SIMD::UInt>(rhs)));
1346 break;
Ben Claytone95eeb12019-03-04 16:32:09 +00001347 case spv::OpIEqual:
1348 dst.emplace(i, As<SIMD::Float>(CmpEQ(As<SIMD::Int>(lhs), As<SIMD::Int>(rhs))));
1349 break;
1350 case spv::OpINotEqual:
1351 dst.emplace(i, As<SIMD::Float>(CmpNEQ(As<SIMD::Int>(lhs), As<SIMD::Int>(rhs))));
1352 break;
1353 case spv::OpUGreaterThan:
1354 dst.emplace(i, As<SIMD::Float>(CmpGT(As<SIMD::UInt>(lhs), As<SIMD::UInt>(rhs))));
1355 break;
1356 case spv::OpSGreaterThan:
1357 dst.emplace(i, As<SIMD::Float>(CmpGT(As<SIMD::Int>(lhs), As<SIMD::Int>(rhs))));
1358 break;
1359 case spv::OpUGreaterThanEqual:
1360 dst.emplace(i, As<SIMD::Float>(CmpGE(As<SIMD::UInt>(lhs), As<SIMD::UInt>(rhs))));
1361 break;
1362 case spv::OpSGreaterThanEqual:
1363 dst.emplace(i, As<SIMD::Float>(CmpGE(As<SIMD::Int>(lhs), As<SIMD::Int>(rhs))));
1364 break;
1365 case spv::OpULessThan:
1366 dst.emplace(i, As<SIMD::Float>(CmpLT(As<SIMD::UInt>(lhs), As<SIMD::UInt>(rhs))));
1367 break;
1368 case spv::OpSLessThan:
1369 dst.emplace(i, As<SIMD::Float>(CmpLT(As<SIMD::Int>(lhs), As<SIMD::Int>(rhs))));
1370 break;
1371 case spv::OpULessThanEqual:
1372 dst.emplace(i, As<SIMD::Float>(CmpLE(As<SIMD::UInt>(lhs), As<SIMD::UInt>(rhs))));
1373 break;
1374 case spv::OpSLessThanEqual:
1375 dst.emplace(i, As<SIMD::Float>(CmpLE(As<SIMD::Int>(lhs), As<SIMD::Int>(rhs))));
1376 break;
Ben Claytondd1e37e2019-02-28 19:59:15 +00001377 case spv::OpFAdd:
1378 dst.emplace(i, lhs + rhs);
1379 break;
1380 case spv::OpFSub:
1381 dst.emplace(i, lhs - rhs);
1382 break;
1383 case spv::OpFDiv:
1384 dst.emplace(i, lhs / rhs);
1385 break;
Ben Claytonec1aeb82019-03-04 19:33:27 +00001386 case spv::OpFOrdEqual:
1387 dst.emplace(i, As<SIMD::Float>(CmpEQ(lhs, rhs)));
1388 break;
1389 case spv::OpFUnordEqual:
1390 dst.emplace(i, As<SIMD::Float>(CmpUEQ(lhs, rhs)));
1391 break;
1392 case spv::OpFOrdNotEqual:
1393 dst.emplace(i, As<SIMD::Float>(CmpNEQ(lhs, rhs)));
1394 break;
1395 case spv::OpFUnordNotEqual:
1396 dst.emplace(i, As<SIMD::Float>(CmpUNEQ(lhs, rhs)));
1397 break;
1398 case spv::OpFOrdLessThan:
1399 dst.emplace(i, As<SIMD::Float>(CmpLT(lhs, rhs)));
1400 break;
1401 case spv::OpFUnordLessThan:
1402 dst.emplace(i, As<SIMD::Float>(CmpULT(lhs, rhs)));
1403 break;
1404 case spv::OpFOrdGreaterThan:
1405 dst.emplace(i, As<SIMD::Float>(CmpGT(lhs, rhs)));
1406 break;
1407 case spv::OpFUnordGreaterThan:
1408 dst.emplace(i, As<SIMD::Float>(CmpUGT(lhs, rhs)));
1409 break;
1410 case spv::OpFOrdLessThanEqual:
1411 dst.emplace(i, As<SIMD::Float>(CmpLE(lhs, rhs)));
1412 break;
1413 case spv::OpFUnordLessThanEqual:
1414 dst.emplace(i, As<SIMD::Float>(CmpULE(lhs, rhs)));
1415 break;
1416 case spv::OpFOrdGreaterThanEqual:
1417 dst.emplace(i, As<SIMD::Float>(CmpGE(lhs, rhs)));
1418 break;
1419 case spv::OpFUnordGreaterThanEqual:
1420 dst.emplace(i, As<SIMD::Float>(CmpUGE(lhs, rhs)));
1421 break;
Ben Claytondd1e37e2019-02-28 19:59:15 +00001422 case spv::OpShiftRightLogical:
1423 dst.emplace(i, As<SIMD::Float>(As<SIMD::UInt>(lhs) >> As<SIMD::UInt>(rhs)));
1424 break;
1425 case spv::OpShiftRightArithmetic:
1426 dst.emplace(i, As<SIMD::Float>(As<SIMD::Int>(lhs) >> As<SIMD::Int>(rhs)));
1427 break;
1428 case spv::OpShiftLeftLogical:
1429 dst.emplace(i, As<SIMD::Float>(As<SIMD::UInt>(lhs) << As<SIMD::UInt>(rhs)));
1430 break;
1431 case spv::OpBitwiseOr:
1432 case spv::OpLogicalOr:
1433 dst.emplace(i, As<SIMD::Float>(As<SIMD::UInt>(lhs) | As<SIMD::UInt>(rhs)));
1434 break;
1435 case spv::OpBitwiseXor:
1436 dst.emplace(i, As<SIMD::Float>(As<SIMD::UInt>(lhs) ^ As<SIMD::UInt>(rhs)));
1437 break;
1438 case spv::OpBitwiseAnd:
1439 case spv::OpLogicalAnd:
1440 dst.emplace(i, As<SIMD::Float>(As<SIMD::UInt>(lhs) & As<SIMD::UInt>(rhs)));
1441 break;
Chris Forbese86b6dc2019-03-01 09:08:47 -08001442 case spv::OpSMulExtended:
1443 // Extended ops: result is a structure containing two members of the same type as lhs & rhs.
1444 // In our flat view then, component i is the i'th component of the first member;
1445 // component i + N is the i'th component of the second member.
1446 dst.emplace(i, As<SIMD::Float>(As<SIMD::Int>(lhs) * As<SIMD::Int>(rhs)));
1447 dst.emplace(i + lhsType.sizeInComponents, As<SIMD::Float>(MulHigh(As<SIMD::Int>(lhs), As<SIMD::Int>(rhs))));
1448 break;
1449 case spv::OpUMulExtended:
1450 dst.emplace(i, As<SIMD::Float>(As<SIMD::UInt>(lhs) * As<SIMD::UInt>(rhs)));
1451 dst.emplace(i + lhsType.sizeInComponents, As<SIMD::Float>(MulHigh(As<SIMD::UInt>(lhs), As<SIMD::UInt>(rhs))));
1452 break;
Ben Claytondd1e37e2019-02-28 19:59:15 +00001453 default:
1454 UNIMPLEMENTED("Unhandled binary operator %s", OpcodeName(insn.opcode()).c_str());
1455 }
1456 }
1457 }
1458
Chris Forbes2b287cc2019-03-01 13:24:17 -08001459 void SpirvShader::EmitDot(InsnIterator insn, SpirvRoutine *routine) const
1460 {
1461 auto &type = getType(insn.word(1));
1462 assert(type.sizeInComponents == 1);
1463 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
1464 auto &lhsType = getType(getObject(insn.word(3)).type);
1465 auto srcLHS = GenericValue(this, routine, insn.word(3));
1466 auto srcRHS = GenericValue(this, routine, insn.word(4));
1467
1468 SIMD::Float result = srcLHS[0] * srcRHS[0];
1469
1470 for (auto i = 1u; i < lhsType.sizeInComponents; i++)
1471 {
1472 result += srcLHS[i] * srcRHS[i];
1473 }
1474
1475 dst.emplace(0, result);
1476 }
1477
Ben Claytonbf943f62019-03-05 12:57:39 +00001478 void SpirvShader::EmitSelect(InsnIterator insn, SpirvRoutine *routine) const
1479 {
1480 auto &type = getType(insn.word(1));
1481 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
1482 auto srcCond = GenericValue(this, routine, insn.word(3));
1483 auto srcLHS = GenericValue(this, routine, insn.word(4));
1484 auto srcRHS = GenericValue(this, routine, insn.word(5));
1485
1486 for (auto i = 0u; i < type.sizeInComponents; i++)
1487 {
1488 auto cond = As<SIMD::Int>(srcCond[i]);
1489 auto lhs = srcLHS[i];
1490 auto rhs = srcRHS[i];
1491 auto out = (cond & As<Int4>(lhs)) | (~cond & As<Int4>(rhs)); // FIXME: IfThenElse()
1492 dst.emplace(i, As<SIMD::Float>(out));
1493 }
1494 }
1495
Chris Forbesc61271e2019-02-19 17:01:28 -08001496 void SpirvShader::emitEpilog(SpirvRoutine *routine) const
1497 {
1498 for (auto insn : *this)
1499 {
1500 switch (insn.opcode())
1501 {
1502 case spv::OpVariable:
1503 {
Ben Claytonab51bbf2019-02-20 14:36:27 +00001504 ObjectID resultId = insn.word(2);
Chris Forbesc61271e2019-02-19 17:01:28 -08001505 auto &object = getObject(resultId);
Ben Clayton9a162482019-02-25 11:54:43 +00001506 auto &objectTy = getType(object.type);
1507 if (object.kind == Object::Kind::InterfaceVariable && objectTy.storageClass == spv::StorageClassOutput)
Chris Forbesc61271e2019-02-19 17:01:28 -08001508 {
1509 auto &dst = routine->getValue(resultId);
1510 int offset = 0;
1511 VisitInterface(resultId,
1512 [&](Decorations const &d, AttribType type) {
1513 auto scalarSlot = d.Location << 2 | d.Component;
1514 routine->outputs[scalarSlot] = dst[offset++];
1515 });
1516 }
1517 break;
1518 }
1519 default:
1520 break;
1521 }
1522 }
1523 }
Ben Clayton76e9bc02019-02-26 15:02:18 +00001524
1525 SpirvRoutine::SpirvRoutine(vk::PipelineLayout const *pipelineLayout) :
1526 pipelineLayout(pipelineLayout)
1527 {
1528 }
1529
Chris Forbesc25b8072018-12-10 15:10:39 -08001530}