blob: 848eefe567ad2055c1d96d71df59fe7aa0f00039 [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
Chris Forbesaf4ed532018-12-06 18:33:27 -080015#include "SpirvShader.hpp"
Ben Claytonfc951cd2019-05-15 17:16:56 +010016#include "SpirvShaderDebug.hpp"
Ben Claytonecfeede2019-05-08 08:51:01 +010017
Ben Clayton25e06e02020-02-07 11:19:08 +000018#include "System/Debug.hpp"
Ben Clayton76e9bc02019-02-26 15:02:18 +000019#include "Vulkan/VkPipelineLayout.hpp"
Chris Forbes24466042019-04-22 10:54:23 -070020#include "Vulkan/VkRenderPass.hpp"
Chris Forbesaf4ed532018-12-06 18:33:27 -080021
Ben Claytonb0ca2a82020-01-08 13:00:57 +000022#include "marl/defer.h"
23
Nicolas Capens82eb22e2019-04-10 01:15:43 -040024#include <spirv/unified1/spirv.hpp>
Ben Clayton62bb5ed2019-06-18 13:12:20 +010025
Nicolas Capens157ba262019-12-10 17:49:14 -050026namespace sw {
27
28SpirvShader::SpirvShader(
Ben Claytonbc1c0672019-12-17 20:37:37 +000029 uint32_t codeSerialID,
30 VkShaderStageFlagBits pipelineStage,
31 const char *entryPointName,
32 InsnStore const &insns,
33 const vk::RenderPass *renderPass,
34 uint32_t subpassIndex,
Ben Clayton7d0ce412019-12-03 13:26:31 +000035 bool robustBufferAccess,
36 const std::shared_ptr<vk::dbg::Context> &dbgctx)
Ben Claytonbc1c0672019-12-17 20:37:37 +000037 : insns{ insns }
38 , inputs{ MAX_INTERFACE_COMPONENTS }
39 , outputs{ MAX_INTERFACE_COMPONENTS }
40 , codeSerialID(codeSerialID)
41 , robustBufferAccess(robustBufferAccess)
Chris Forbesaf4ed532018-12-06 18:33:27 -080042{
Nicolas Capens157ba262019-12-10 17:49:14 -050043 ASSERT(insns.size() > 0);
Ben Clayton9e4bc1b2019-04-16 16:52:02 -040044
Ben Claytonb0ca2a82020-01-08 13:00:57 +000045 if(dbgctx)
46 {
47 dbgInit(dbgctx);
48 }
49
Nicolas Capens81bc9d92019-12-16 15:05:57 -050050 if(renderPass)
Chris Forbesaf4ed532018-12-06 18:33:27 -080051 {
Nicolas Capens157ba262019-12-10 17:49:14 -050052 // capture formats of any input attachments present
53 auto subpass = renderPass->getSubpass(subpassIndex);
54 inputAttachmentFormats.reserve(subpass.inputAttachmentCount);
Nicolas Capens81bc9d92019-12-16 15:05:57 -050055 for(auto i = 0u; i < subpass.inputAttachmentCount; i++)
Chris Forbes24466042019-04-22 10:54:23 -070056 {
Nicolas Capens157ba262019-12-10 17:49:14 -050057 auto attachmentIndex = subpass.pInputAttachments[i].attachment;
58 inputAttachmentFormats.push_back(attachmentIndex != VK_ATTACHMENT_UNUSED
Ben Claytonbc1c0672019-12-17 20:37:37 +000059 ? renderPass->getAttachment(attachmentIndex).format
60 : VK_FORMAT_UNDEFINED);
Ben Clayton64f78f52019-03-21 17:21:06 +000061 }
Chris Forbesaf4ed532018-12-06 18:33:27 -080062 }
63
Nicolas Capens157ba262019-12-10 17:49:14 -050064 // Simplifying assumptions (to be satisfied by earlier transformations)
65 // - The only input/output OpVariables present are those used by the entrypoint
66
67 Function::ID currentFunction;
68 Block::ID currentBlock;
69 InsnIterator blockStart;
70
Nicolas Capens81bc9d92019-12-16 15:05:57 -050071 for(auto insn : *this)
Ben Clayton0bb83b82019-02-26 11:41:07 +000072 {
Nicolas Capens157ba262019-12-10 17:49:14 -050073 spv::Op opcode = insn.opcode();
Nicolas Capens82eb22e2019-04-10 01:15:43 -040074
Nicolas Capens81bc9d92019-12-16 15:05:57 -050075 switch(opcode)
Ben Clayton9b156612019-03-13 19:48:31 +000076 {
Ben Claytonbc1c0672019-12-17 20:37:37 +000077 case spv::OpEntryPoint:
Nicolas Capens157ba262019-12-10 17:49:14 -050078 {
Ben Claytonbc1c0672019-12-17 20:37:37 +000079 executionModel = spv::ExecutionModel(insn.word(1));
80 auto id = Function::ID(insn.word(2));
81 auto name = insn.string(3);
82 auto stage = executionModelToStage(executionModel);
83 if(stage == pipelineStage && strcmp(name, entryPointName) == 0)
84 {
85 ASSERT_MSG(entryPoint == 0, "Duplicate entry point with name '%s' and stage %d", name, int(stage));
86 entryPoint = id;
87 }
Nicolas Capens157ba262019-12-10 17:49:14 -050088 break;
89 }
90
Ben Claytonbc1c0672019-12-17 20:37:37 +000091 case spv::OpExecutionMode:
92 ProcessExecutionMode(insn);
93 break;
Nicolas Capens157ba262019-12-10 17:49:14 -050094
Ben Claytonbc1c0672019-12-17 20:37:37 +000095 case spv::OpDecorate:
Nicolas Capens157ba262019-12-10 17:49:14 -050096 {
Ben Claytonbc1c0672019-12-17 20:37:37 +000097 TypeOrObjectID targetId = insn.word(1);
98 auto decoration = static_cast<spv::Decoration>(insn.word(2));
99 uint32_t value = insn.wordCount() > 3 ? insn.word(3) : 0;
100
101 decorations[targetId].Apply(decoration, value);
102
103 switch(decoration)
104 {
105 case spv::DecorationDescriptorSet:
106 descriptorDecorations[targetId].DescriptorSet = value;
107 break;
108 case spv::DecorationBinding:
109 descriptorDecorations[targetId].Binding = value;
110 break;
111 case spv::DecorationInputAttachmentIndex:
112 descriptorDecorations[targetId].InputAttachmentIndex = value;
113 break;
114 default:
115 // Only handling descriptor decorations here.
116 break;
117 }
118
119 if(decoration == spv::DecorationCentroid)
120 modes.NeedsCentroid = true;
121 break;
Nicolas Capens157ba262019-12-10 17:49:14 -0500122 }
123
Ben Claytonbc1c0672019-12-17 20:37:37 +0000124 case spv::OpMemberDecorate:
Nicolas Capens157ba262019-12-10 17:49:14 -0500125 {
Ben Claytonbc1c0672019-12-17 20:37:37 +0000126 Type::ID targetId = insn.word(1);
127 auto memberIndex = insn.word(2);
128 auto decoration = static_cast<spv::Decoration>(insn.word(3));
129 uint32_t value = insn.wordCount() > 4 ? insn.word(4) : 0;
130
131 auto &d = memberDecorations[targetId];
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500132 if(memberIndex >= d.size())
Ben Claytonbc1c0672019-12-17 20:37:37 +0000133 d.resize(memberIndex + 1); // on demand; exact size would require another pass...
134
135 d[memberIndex].Apply(decoration, value);
136
137 if(decoration == spv::DecorationCentroid)
138 modes.NeedsCentroid = true;
139 break;
Nicolas Capens157ba262019-12-10 17:49:14 -0500140 }
Nicolas Capens157ba262019-12-10 17:49:14 -0500141
Ben Claytonbc1c0672019-12-17 20:37:37 +0000142 case spv::OpDecorationGroup:
143 // Nothing to do here. We don't need to record the definition of the group; we'll just have
144 // the bundle of decorations float around. If we were to ever walk the decorations directly,
145 // we might think about introducing this as a real Object.
Nicolas Capens157ba262019-12-10 17:49:14 -0500146 break;
147
Ben Claytonbc1c0672019-12-17 20:37:37 +0000148 case spv::OpGroupDecorate:
149 {
150 uint32_t group = insn.word(1);
151 auto const &groupDecorations = decorations[group];
152 auto const &descriptorGroupDecorations = descriptorDecorations[group];
153 for(auto i = 2u; i < insn.wordCount(); i++)
154 {
155 // Remaining operands are targets to apply the group to.
156 uint32_t target = insn.word(i);
157 decorations[target].Apply(groupDecorations);
158 descriptorDecorations[target].Apply(descriptorGroupDecorations);
159 }
160
161 break;
162 }
163
164 case spv::OpGroupMemberDecorate:
165 {
166 auto const &srcDecorations = decorations[insn.word(1)];
167 for(auto i = 2u; i < insn.wordCount(); i += 2)
168 {
169 // remaining operands are pairs of <id>, literal for members to apply to.
170 auto &d = memberDecorations[insn.word(i)];
171 auto memberIndex = insn.word(i + 1);
172 if(memberIndex >= d.size())
173 d.resize(memberIndex + 1); // on demand resize, see above...
174 d[memberIndex].Apply(srcDecorations);
175 }
176 break;
177 }
178
179 case spv::OpLabel:
180 {
181 ASSERT(currentBlock.value() == 0);
182 currentBlock = Block::ID(insn.word(1));
183 blockStart = insn;
184 break;
185 }
186
187 // Branch Instructions (subset of Termination Instructions):
188 case spv::OpBranch:
189 case spv::OpBranchConditional:
190 case spv::OpSwitch:
191 case spv::OpReturn:
Nicolas Capens57eb48a2020-05-15 17:07:07 -0400192 // [[fallthrough]]
Ben Claytonbc1c0672019-12-17 20:37:37 +0000193
194 // Termination instruction:
195 case spv::OpKill:
196 case spv::OpUnreachable:
197 {
198 ASSERT(currentBlock.value() != 0);
199 ASSERT(currentFunction.value() != 0);
200
201 auto blockEnd = insn;
202 blockEnd++;
203 functions[currentFunction].blocks[currentBlock] = Block(blockStart, blockEnd);
204 currentBlock = Block::ID(0);
205
206 if(opcode == spv::OpKill)
207 {
208 modes.ContainsKill = true;
209 }
210 break;
211 }
212
213 case spv::OpLoopMerge:
214 case spv::OpSelectionMerge:
215 break; // Nothing to do in analysis pass.
216
217 case spv::OpTypeVoid:
218 case spv::OpTypeBool:
219 case spv::OpTypeInt:
220 case spv::OpTypeFloat:
221 case spv::OpTypeVector:
222 case spv::OpTypeMatrix:
223 case spv::OpTypeImage:
224 case spv::OpTypeSampler:
225 case spv::OpTypeSampledImage:
226 case spv::OpTypeArray:
227 case spv::OpTypeRuntimeArray:
228 case spv::OpTypeStruct:
229 case spv::OpTypePointer:
230 case spv::OpTypeFunction:
231 DeclareType(insn);
Nicolas Capens157ba262019-12-10 17:49:14 -0500232 break;
233
Ben Claytonbc1c0672019-12-17 20:37:37 +0000234 case spv::OpVariable:
Nicolas Capens157ba262019-12-10 17:49:14 -0500235 {
Ben Claytonbc1c0672019-12-17 20:37:37 +0000236 Type::ID typeId = insn.word(1);
237 Object::ID resultId = insn.word(2);
238 auto storageClass = static_cast<spv::StorageClass>(insn.word(3));
239
240 auto &object = defs[resultId];
Nicolas Capens157ba262019-12-10 17:49:14 -0500241 object.kind = Object::Kind::Pointer;
Ben Claytonbc1c0672019-12-17 20:37:37 +0000242 object.definition = insn;
Nicolas Capens157ba262019-12-10 17:49:14 -0500243
Ben Claytonbc1c0672019-12-17 20:37:37 +0000244 ASSERT(getType(typeId).definition.opcode() == spv::OpTypePointer);
245 ASSERT(getType(typeId).storageClass == storageClass);
Nicolas Capens157ba262019-12-10 17:49:14 -0500246
Ben Claytonbc1c0672019-12-17 20:37:37 +0000247 switch(storageClass)
Nicolas Capens157ba262019-12-10 17:49:14 -0500248 {
Ben Claytonbc1c0672019-12-17 20:37:37 +0000249 case spv::StorageClassInput:
250 case spv::StorageClassOutput:
251 ProcessInterfaceVariable(object);
252 break;
253
254 case spv::StorageClassUniform:
255 case spv::StorageClassStorageBuffer:
256 object.kind = Object::Kind::DescriptorSet;
257 break;
258
259 case spv::StorageClassPushConstant:
260 case spv::StorageClassPrivate:
261 case spv::StorageClassFunction:
262 case spv::StorageClassUniformConstant:
263 break; // Correctly handled.
264
265 case spv::StorageClassWorkgroup:
266 {
267 auto &elTy = getType(getType(typeId).element);
Nicolas Capensff9f9b52020-04-14 00:46:38 -0400268 auto sizeInBytes = elTy.componentCount * static_cast<uint32_t>(sizeof(float));
Ben Claytonbc1c0672019-12-17 20:37:37 +0000269 workgroupMemory.allocate(resultId, sizeInBytes);
270 object.kind = Object::Kind::Pointer;
271 break;
272 }
273 case spv::StorageClassAtomicCounter:
274 case spv::StorageClassImage:
Nicolas Capens44bd43a2020-01-22 03:07:14 -0500275 UNSUPPORTED("StorageClass %d not yet supported", (int)storageClass);
Ben Claytonbc1c0672019-12-17 20:37:37 +0000276 break;
277
278 case spv::StorageClassCrossWorkgroup:
279 UNSUPPORTED("SPIR-V OpenCL Execution Model (StorageClassCrossWorkgroup)");
280 break;
281
282 case spv::StorageClassGeneric:
283 UNSUPPORTED("SPIR-V GenericPointer Capability (StorageClassGeneric)");
284 break;
285
286 default:
287 UNREACHABLE("Unexpected StorageClass %d", storageClass); // See Appendix A of the Vulkan spec.
288 break;
Nicolas Capens157ba262019-12-10 17:49:14 -0500289 }
Ben Claytonbc1c0672019-12-17 20:37:37 +0000290 break;
Nicolas Capens157ba262019-12-10 17:49:14 -0500291 }
292
Ben Claytonbc1c0672019-12-17 20:37:37 +0000293 case spv::OpConstant:
294 case spv::OpSpecConstant:
295 CreateConstant(insn).constantValue[0] = insn.word(3);
296 break;
297 case spv::OpConstantFalse:
298 case spv::OpSpecConstantFalse:
299 CreateConstant(insn).constantValue[0] = 0; // Represent Boolean false as zero.
300 break;
301 case spv::OpConstantTrue:
302 case spv::OpSpecConstantTrue:
303 CreateConstant(insn).constantValue[0] = ~0u; // Represent Boolean true as all bits set.
304 break;
305 case spv::OpConstantNull:
306 case spv::OpUndef:
Nicolas Capens157ba262019-12-10 17:49:14 -0500307 {
Ben Claytonbc1c0672019-12-17 20:37:37 +0000308 // TODO: consider a real LLVM-level undef. For now, zero is a perfectly good value.
309 // OpConstantNull forms a constant of arbitrary type, all zeros.
310 auto &object = CreateConstant(insn);
Nicolas Capens72f089c2020-04-08 23:37:08 -0400311 auto &objectTy = getType(object);
Nicolas Capensff9f9b52020-04-14 00:46:38 -0400312 for(auto i = 0u; i < objectTy.componentCount; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -0500313 {
Ben Claytonbc1c0672019-12-17 20:37:37 +0000314 object.constantValue[i] = 0;
Nicolas Capens157ba262019-12-10 17:49:14 -0500315 }
Ben Claytonbc1c0672019-12-17 20:37:37 +0000316 break;
Nicolas Capens157ba262019-12-10 17:49:14 -0500317 }
Ben Claytonbc1c0672019-12-17 20:37:37 +0000318 case spv::OpConstantComposite:
319 case spv::OpSpecConstantComposite:
Nicolas Capens157ba262019-12-10 17:49:14 -0500320 {
Ben Claytonbc1c0672019-12-17 20:37:37 +0000321 auto &object = CreateConstant(insn);
322 auto offset = 0u;
323 for(auto i = 0u; i < insn.wordCount() - 3; i++)
324 {
325 auto &constituent = getObject(insn.word(i + 3));
Nicolas Capens72f089c2020-04-08 23:37:08 -0400326 auto &constituentTy = getType(constituent);
Nicolas Capensff9f9b52020-04-14 00:46:38 -0400327 for(auto j = 0u; j < constituentTy.componentCount; j++)
Ben Claytonbc1c0672019-12-17 20:37:37 +0000328 {
329 object.constantValue[offset++] = constituent.constantValue[j];
330 }
331 }
332
333 auto objectId = Object::ID(insn.word(2));
334 auto decorationsIt = decorations.find(objectId);
335 if(decorationsIt != decorations.end() &&
336 decorationsIt->second.BuiltIn == spv::BuiltInWorkgroupSize)
337 {
338 // https://www.khronos.org/registry/vulkan/specs/1.1/html/vkspec.html#interfaces-builtin-variables :
339 // Decorating an object with the WorkgroupSize built-in
340 // decoration will make that object contain the dimensions
341 // of a local workgroup. If an object is decorated with the
342 // WorkgroupSize decoration, this must take precedence over
343 // any execution mode set for LocalSize.
344 // The object decorated with WorkgroupSize must be declared
345 // as a three-component vector of 32-bit integers.
Nicolas Capensff9f9b52020-04-14 00:46:38 -0400346 ASSERT(getType(object).componentCount == 3);
Ben Claytonbc1c0672019-12-17 20:37:37 +0000347 modes.WorkgroupSizeX = object.constantValue[0];
348 modes.WorkgroupSizeY = object.constantValue[1];
349 modes.WorkgroupSizeZ = object.constantValue[2];
350 }
351 break;
Nicolas Capens157ba262019-12-10 17:49:14 -0500352 }
Ben Claytonbc1c0672019-12-17 20:37:37 +0000353 case spv::OpSpecConstantOp:
354 EvalSpecConstantOp(insn);
355 break;
Ben Clayton9b156612019-03-13 19:48:31 +0000356
Ben Claytonbc1c0672019-12-17 20:37:37 +0000357 case spv::OpCapability:
358 {
359 auto capability = static_cast<spv::Capability>(insn.word(1));
360 switch(capability)
361 {
362 case spv::CapabilityMatrix: capabilities.Matrix = true; break;
363 case spv::CapabilityShader: capabilities.Shader = true; break;
364 case spv::CapabilityClipDistance: capabilities.ClipDistance = true; break;
365 case spv::CapabilityCullDistance: capabilities.CullDistance = true; break;
366 case spv::CapabilityInputAttachment: capabilities.InputAttachment = true; break;
367 case spv::CapabilitySampled1D: capabilities.Sampled1D = true; break;
368 case spv::CapabilityImage1D: capabilities.Image1D = true; break;
369 case spv::CapabilityImageCubeArray: capabilities.ImageCubeArray = true; break;
370 case spv::CapabilitySampledBuffer: capabilities.SampledBuffer = true; break;
371 case spv::CapabilitySampledCubeArray: capabilities.SampledCubeArray = true; break;
372 case spv::CapabilityImageBuffer: capabilities.ImageBuffer = true; break;
373 case spv::CapabilityStorageImageExtendedFormats: capabilities.StorageImageExtendedFormats = true; break;
374 case spv::CapabilityImageQuery: capabilities.ImageQuery = true; break;
375 case spv::CapabilityDerivativeControl: capabilities.DerivativeControl = true; break;
376 case spv::CapabilityGroupNonUniform: capabilities.GroupNonUniform = true; break;
377 case spv::CapabilityGroupNonUniformVote: capabilities.GroupNonUniformVote = true; break;
378 case spv::CapabilityGroupNonUniformArithmetic: capabilities.GroupNonUniformArithmetic = true; break;
379 case spv::CapabilityGroupNonUniformBallot: capabilities.GroupNonUniformBallot = true; break;
380 case spv::CapabilityGroupNonUniformShuffle: capabilities.GroupNonUniformShuffle = true; break;
381 case spv::CapabilityGroupNonUniformShuffleRelative: capabilities.GroupNonUniformShuffleRelative = true; break;
382 case spv::CapabilityDeviceGroup: capabilities.DeviceGroup = true; break;
383 case spv::CapabilityMultiView: capabilities.MultiView = true; break;
Alexis Hetu1ee36c92020-02-20 14:07:26 -0500384 case spv::CapabilityStencilExportEXT: capabilities.StencilExportEXT = true; break;
Ben Claytonbc1c0672019-12-17 20:37:37 +0000385 default:
386 UNSUPPORTED("Unsupported capability %u", insn.word(1));
387 }
388 break; // Various capabilities will be declared, but none affect our code generation at this point.
389 }
Ben Clayton9b156612019-03-13 19:48:31 +0000390
Ben Claytonbc1c0672019-12-17 20:37:37 +0000391 case spv::OpMemoryModel:
392 break; // Memory model does not affect our code generation until we decide to do Vulkan Memory Model support.
Nicolas Capens157ba262019-12-10 17:49:14 -0500393
Ben Claytonbc1c0672019-12-17 20:37:37 +0000394 case spv::OpFunction:
395 {
396 auto functionId = Function::ID(insn.word(2));
397 ASSERT_MSG(currentFunction == 0, "Functions %d and %d overlap", currentFunction.value(), functionId.value());
398 currentFunction = functionId;
399 auto &function = functions[functionId];
400 function.result = Type::ID(insn.word(1));
401 function.type = Type::ID(insn.word(4));
402 // Scan forward to find the function's label.
Ben Clayton7d098242020-03-13 13:07:12 +0000403 for(auto it = insn; it != end(); it++)
Ben Claytonbc1c0672019-12-17 20:37:37 +0000404 {
Ben Clayton7d098242020-03-13 13:07:12 +0000405 if(it.opcode() == spv::OpLabel)
Ben Claytonbc1c0672019-12-17 20:37:37 +0000406 {
Ben Clayton7d098242020-03-13 13:07:12 +0000407 function.entry = Block::ID(it.word(1));
408 break;
Ben Claytonbc1c0672019-12-17 20:37:37 +0000409 }
410 }
411 ASSERT_MSG(function.entry != 0, "Function<%d> has no label", currentFunction.value());
412 break;
413 }
Nicolas Capens157ba262019-12-10 17:49:14 -0500414
Ben Claytonbc1c0672019-12-17 20:37:37 +0000415 case spv::OpFunctionEnd:
416 currentFunction = 0;
417 break;
Nicolas Capens157ba262019-12-10 17:49:14 -0500418
Ben Claytonbc1c0672019-12-17 20:37:37 +0000419 case spv::OpExtInstImport:
420 {
Ben Clayton683bad82020-02-10 23:57:09 +0000421 static constexpr std::pair<const char *, Extension::Name> extensionsByName[] = {
Ben Claytonf6a6a412020-01-09 16:43:37 +0000422 { "GLSL.std.450", Extension::GLSLstd450 },
Ben Claytoncd55f052020-01-14 11:56:00 +0000423 { "OpenCL.DebugInfo.100", Extension::OpenCLDebugInfo100 },
Ben Claytonf6a6a412020-01-09 16:43:37 +0000424 };
Ben Clayton683bad82020-02-10 23:57:09 +0000425 static constexpr auto extensionCount = sizeof(extensionsByName) / sizeof(extensionsByName[0]);
426
Ben Claytonb36dbbe2020-01-08 12:18:43 +0000427 auto id = Extension::ID(insn.word(1));
428 auto name = insn.string(2);
429 auto ext = Extension{ Extension::Unknown };
Ben Clayton683bad82020-02-10 23:57:09 +0000430 for(size_t i = 0; i < extensionCount; i++)
Ben Claytonbc1c0672019-12-17 20:37:37 +0000431 {
Ben Clayton683bad82020-02-10 23:57:09 +0000432 if(0 == strcmp(name, extensionsByName[i].first))
Ben Claytonb36dbbe2020-01-08 12:18:43 +0000433 {
Ben Clayton683bad82020-02-10 23:57:09 +0000434 ext = Extension{ extensionsByName[i].second };
Ben Claytonb36dbbe2020-01-08 12:18:43 +0000435 break;
436 }
Ben Claytonbc1c0672019-12-17 20:37:37 +0000437 }
Ben Claytonb36dbbe2020-01-08 12:18:43 +0000438 if(ext.name == Extension::Unknown)
439 {
440 UNSUPPORTED("SPIR-V Extension: %s", name);
441 break;
442 }
Ben Clayton8842c8f2020-01-13 16:57:48 +0000443 extensionsByID.emplace(id, ext);
444 extensionsImported.emplace(ext.name);
Ben Claytonbc1c0672019-12-17 20:37:37 +0000445 break;
446 }
447 case spv::OpName:
448 case spv::OpMemberName:
449 case spv::OpSource:
450 case spv::OpSourceContinued:
451 case spv::OpSourceExtension:
452 case spv::OpLine:
453 case spv::OpNoLine:
454 case spv::OpModuleProcessed:
Ben Claytonbc1c0672019-12-17 20:37:37 +0000455 // No semantic impact
456 break;
Ben Clayton9b156612019-03-13 19:48:31 +0000457
Ben Clayton9c8823a2020-01-08 12:07:30 +0000458 case spv::OpString:
459 strings.emplace(insn.word(1), insn.string(2));
460 break;
461
Ben Claytonbc1c0672019-12-17 20:37:37 +0000462 case spv::OpFunctionParameter:
463 // These should have all been removed by preprocessing passes. If we see them here,
464 // our assumptions are wrong and we will probably generate wrong code.
465 UNREACHABLE("%s should have already been lowered.", OpcodeName(opcode).c_str());
466 break;
467
468 case spv::OpFunctionCall:
469 // TODO(b/141246700): Add full support for spv::OpFunctionCall
470 break;
471
472 case spv::OpFConvert:
473 UNSUPPORTED("SPIR-V Float16 or Float64 Capability (OpFConvert)");
474 break;
475
476 case spv::OpSConvert:
477 UNSUPPORTED("SPIR-V Int16 or Int64 Capability (OpSConvert)");
478 break;
479
480 case spv::OpUConvert:
481 UNSUPPORTED("SPIR-V Int16 or Int64 Capability (OpUConvert)");
482 break;
483
484 case spv::OpLoad:
485 case spv::OpAccessChain:
486 case spv::OpInBoundsAccessChain:
487 case spv::OpSampledImage:
488 case spv::OpImage:
Nicolas Capens157ba262019-12-10 17:49:14 -0500489 {
490 // Propagate the descriptor decorations to the result.
491 Object::ID resultId = insn.word(2);
492 Object::ID pointerId = insn.word(3);
493 const auto &d = descriptorDecorations.find(pointerId);
494
495 if(d != descriptorDecorations.end())
496 {
497 descriptorDecorations[resultId] = d->second;
498 }
499
500 DefineResult(insn);
501
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500502 if(opcode == spv::OpAccessChain || opcode == spv::OpInBoundsAccessChain)
Nicolas Capens157ba262019-12-10 17:49:14 -0500503 {
504 Decorations dd{};
505 ApplyDecorationsForAccessChain(&dd, &descriptorDecorations[resultId], pointerId, insn.wordCount() - 4, insn.wordPointer(4));
506 // Note: offset is the one thing that does *not* propagate, as the access chain accounts for it.
507 dd.HasOffset = false;
508 decorations[resultId].Apply(dd);
509 }
510 }
511 break;
Ben Clayton9b156612019-03-13 19:48:31 +0000512
Ben Claytonbc1c0672019-12-17 20:37:37 +0000513 case spv::OpCompositeConstruct:
514 case spv::OpCompositeInsert:
515 case spv::OpCompositeExtract:
516 case spv::OpVectorShuffle:
517 case spv::OpVectorTimesScalar:
518 case spv::OpMatrixTimesScalar:
519 case spv::OpMatrixTimesVector:
520 case spv::OpVectorTimesMatrix:
521 case spv::OpMatrixTimesMatrix:
522 case spv::OpOuterProduct:
523 case spv::OpTranspose:
524 case spv::OpVectorExtractDynamic:
525 case spv::OpVectorInsertDynamic:
526 // Unary ops
527 case spv::OpNot:
528 case spv::OpBitFieldInsert:
529 case spv::OpBitFieldSExtract:
530 case spv::OpBitFieldUExtract:
531 case spv::OpBitReverse:
532 case spv::OpBitCount:
533 case spv::OpSNegate:
534 case spv::OpFNegate:
535 case spv::OpLogicalNot:
536 case spv::OpQuantizeToF16:
537 // Binary ops
538 case spv::OpIAdd:
539 case spv::OpISub:
540 case spv::OpIMul:
541 case spv::OpSDiv:
542 case spv::OpUDiv:
543 case spv::OpFAdd:
544 case spv::OpFSub:
545 case spv::OpFMul:
546 case spv::OpFDiv:
547 case spv::OpFMod:
548 case spv::OpFRem:
549 case spv::OpFOrdEqual:
550 case spv::OpFUnordEqual:
551 case spv::OpFOrdNotEqual:
552 case spv::OpFUnordNotEqual:
553 case spv::OpFOrdLessThan:
554 case spv::OpFUnordLessThan:
555 case spv::OpFOrdGreaterThan:
556 case spv::OpFUnordGreaterThan:
557 case spv::OpFOrdLessThanEqual:
558 case spv::OpFUnordLessThanEqual:
559 case spv::OpFOrdGreaterThanEqual:
560 case spv::OpFUnordGreaterThanEqual:
561 case spv::OpSMod:
562 case spv::OpSRem:
563 case spv::OpUMod:
564 case spv::OpIEqual:
565 case spv::OpINotEqual:
566 case spv::OpUGreaterThan:
567 case spv::OpSGreaterThan:
568 case spv::OpUGreaterThanEqual:
569 case spv::OpSGreaterThanEqual:
570 case spv::OpULessThan:
571 case spv::OpSLessThan:
572 case spv::OpULessThanEqual:
573 case spv::OpSLessThanEqual:
574 case spv::OpShiftRightLogical:
575 case spv::OpShiftRightArithmetic:
576 case spv::OpShiftLeftLogical:
577 case spv::OpBitwiseOr:
578 case spv::OpBitwiseXor:
579 case spv::OpBitwiseAnd:
580 case spv::OpLogicalOr:
581 case spv::OpLogicalAnd:
582 case spv::OpLogicalEqual:
583 case spv::OpLogicalNotEqual:
584 case spv::OpUMulExtended:
585 case spv::OpSMulExtended:
586 case spv::OpIAddCarry:
587 case spv::OpISubBorrow:
588 case spv::OpDot:
589 case spv::OpConvertFToU:
590 case spv::OpConvertFToS:
591 case spv::OpConvertSToF:
592 case spv::OpConvertUToF:
593 case spv::OpBitcast:
594 case spv::OpSelect:
Ben Claytonbc1c0672019-12-17 20:37:37 +0000595 case spv::OpIsInf:
596 case spv::OpIsNan:
597 case spv::OpAny:
598 case spv::OpAll:
599 case spv::OpDPdx:
600 case spv::OpDPdxCoarse:
601 case spv::OpDPdy:
602 case spv::OpDPdyCoarse:
603 case spv::OpFwidth:
604 case spv::OpFwidthCoarse:
605 case spv::OpDPdxFine:
606 case spv::OpDPdyFine:
607 case spv::OpFwidthFine:
608 case spv::OpAtomicLoad:
609 case spv::OpAtomicIAdd:
610 case spv::OpAtomicISub:
611 case spv::OpAtomicSMin:
612 case spv::OpAtomicSMax:
613 case spv::OpAtomicUMin:
614 case spv::OpAtomicUMax:
615 case spv::OpAtomicAnd:
616 case spv::OpAtomicOr:
617 case spv::OpAtomicXor:
618 case spv::OpAtomicIIncrement:
619 case spv::OpAtomicIDecrement:
620 case spv::OpAtomicExchange:
621 case spv::OpAtomicCompareExchange:
622 case spv::OpPhi:
623 case spv::OpImageSampleImplicitLod:
624 case spv::OpImageSampleExplicitLod:
625 case spv::OpImageSampleDrefImplicitLod:
626 case spv::OpImageSampleDrefExplicitLod:
627 case spv::OpImageSampleProjImplicitLod:
628 case spv::OpImageSampleProjExplicitLod:
629 case spv::OpImageSampleProjDrefImplicitLod:
630 case spv::OpImageSampleProjDrefExplicitLod:
631 case spv::OpImageGather:
632 case spv::OpImageDrefGather:
633 case spv::OpImageFetch:
634 case spv::OpImageQuerySizeLod:
635 case spv::OpImageQuerySize:
636 case spv::OpImageQueryLod:
637 case spv::OpImageQueryLevels:
638 case spv::OpImageQuerySamples:
639 case spv::OpImageRead:
640 case spv::OpImageTexelPointer:
641 case spv::OpGroupNonUniformElect:
642 case spv::OpGroupNonUniformAll:
643 case spv::OpGroupNonUniformAny:
644 case spv::OpGroupNonUniformAllEqual:
645 case spv::OpGroupNonUniformBroadcast:
646 case spv::OpGroupNonUniformBroadcastFirst:
647 case spv::OpGroupNonUniformBallot:
648 case spv::OpGroupNonUniformInverseBallot:
649 case spv::OpGroupNonUniformBallotBitExtract:
650 case spv::OpGroupNonUniformBallotBitCount:
651 case spv::OpGroupNonUniformBallotFindLSB:
652 case spv::OpGroupNonUniformBallotFindMSB:
653 case spv::OpGroupNonUniformShuffle:
654 case spv::OpGroupNonUniformShuffleXor:
655 case spv::OpGroupNonUniformShuffleUp:
656 case spv::OpGroupNonUniformShuffleDown:
657 case spv::OpGroupNonUniformIAdd:
658 case spv::OpGroupNonUniformFAdd:
659 case spv::OpGroupNonUniformIMul:
660 case spv::OpGroupNonUniformFMul:
661 case spv::OpGroupNonUniformSMin:
662 case spv::OpGroupNonUniformUMin:
663 case spv::OpGroupNonUniformFMin:
664 case spv::OpGroupNonUniformSMax:
665 case spv::OpGroupNonUniformUMax:
666 case spv::OpGroupNonUniformFMax:
667 case spv::OpGroupNonUniformBitwiseAnd:
668 case spv::OpGroupNonUniformBitwiseOr:
669 case spv::OpGroupNonUniformBitwiseXor:
670 case spv::OpGroupNonUniformLogicalAnd:
671 case spv::OpGroupNonUniformLogicalOr:
672 case spv::OpGroupNonUniformLogicalXor:
673 case spv::OpCopyObject:
674 case spv::OpArrayLength:
675 // Instructions that yield an intermediate value or divergent pointer
676 DefineResult(insn);
677 break;
Ben Claytone4605da2019-05-09 16:24:01 +0100678
Ben Claytonb36dbbe2020-01-08 12:18:43 +0000679 case spv::OpExtInst:
680 switch(getExtension(insn.word(3)).name)
681 {
682 case Extension::GLSLstd450:
683 DefineResult(insn);
684 break;
Ben Claytoncd55f052020-01-14 11:56:00 +0000685 case Extension::OpenCLDebugInfo100:
686 DefineOpenCLDebugInfo100(insn);
687 break;
Ben Claytonb36dbbe2020-01-08 12:18:43 +0000688 default:
689 UNREACHABLE("Unexpected Extension name %d", int(getExtension(insn.word(3)).name));
690 break;
691 }
692 break;
693
Ben Claytonbc1c0672019-12-17 20:37:37 +0000694 case spv::OpStore:
695 case spv::OpAtomicStore:
696 case spv::OpImageWrite:
697 case spv::OpCopyMemory:
698 case spv::OpMemoryBarrier:
699 // Don't need to do anything during analysis pass
700 break;
Nicolas Capens157ba262019-12-10 17:49:14 -0500701
Ben Claytonbc1c0672019-12-17 20:37:37 +0000702 case spv::OpControlBarrier:
703 modes.ContainsControlBarriers = true;
704 break;
Nicolas Capens157ba262019-12-10 17:49:14 -0500705
Ben Claytonbc1c0672019-12-17 20:37:37 +0000706 case spv::OpExtension:
707 {
708 auto ext = insn.string(1);
709 // Part of core SPIR-V 1.3. Vulkan 1.1 implementations must also accept the pre-1.3
710 // extension per Appendix A, `Vulkan Environment for SPIR-V`.
711 if(!strcmp(ext, "SPV_KHR_storage_buffer_storage_class")) break;
712 if(!strcmp(ext, "SPV_KHR_shader_draw_parameters")) break;
713 if(!strcmp(ext, "SPV_KHR_16bit_storage")) break;
714 if(!strcmp(ext, "SPV_KHR_variable_pointers")) break;
715 if(!strcmp(ext, "SPV_KHR_device_group")) break;
716 if(!strcmp(ext, "SPV_KHR_multiview")) break;
Alexis Hetu1ee36c92020-02-20 14:07:26 -0500717 if(!strcmp(ext, "SPV_EXT_shader_stencil_export")) break;
Ben Claytonbc1c0672019-12-17 20:37:37 +0000718 UNSUPPORTED("SPIR-V Extension: %s", ext);
719 break;
720 }
Ben Claytonc0cf68b2019-03-21 17:46:08 +0000721
Ben Claytonbc1c0672019-12-17 20:37:37 +0000722 default:
Nicolas Capens865f8892020-01-21 14:27:10 -0500723 UNSUPPORTED("%s", OpcodeName(opcode).c_str());
Nicolas Capens157ba262019-12-10 17:49:14 -0500724 }
Chris Forbesd5aed492019-02-02 15:18:52 -0800725 }
Chris Forbesc61271e2019-02-19 17:01:28 -0800726
Nicolas Capens157ba262019-12-10 17:49:14 -0500727 ASSERT_MSG(entryPoint != 0, "Entry point '%s' not found", entryPointName);
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500728 for(auto &it : functions)
Nicolas Capensfabdec52019-03-21 17:04:05 -0400729 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500730 it.second.AssignBlockFields();
Nicolas Capensfabdec52019-03-21 17:04:05 -0400731 }
Ben Claytonb0ca2a82020-01-08 13:00:57 +0000732
Ben Clayton0d6791c2020-04-22 21:55:27 +0100733#ifdef SPIRV_SHADER_CFG_GRAPHVIZ_DOT_FILEPATH
734 {
735 char path[1024];
736 snprintf(path, sizeof(path), SPIRV_SHADER_CFG_GRAPHVIZ_DOT_FILEPATH, codeSerialID);
737 WriteCFGGraphVizDotFile(path);
738 }
739#endif
740
Ben Claytonb0ca2a82020-01-08 13:00:57 +0000741 dbgCreateFile();
742}
743
744SpirvShader::~SpirvShader()
745{
746 dbgTerm();
Nicolas Capens157ba262019-12-10 17:49:14 -0500747}
Nicolas Capensfabdec52019-03-21 17:04:05 -0400748
Nicolas Capens157ba262019-12-10 17:49:14 -0500749void SpirvShader::DeclareType(InsnIterator insn)
750{
751 Type::ID resultId = insn.word(1);
752
753 auto &type = types[resultId];
754 type.definition = insn;
Nicolas Capensff9f9b52020-04-14 00:46:38 -0400755 type.componentCount = ComputeTypeSize(insn);
Nicolas Capens157ba262019-12-10 17:49:14 -0500756
757 // A structure is a builtin block if it has a builtin
758 // member. All members of such a structure are builtins.
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500759 switch(insn.opcode())
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000760 {
Ben Claytonbc1c0672019-12-17 20:37:37 +0000761 case spv::OpTypeStruct:
Nicolas Capens157ba262019-12-10 17:49:14 -0500762 {
Ben Claytonbc1c0672019-12-17 20:37:37 +0000763 auto d = memberDecorations.find(resultId);
764 if(d != memberDecorations.end())
Nicolas Capens157ba262019-12-10 17:49:14 -0500765 {
Ben Claytonbc1c0672019-12-17 20:37:37 +0000766 for(auto &m : d->second)
Nicolas Capens157ba262019-12-10 17:49:14 -0500767 {
Ben Claytonbc1c0672019-12-17 20:37:37 +0000768 if(m.HasBuiltIn)
769 {
770 type.isBuiltInBlock = true;
771 break;
772 }
Nicolas Capens157ba262019-12-10 17:49:14 -0500773 }
774 }
Ben Claytonbc1c0672019-12-17 20:37:37 +0000775 break;
Nicolas Capens157ba262019-12-10 17:49:14 -0500776 }
Ben Claytonbc1c0672019-12-17 20:37:37 +0000777 case spv::OpTypePointer:
778 {
779 Type::ID elementTypeId = insn.word(3);
780 type.element = elementTypeId;
781 type.isBuiltInBlock = getType(elementTypeId).isBuiltInBlock;
782 type.storageClass = static_cast<spv::StorageClass>(insn.word(2));
783 break;
784 }
785 case spv::OpTypeVector:
786 case spv::OpTypeMatrix:
787 case spv::OpTypeArray:
788 case spv::OpTypeRuntimeArray:
789 {
790 Type::ID elementTypeId = insn.word(2);
791 type.element = elementTypeId;
792 break;
793 }
794 default:
795 break;
Nicolas Capens157ba262019-12-10 17:49:14 -0500796 }
797}
798
Ben Claytonbc1c0672019-12-17 20:37:37 +0000799SpirvShader::Object &SpirvShader::CreateConstant(InsnIterator insn)
Nicolas Capens157ba262019-12-10 17:49:14 -0500800{
801 Type::ID typeId = insn.word(1);
802 Object::ID resultId = insn.word(2);
803 auto &object = defs[resultId];
804 auto &objectTy = getType(typeId);
Nicolas Capens157ba262019-12-10 17:49:14 -0500805 object.kind = Object::Kind::Constant;
806 object.definition = insn;
Nicolas Capens2f4b6032020-04-09 02:01:50 -0400807 object.constantValue.resize(objectTy.componentCount);
Nicolas Capens72f089c2020-04-08 23:37:08 -0400808
Nicolas Capens157ba262019-12-10 17:49:14 -0500809 return object;
810}
811
812void SpirvShader::ProcessInterfaceVariable(Object &object)
813{
Nicolas Capens72f089c2020-04-08 23:37:08 -0400814 auto &objectTy = getType(object);
Nicolas Capens157ba262019-12-10 17:49:14 -0500815 ASSERT(objectTy.storageClass == spv::StorageClassInput || objectTy.storageClass == spv::StorageClassOutput);
816
817 ASSERT(objectTy.opcode() == spv::OpTypePointer);
818 auto pointeeTy = getType(objectTy.element);
819
820 auto &builtinInterface = (objectTy.storageClass == spv::StorageClassInput) ? inputBuiltins : outputBuiltins;
821 auto &userDefinedInterface = (objectTy.storageClass == spv::StorageClassInput) ? inputs : outputs;
822
823 ASSERT(object.opcode() == spv::OpVariable);
824 Object::ID resultId = object.definition.word(2);
825
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500826 if(objectTy.isBuiltInBlock)
Nicolas Capens157ba262019-12-10 17:49:14 -0500827 {
Nicolas Capens71186752020-04-09 01:05:31 -0400828 // Walk the builtin block, registering each of its members separately.
Nicolas Capens157ba262019-12-10 17:49:14 -0500829 auto m = memberDecorations.find(objectTy.element);
Nicolas Capens71186752020-04-09 01:05:31 -0400830 ASSERT(m != memberDecorations.end()); // Otherwise we wouldn't have marked the type chain
Nicolas Capens157ba262019-12-10 17:49:14 -0500831 auto &structType = pointeeTy.definition;
Nicolas Capens71186752020-04-09 01:05:31 -0400832 auto memberIndex = 0u;
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000833 auto offset = 0u;
Nicolas Capens71186752020-04-09 01:05:31 -0400834
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500835 for(auto &member : m->second)
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000836 {
Nicolas Capens71186752020-04-09 01:05:31 -0400837 auto &memberType = getType(structType.word(2 + memberIndex));
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000838
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500839 if(member.HasBuiltIn)
Ben Clayton9b62c5e2019-03-08 09:32:34 +0000840 {
Nicolas Capensff9f9b52020-04-14 00:46:38 -0400841 builtinInterface[member.BuiltIn] = { resultId, offset, memberType.componentCount };
Ben Clayton9b62c5e2019-03-08 09:32:34 +0000842 }
Ben Claytonc0cf68b2019-03-21 17:46:08 +0000843
Nicolas Capensff9f9b52020-04-14 00:46:38 -0400844 offset += memberType.componentCount;
Nicolas Capens71186752020-04-09 01:05:31 -0400845 ++memberIndex;
Nicolas Capens157ba262019-12-10 17:49:14 -0500846 }
Nicolas Capens71186752020-04-09 01:05:31 -0400847
Nicolas Capens157ba262019-12-10 17:49:14 -0500848 return;
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000849 }
850
Nicolas Capens157ba262019-12-10 17:49:14 -0500851 auto d = decorations.find(resultId);
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500852 if(d != decorations.end() && d->second.HasBuiltIn)
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000853 {
Nicolas Capensff9f9b52020-04-14 00:46:38 -0400854 builtinInterface[d->second.BuiltIn] = { resultId, 0, pointeeTy.componentCount };
Nicolas Capens157ba262019-12-10 17:49:14 -0500855 }
856 else
857 {
858 object.kind = Object::Kind::InterfaceVariable;
859 VisitInterface(resultId,
Ben Claytonbc1c0672019-12-17 20:37:37 +0000860 [&userDefinedInterface](Decorations const &d, AttribType type) {
861 // Populate a single scalar slot in the interface from a collection of decorations and the intended component type.
862 auto scalarSlot = (d.Location << 2) | d.Component;
863 ASSERT(scalarSlot >= 0 &&
864 scalarSlot < static_cast<int32_t>(userDefinedInterface.size()));
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000865
Ben Claytonbc1c0672019-12-17 20:37:37 +0000866 auto &slot = userDefinedInterface[scalarSlot];
867 slot.Type = type;
868 slot.Flat = d.Flat;
869 slot.NoPerspective = d.NoPerspective;
870 slot.Centroid = d.Centroid;
871 });
Nicolas Capens157ba262019-12-10 17:49:14 -0500872 }
873}
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000874
Nicolas Capens157ba262019-12-10 17:49:14 -0500875void SpirvShader::ProcessExecutionMode(InsnIterator insn)
876{
Nicolas Capens57eb48a2020-05-15 17:07:07 -0400877 Function::ID function = insn.word(1);
878 if(function != entryPoint)
879 {
880 return;
881 }
882
Nicolas Capens157ba262019-12-10 17:49:14 -0500883 auto mode = static_cast<spv::ExecutionMode>(insn.word(2));
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500884 switch(mode)
Nicolas Capens157ba262019-12-10 17:49:14 -0500885 {
Ben Claytonbc1c0672019-12-17 20:37:37 +0000886 case spv::ExecutionModeEarlyFragmentTests:
887 modes.EarlyFragmentTests = true;
888 break;
889 case spv::ExecutionModeDepthReplacing:
890 modes.DepthReplacing = true;
891 break;
892 case spv::ExecutionModeDepthGreater:
893 modes.DepthGreater = true;
894 break;
895 case spv::ExecutionModeDepthLess:
896 modes.DepthLess = true;
897 break;
898 case spv::ExecutionModeDepthUnchanged:
899 modes.DepthUnchanged = true;
900 break;
901 case spv::ExecutionModeLocalSize:
902 modes.WorkgroupSizeX = insn.word(3);
903 modes.WorkgroupSizeY = insn.word(4);
904 modes.WorkgroupSizeZ = insn.word(5);
905 break;
906 case spv::ExecutionModeOriginUpperLeft:
907 // This is always the case for a Vulkan shader. Do nothing.
908 break;
909 default:
910 UNREACHABLE("Execution mode: %d", int(mode));
Nicolas Capens157ba262019-12-10 17:49:14 -0500911 }
912}
Ben Claytonc0cf68b2019-03-21 17:46:08 +0000913
Nicolas Capens157ba262019-12-10 17:49:14 -0500914uint32_t SpirvShader::ComputeTypeSize(InsnIterator insn)
915{
916 // Types are always built from the bottom up (with the exception of forward ptrs, which
917 // don't appear in Vulkan shaders. Therefore, we can always assume our component parts have
918 // already been described (and so their sizes determined)
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500919 switch(insn.opcode())
Nicolas Capens157ba262019-12-10 17:49:14 -0500920 {
Ben Claytonbc1c0672019-12-17 20:37:37 +0000921 case spv::OpTypeVoid:
922 case spv::OpTypeSampler:
923 case spv::OpTypeImage:
924 case spv::OpTypeSampledImage:
925 case spv::OpTypeFunction:
926 case spv::OpTypeRuntimeArray:
927 // Objects that don't consume any space.
928 // Descriptor-backed objects currently only need exist at compile-time.
929 // Runtime arrays don't appear in places where their size would be interesting
930 return 0;
Nicolas Capens157ba262019-12-10 17:49:14 -0500931
Ben Claytonbc1c0672019-12-17 20:37:37 +0000932 case spv::OpTypeBool:
933 case spv::OpTypeFloat:
934 case spv::OpTypeInt:
935 // All the fundamental types are 1 component. If we ever add support for 8/16/64-bit components,
936 // we might need to change this, but only 32 bit components are required for Vulkan 1.1.
937 return 1;
Nicolas Capens157ba262019-12-10 17:49:14 -0500938
Ben Claytonbc1c0672019-12-17 20:37:37 +0000939 case spv::OpTypeVector:
940 case spv::OpTypeMatrix:
941 // Vectors and matrices both consume element count * element size.
Nicolas Capensff9f9b52020-04-14 00:46:38 -0400942 return getType(insn.word(2)).componentCount * insn.word(3);
Nicolas Capens157ba262019-12-10 17:49:14 -0500943
Ben Claytonbc1c0672019-12-17 20:37:37 +0000944 case spv::OpTypeArray:
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000945 {
Ben Claytonbc1c0672019-12-17 20:37:37 +0000946 // Element count * element size. Array sizes come from constant ids.
947 auto arraySize = GetConstScalarInt(insn.word(3));
Nicolas Capensff9f9b52020-04-14 00:46:38 -0400948 return getType(insn.word(2)).componentCount * arraySize;
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000949 }
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000950
Ben Claytonbc1c0672019-12-17 20:37:37 +0000951 case spv::OpTypeStruct:
952 {
953 uint32_t size = 0;
954 for(uint32_t i = 2u; i < insn.wordCount(); i++)
955 {
Nicolas Capensff9f9b52020-04-14 00:46:38 -0400956 size += getType(insn.word(i)).componentCount;
Ben Claytonbc1c0672019-12-17 20:37:37 +0000957 }
958 return size;
959 }
Nicolas Capens157ba262019-12-10 17:49:14 -0500960
Ben Claytonbc1c0672019-12-17 20:37:37 +0000961 case spv::OpTypePointer:
962 // Runtime representation of a pointer is a per-lane index.
963 // Note: clients are expected to look through the pointer if they want the pointee size instead.
964 return 1;
965
966 default:
967 UNREACHABLE("%s", OpcodeName(insn.opcode()).c_str());
968 return 0;
Nicolas Capens157ba262019-12-10 17:49:14 -0500969 }
970}
971
972int SpirvShader::VisitInterfaceInner(Type::ID id, Decorations d, const InterfaceVisitor &f) const
973{
974 // Recursively walks variable definition and its type tree, taking into account
975 // any explicit Location or Component decorations encountered; where explicit
976 // Locations or Components are not specified, assigns them sequentially.
977 // Collected decorations are carried down toward the leaves and across
978 // siblings; Effect of decorations intentionally does not flow back up the tree.
979 //
980 // F is a functor to be called with the effective decoration set for every component.
981 //
982 // Returns the next available location, and calls f().
983
984 // This covers the rules in Vulkan 1.1 spec, 14.1.4 Location Assignment.
985
986 ApplyDecorationsForId(&d, id);
987
988 auto const &obj = getType(id);
989 switch(obj.opcode())
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000990 {
Ben Claytonbc1c0672019-12-17 20:37:37 +0000991 case spv::OpTypePointer:
992 return VisitInterfaceInner(obj.definition.word(3), d, f);
993 case spv::OpTypeMatrix:
994 for(auto i = 0u; i < obj.definition.word(3); i++, d.Location++)
995 {
996 // consumes same components of N consecutive locations
997 VisitInterfaceInner(obj.definition.word(2), d, f);
998 }
999 return d.Location;
1000 case spv::OpTypeVector:
1001 for(auto i = 0u; i < obj.definition.word(3); i++, d.Component++)
1002 {
1003 // consumes N consecutive components in the same location
1004 VisitInterfaceInner(obj.definition.word(2), d, f);
1005 }
1006 return d.Location + 1;
1007 case spv::OpTypeFloat:
1008 f(d, ATTRIBTYPE_FLOAT);
1009 return d.Location + 1;
1010 case spv::OpTypeInt:
1011 f(d, obj.definition.word(3) ? ATTRIBTYPE_INT : ATTRIBTYPE_UINT);
1012 return d.Location + 1;
1013 case spv::OpTypeBool:
1014 f(d, ATTRIBTYPE_UINT);
1015 return d.Location + 1;
1016 case spv::OpTypeStruct:
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001017 {
Ben Claytonbc1c0672019-12-17 20:37:37 +00001018 // iterate over members, which may themselves have Location/Component decorations
1019 for(auto i = 0u; i < obj.definition.wordCount() - 2; i++)
1020 {
1021 ApplyDecorationsForIdMember(&d, id, i);
1022 d.Location = VisitInterfaceInner(obj.definition.word(i + 2), d, f);
1023 d.Component = 0; // Implicit locations always have component=0
1024 }
1025 return d.Location;
Nicolas Capens157ba262019-12-10 17:49:14 -05001026 }
Ben Claytonbc1c0672019-12-17 20:37:37 +00001027 case spv::OpTypeArray:
Nicolas Capens157ba262019-12-10 17:49:14 -05001028 {
Ben Claytonbc1c0672019-12-17 20:37:37 +00001029 auto arraySize = GetConstScalarInt(obj.definition.word(3));
1030 for(auto i = 0u; i < arraySize; i++)
1031 {
1032 d.Location = VisitInterfaceInner(obj.definition.word(2), d, f);
1033 }
1034 return d.Location;
Nicolas Capens157ba262019-12-10 17:49:14 -05001035 }
Ben Claytonbc1c0672019-12-17 20:37:37 +00001036 default:
1037 // Intentionally partial; most opcodes do not participate in type hierarchies
1038 return 0;
Nicolas Capens157ba262019-12-10 17:49:14 -05001039 }
1040}
1041
1042void SpirvShader::VisitInterface(Object::ID id, const InterfaceVisitor &f) const
1043{
1044 // Walk a variable definition and call f for each component in it.
1045 Decorations d{};
1046 ApplyDecorationsForId(&d, id);
1047
1048 auto def = getObject(id).definition;
1049 ASSERT(def.opcode() == spv::OpVariable);
1050 VisitInterfaceInner(def.word(1), d, f);
1051}
1052
1053void SpirvShader::ApplyDecorationsForAccessChain(Decorations *d, DescriptorDecorations *dd, Object::ID baseId, uint32_t numIndexes, uint32_t const *indexIds) const
1054{
1055 ApplyDecorationsForId(d, baseId);
1056 auto &baseObject = getObject(baseId);
Nicolas Capens72f089c2020-04-08 23:37:08 -04001057 ApplyDecorationsForId(d, baseObject.typeId());
1058 auto typeId = getType(baseObject).element;
Nicolas Capens157ba262019-12-10 17:49:14 -05001059
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001060 for(auto i = 0u; i < numIndexes; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05001061 {
1062 ApplyDecorationsForId(d, typeId);
Ben Claytonbc1c0672019-12-17 20:37:37 +00001063 auto &type = getType(typeId);
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001064 switch(type.opcode())
Nicolas Capens157ba262019-12-10 17:49:14 -05001065 {
Ben Claytonbc1c0672019-12-17 20:37:37 +00001066 case spv::OpTypeStruct:
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001067 {
Ben Claytonbc1c0672019-12-17 20:37:37 +00001068 int memberIndex = GetConstScalarInt(indexIds[i]);
1069 ApplyDecorationsForIdMember(d, typeId, memberIndex);
1070 typeId = type.definition.word(2u + memberIndex);
1071 break;
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001072 }
Ben Claytonbc1c0672019-12-17 20:37:37 +00001073 case spv::OpTypeArray:
1074 case spv::OpTypeRuntimeArray:
1075 if(dd->InputAttachmentIndex >= 0)
1076 {
1077 dd->InputAttachmentIndex += GetConstScalarInt(indexIds[i]);
1078 }
1079 typeId = type.element;
1080 break;
1081 case spv::OpTypeVector:
1082 typeId = type.element;
1083 break;
1084 case spv::OpTypeMatrix:
1085 typeId = type.element;
1086 d->InsideMatrix = true;
1087 break;
1088 default:
1089 UNREACHABLE("%s", OpcodeName(type.definition.opcode()).c_str());
Nicolas Capens157ba262019-12-10 17:49:14 -05001090 }
1091 }
1092}
1093
1094SIMD::Pointer SpirvShader::WalkExplicitLayoutAccessChain(Object::ID baseId, uint32_t numIndexes, uint32_t const *indexIds, EmitState const *state) const
1095{
1096 // Produce a offset into external memory in sizeof(float) units
1097
1098 auto &baseObject = getObject(baseId);
Nicolas Capens72f089c2020-04-08 23:37:08 -04001099 Type::ID typeId = getType(baseObject).element;
Nicolas Capens157ba262019-12-10 17:49:14 -05001100 Decorations d = {};
Nicolas Capens72f089c2020-04-08 23:37:08 -04001101 ApplyDecorationsForId(&d, baseObject.typeId());
Nicolas Capens157ba262019-12-10 17:49:14 -05001102
Nicolas Capens479d1432020-01-31 11:19:21 -05001103 Int arrayIndex = 0;
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001104 if(baseObject.kind == Object::Kind::DescriptorSet)
Nicolas Capens157ba262019-12-10 17:49:14 -05001105 {
1106 auto type = getType(typeId).definition.opcode();
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001107 if(type == spv::OpTypeArray || type == spv::OpTypeRuntimeArray)
Nicolas Capens157ba262019-12-10 17:49:14 -05001108 {
Nicolas Capens479d1432020-01-31 11:19:21 -05001109 auto &obj = getObject(indexIds[0]);
1110 ASSERT(obj.kind == Object::Kind::Constant || obj.kind == Object::Kind::Intermediate);
1111 if(obj.kind == Object::Kind::Constant)
1112 {
1113 arrayIndex = GetConstScalarInt(indexIds[0]);
1114 }
1115 else
1116 {
1117 // Note: the value of indexIds[0] must be dynamically uniform.
1118 arrayIndex = Extract(state->getIntermediate(indexIds[0]).Int(0), 0);
1119 }
Nicolas Capens157ba262019-12-10 17:49:14 -05001120
1121 numIndexes--;
1122 indexIds++;
1123 typeId = getType(typeId).element;
1124 }
1125 }
1126
1127 auto ptr = GetPointerToData(baseId, arrayIndex, state);
1128
1129 int constantOffset = 0;
1130
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001131 for(auto i = 0u; i < numIndexes; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05001132 {
Ben Claytonbc1c0672019-12-17 20:37:37 +00001133 auto &type = getType(typeId);
Nicolas Capens157ba262019-12-10 17:49:14 -05001134 ApplyDecorationsForId(&d, typeId);
1135
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001136 switch(type.definition.opcode())
Nicolas Capens157ba262019-12-10 17:49:14 -05001137 {
Ben Claytonbc1c0672019-12-17 20:37:37 +00001138 case spv::OpTypeStruct:
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001139 {
Ben Claytonbc1c0672019-12-17 20:37:37 +00001140 int memberIndex = GetConstScalarInt(indexIds[i]);
1141 ApplyDecorationsForIdMember(&d, typeId, memberIndex);
1142 ASSERT(d.HasOffset);
1143 constantOffset += d.Offset;
1144 typeId = type.definition.word(2u + memberIndex);
1145 break;
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001146 }
Ben Claytonbc1c0672019-12-17 20:37:37 +00001147 case spv::OpTypeArray:
1148 case spv::OpTypeRuntimeArray:
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001149 {
Ben Claytonbc1c0672019-12-17 20:37:37 +00001150 // TODO: b/127950082: Check bounds.
1151 ASSERT(d.HasArrayStride);
1152 auto &obj = getObject(indexIds[i]);
1153 if(obj.kind == Object::Kind::Constant)
1154 {
1155 constantOffset += d.ArrayStride * GetConstScalarInt(indexIds[i]);
1156 }
1157 else
1158 {
1159 ptr += SIMD::Int(d.ArrayStride) * state->getIntermediate(indexIds[i]).Int(0);
1160 }
1161 typeId = type.element;
1162 break;
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001163 }
Ben Claytonbc1c0672019-12-17 20:37:37 +00001164 case spv::OpTypeMatrix:
Chris Forbes17813932019-04-18 11:45:54 -07001165 {
Ben Claytonbc1c0672019-12-17 20:37:37 +00001166 // TODO: b/127950082: Check bounds.
1167 ASSERT(d.HasMatrixStride);
1168 d.InsideMatrix = true;
1169 auto columnStride = (d.HasRowMajor && d.RowMajor) ? static_cast<int32_t>(sizeof(float)) : d.MatrixStride;
1170 auto &obj = getObject(indexIds[i]);
1171 if(obj.kind == Object::Kind::Constant)
1172 {
1173 constantOffset += columnStride * GetConstScalarInt(indexIds[i]);
1174 }
1175 else
1176 {
1177 ptr += SIMD::Int(columnStride) * state->getIntermediate(indexIds[i]).Int(0);
1178 }
1179 typeId = type.element;
1180 break;
Chris Forbes17813932019-04-18 11:45:54 -07001181 }
Ben Claytonbc1c0672019-12-17 20:37:37 +00001182 case spv::OpTypeVector:
Chris Forbesa16238d2019-04-18 16:31:54 -07001183 {
Ben Claytonbc1c0672019-12-17 20:37:37 +00001184 auto elemStride = (d.InsideMatrix && d.HasRowMajor && d.RowMajor) ? d.MatrixStride : static_cast<int32_t>(sizeof(float));
1185 auto &obj = getObject(indexIds[i]);
1186 if(obj.kind == Object::Kind::Constant)
1187 {
1188 constantOffset += elemStride * GetConstScalarInt(indexIds[i]);
1189 }
1190 else
1191 {
1192 ptr += SIMD::Int(elemStride) * state->getIntermediate(indexIds[i]).Int(0);
1193 }
1194 typeId = type.element;
1195 break;
Chris Forbesa16238d2019-04-18 16:31:54 -07001196 }
Ben Claytonbc1c0672019-12-17 20:37:37 +00001197 default:
1198 UNREACHABLE("%s", OpcodeName(type.definition.opcode()).c_str());
Ben Clayton60f15ec2019-05-09 17:50:01 +01001199 }
1200 }
1201
Nicolas Capens157ba262019-12-10 17:49:14 -05001202 ptr += constantOffset;
1203 return ptr;
1204}
Ben Clayton59cd59b2019-06-25 19:07:48 +01001205
Nicolas Capens157ba262019-12-10 17:49:14 -05001206SIMD::Pointer SpirvShader::WalkAccessChain(Object::ID baseId, uint32_t numIndexes, uint32_t const *indexIds, EmitState const *state) const
1207{
1208 // TODO: avoid doing per-lane work in some cases if we can?
1209 auto routine = state->routine;
1210 auto &baseObject = getObject(baseId);
Nicolas Capens72f089c2020-04-08 23:37:08 -04001211 Type::ID typeId = getType(baseObject).element;
Nicolas Capens157ba262019-12-10 17:49:14 -05001212
1213 auto ptr = state->getPointer(baseId);
1214
1215 int constantOffset = 0;
1216
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001217 for(auto i = 0u; i < numIndexes; i++)
Ben Clayton76e9bc02019-02-26 15:02:18 +00001218 {
Ben Claytonbc1c0672019-12-17 20:37:37 +00001219 auto &type = getType(typeId);
Nicolas Capens157ba262019-12-10 17:49:14 -05001220 switch(type.opcode())
1221 {
Ben Claytonbc1c0672019-12-17 20:37:37 +00001222 case spv::OpTypeStruct:
Nicolas Capens157ba262019-12-10 17:49:14 -05001223 {
Ben Claytonbc1c0672019-12-17 20:37:37 +00001224 int memberIndex = GetConstScalarInt(indexIds[i]);
1225 int offsetIntoStruct = 0;
1226 for(auto j = 0; j < memberIndex; j++)
Nicolas Capens157ba262019-12-10 17:49:14 -05001227 {
Ben Claytonbc1c0672019-12-17 20:37:37 +00001228 auto memberType = type.definition.word(2u + j);
Nicolas Capensff9f9b52020-04-14 00:46:38 -04001229 offsetIntoStruct += getType(memberType).componentCount * sizeof(float);
Nicolas Capens157ba262019-12-10 17:49:14 -05001230 }
Ben Claytonbc1c0672019-12-17 20:37:37 +00001231 constantOffset += offsetIntoStruct;
1232 typeId = type.definition.word(2u + memberIndex);
1233 break;
Nicolas Capens157ba262019-12-10 17:49:14 -05001234 }
Ben Claytonbc1c0672019-12-17 20:37:37 +00001235
1236 case spv::OpTypeVector:
1237 case spv::OpTypeMatrix:
1238 case spv::OpTypeArray:
1239 case spv::OpTypeRuntimeArray:
Nicolas Capens157ba262019-12-10 17:49:14 -05001240 {
Nicolas Capens479d1432020-01-31 11:19:21 -05001241 // TODO(b/127950082): Check bounds.
Nicolas Capens72f089c2020-04-08 23:37:08 -04001242 if(getType(baseObject).storageClass == spv::StorageClassUniformConstant)
Nicolas Capens157ba262019-12-10 17:49:14 -05001243 {
Ben Claytonbc1c0672019-12-17 20:37:37 +00001244 // indexing into an array of descriptors.
Ben Claytonbc1c0672019-12-17 20:37:37 +00001245 auto d = descriptorDecorations.at(baseId);
1246 ASSERT(d.DescriptorSet >= 0);
1247 ASSERT(d.Binding >= 0);
Nicolas Capensc7d5ec32020-04-22 01:11:37 -04001248 uint32_t descriptorSize = routine->pipelineLayout->getDescriptorSize(d.DescriptorSet, d.Binding);
Nicolas Capens479d1432020-01-31 11:19:21 -05001249
1250 auto &obj = getObject(indexIds[i]);
1251 if(obj.kind == Object::Kind::Constant)
1252 {
1253 ptr.base += descriptorSize * GetConstScalarInt(indexIds[i]);
1254 }
1255 else
1256 {
1257 // Note: the value of indexIds[i] must be dynamically uniform.
1258 ptr.base += descriptorSize * Extract(state->getIntermediate(indexIds[i]).Int(0), 0);
1259 }
Nicolas Capens157ba262019-12-10 17:49:14 -05001260 }
1261 else
1262 {
Nicolas Capensff9f9b52020-04-14 00:46:38 -04001263 auto stride = getType(type.element).componentCount * static_cast<uint32_t>(sizeof(float));
Ben Claytonbc1c0672019-12-17 20:37:37 +00001264 auto &obj = getObject(indexIds[i]);
1265 if(obj.kind == Object::Kind::Constant)
1266 {
1267 ptr += stride * GetConstScalarInt(indexIds[i]);
1268 }
1269 else
1270 {
1271 ptr += SIMD::Int(stride) * state->getIntermediate(indexIds[i]).Int(0);
1272 }
Nicolas Capens157ba262019-12-10 17:49:14 -05001273 }
Ben Claytonbc1c0672019-12-17 20:37:37 +00001274 typeId = type.element;
1275 break;
Nicolas Capens157ba262019-12-10 17:49:14 -05001276 }
Nicolas Capens157ba262019-12-10 17:49:14 -05001277
Ben Claytonbc1c0672019-12-17 20:37:37 +00001278 default:
1279 UNREACHABLE("%s", OpcodeName(type.opcode()).c_str());
Nicolas Capens157ba262019-12-10 17:49:14 -05001280 }
Ben Clayton76e9bc02019-02-26 15:02:18 +00001281 }
1282
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001283 if(constantOffset != 0)
Ben Clayton30ee92e2019-08-13 14:21:44 +01001284 {
Nicolas Capens157ba262019-12-10 17:49:14 -05001285 ptr += constantOffset;
1286 }
1287 return ptr;
1288}
Ben Clayton30ee92e2019-08-13 14:21:44 +01001289
Nicolas Capens157ba262019-12-10 17:49:14 -05001290uint32_t SpirvShader::WalkLiteralAccessChain(Type::ID typeId, uint32_t numIndexes, uint32_t const *indexes) const
1291{
1292 uint32_t componentOffset = 0;
Ben Clayton30ee92e2019-08-13 14:21:44 +01001293
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001294 for(auto i = 0u; i < numIndexes; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05001295 {
Ben Claytonbc1c0672019-12-17 20:37:37 +00001296 auto &type = getType(typeId);
Nicolas Capens157ba262019-12-10 17:49:14 -05001297 switch(type.opcode())
Ben Clayton30ee92e2019-08-13 14:21:44 +01001298 {
Ben Claytonbc1c0672019-12-17 20:37:37 +00001299 case spv::OpTypeStruct:
1300 {
1301 int memberIndex = indexes[i];
1302 int offsetIntoStruct = 0;
1303 for(auto j = 0; j < memberIndex; j++)
1304 {
1305 auto memberType = type.definition.word(2u + j);
Nicolas Capensff9f9b52020-04-14 00:46:38 -04001306 offsetIntoStruct += getType(memberType).componentCount;
Ben Claytonbc1c0672019-12-17 20:37:37 +00001307 }
1308 componentOffset += offsetIntoStruct;
1309 typeId = type.definition.word(2u + memberIndex);
1310 break;
Nicolas Capens157ba262019-12-10 17:49:14 -05001311 }
Ben Clayton30ee92e2019-08-13 14:21:44 +01001312
Ben Claytonbc1c0672019-12-17 20:37:37 +00001313 case spv::OpTypeVector:
1314 case spv::OpTypeMatrix:
1315 case spv::OpTypeArray:
1316 {
1317 auto elementType = type.definition.word(2);
Nicolas Capensff9f9b52020-04-14 00:46:38 -04001318 auto stride = getType(elementType).componentCount;
Ben Claytonbc1c0672019-12-17 20:37:37 +00001319 componentOffset += stride * indexes[i];
1320 typeId = elementType;
1321 break;
1322 }
Ben Clayton30ee92e2019-08-13 14:21:44 +01001323
Ben Claytonbc1c0672019-12-17 20:37:37 +00001324 default:
1325 UNREACHABLE("%s", OpcodeName(type.opcode()).c_str());
Nicolas Capens157ba262019-12-10 17:49:14 -05001326 }
1327 }
Ben Clayton30ee92e2019-08-13 14:21:44 +01001328
Nicolas Capens157ba262019-12-10 17:49:14 -05001329 return componentOffset;
1330}
Ben Clayton30ee92e2019-08-13 14:21:44 +01001331
Nicolas Capens157ba262019-12-10 17:49:14 -05001332void SpirvShader::Decorations::Apply(spv::Decoration decoration, uint32_t arg)
1333{
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001334 switch(decoration)
Nicolas Capens157ba262019-12-10 17:49:14 -05001335 {
Ben Claytonbc1c0672019-12-17 20:37:37 +00001336 case spv::DecorationLocation:
1337 HasLocation = true;
1338 Location = static_cast<int32_t>(arg);
1339 break;
1340 case spv::DecorationComponent:
1341 HasComponent = true;
1342 Component = arg;
1343 break;
1344 case spv::DecorationBuiltIn:
1345 HasBuiltIn = true;
1346 BuiltIn = static_cast<spv::BuiltIn>(arg);
1347 break;
1348 case spv::DecorationFlat:
1349 Flat = true;
1350 break;
1351 case spv::DecorationNoPerspective:
1352 NoPerspective = true;
1353 break;
1354 case spv::DecorationCentroid:
1355 Centroid = true;
1356 break;
1357 case spv::DecorationBlock:
1358 Block = true;
1359 break;
1360 case spv::DecorationBufferBlock:
1361 BufferBlock = true;
1362 break;
1363 case spv::DecorationOffset:
1364 HasOffset = true;
1365 Offset = static_cast<int32_t>(arg);
1366 break;
1367 case spv::DecorationArrayStride:
1368 HasArrayStride = true;
1369 ArrayStride = static_cast<int32_t>(arg);
1370 break;
1371 case spv::DecorationMatrixStride:
1372 HasMatrixStride = true;
1373 MatrixStride = static_cast<int32_t>(arg);
1374 break;
1375 case spv::DecorationRelaxedPrecision:
1376 RelaxedPrecision = true;
1377 break;
1378 case spv::DecorationRowMajor:
1379 HasRowMajor = true;
1380 RowMajor = true;
1381 break;
1382 case spv::DecorationColMajor:
1383 HasRowMajor = true;
1384 RowMajor = false;
1385 default:
1386 // Intentionally partial, there are many decorations we just don't care about.
1387 break;
Ben Clayton30ee92e2019-08-13 14:21:44 +01001388 }
Chris Forbesc25b8072018-12-10 15:10:39 -08001389}
Nicolas Capens157ba262019-12-10 17:49:14 -05001390
1391void SpirvShader::Decorations::Apply(const sw::SpirvShader::Decorations &src)
1392{
1393 // Apply a decoration group to this set of decorations
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001394 if(src.HasBuiltIn)
Nicolas Capens157ba262019-12-10 17:49:14 -05001395 {
1396 HasBuiltIn = true;
1397 BuiltIn = src.BuiltIn;
1398 }
1399
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001400 if(src.HasLocation)
Nicolas Capens157ba262019-12-10 17:49:14 -05001401 {
1402 HasLocation = true;
1403 Location = src.Location;
1404 }
1405
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001406 if(src.HasComponent)
Nicolas Capens157ba262019-12-10 17:49:14 -05001407 {
1408 HasComponent = true;
1409 Component = src.Component;
1410 }
1411
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001412 if(src.HasOffset)
Nicolas Capens157ba262019-12-10 17:49:14 -05001413 {
1414 HasOffset = true;
1415 Offset = src.Offset;
1416 }
1417
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001418 if(src.HasArrayStride)
Nicolas Capens157ba262019-12-10 17:49:14 -05001419 {
1420 HasArrayStride = true;
1421 ArrayStride = src.ArrayStride;
1422 }
1423
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001424 if(src.HasMatrixStride)
Nicolas Capens157ba262019-12-10 17:49:14 -05001425 {
1426 HasMatrixStride = true;
1427 MatrixStride = src.MatrixStride;
1428 }
1429
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001430 if(src.HasRowMajor)
Nicolas Capens157ba262019-12-10 17:49:14 -05001431 {
1432 HasRowMajor = true;
1433 RowMajor = src.RowMajor;
1434 }
1435
1436 Flat |= src.Flat;
1437 NoPerspective |= src.NoPerspective;
1438 Centroid |= src.Centroid;
1439 Block |= src.Block;
1440 BufferBlock |= src.BufferBlock;
1441 RelaxedPrecision |= src.RelaxedPrecision;
1442 InsideMatrix |= src.InsideMatrix;
1443}
1444
1445void SpirvShader::DescriptorDecorations::Apply(const sw::SpirvShader::DescriptorDecorations &src)
1446{
1447 if(src.DescriptorSet >= 0)
1448 {
1449 DescriptorSet = src.DescriptorSet;
1450 }
1451
1452 if(src.Binding >= 0)
1453 {
1454 Binding = src.Binding;
1455 }
1456
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001457 if(src.InputAttachmentIndex >= 0)
Nicolas Capens157ba262019-12-10 17:49:14 -05001458 {
1459 InputAttachmentIndex = src.InputAttachmentIndex;
1460 }
1461}
1462
1463void SpirvShader::ApplyDecorationsForId(Decorations *d, TypeOrObjectID id) const
1464{
1465 auto it = decorations.find(id);
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001466 if(it != decorations.end())
Nicolas Capens157ba262019-12-10 17:49:14 -05001467 d->Apply(it->second);
1468}
1469
1470void SpirvShader::ApplyDecorationsForIdMember(Decorations *d, Type::ID id, uint32_t member) const
1471{
1472 auto it = memberDecorations.find(id);
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001473 if(it != memberDecorations.end() && member < it->second.size())
Nicolas Capens157ba262019-12-10 17:49:14 -05001474 {
1475 d->Apply(it->second[member]);
1476 }
1477}
1478
1479void SpirvShader::DefineResult(const InsnIterator &insn)
1480{
1481 Type::ID typeId = insn.word(1);
1482 Object::ID resultId = insn.word(2);
1483 auto &object = defs[resultId];
Nicolas Capens157ba262019-12-10 17:49:14 -05001484
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001485 switch(getType(typeId).opcode())
Nicolas Capens157ba262019-12-10 17:49:14 -05001486 {
Ben Claytonbc1c0672019-12-17 20:37:37 +00001487 case spv::OpTypePointer:
1488 case spv::OpTypeImage:
1489 case spv::OpTypeSampledImage:
1490 case spv::OpTypeSampler:
1491 object.kind = Object::Kind::Pointer;
1492 break;
Nicolas Capens157ba262019-12-10 17:49:14 -05001493
Ben Claytonbc1c0672019-12-17 20:37:37 +00001494 default:
1495 object.kind = Object::Kind::Intermediate;
Nicolas Capens157ba262019-12-10 17:49:14 -05001496 }
1497
1498 object.definition = insn;
Ben Claytonb0ca2a82020-01-08 13:00:57 +00001499 dbgDeclareResult(insn, resultId);
Nicolas Capens157ba262019-12-10 17:49:14 -05001500}
1501
1502OutOfBoundsBehavior SpirvShader::EmitState::getOutOfBoundsBehavior(spv::StorageClass storageClass) const
1503{
1504 switch(storageClass)
1505 {
Ben Claytonbc1c0672019-12-17 20:37:37 +00001506 case spv::StorageClassUniform:
1507 case spv::StorageClassStorageBuffer:
1508 // Buffer resource access. robustBufferAccess feature applies.
Nicolas Capens157ba262019-12-10 17:49:14 -05001509 return robustBufferAccess ? OutOfBoundsBehavior::RobustBufferAccess
1510 : OutOfBoundsBehavior::UndefinedBehavior;
Ben Claytonbc1c0672019-12-17 20:37:37 +00001511
1512 case spv::StorageClassImage:
1513 return OutOfBoundsBehavior::UndefinedValue; // "The value returned by a read of an invalid texel is undefined"
1514
1515 case spv::StorageClassInput:
1516 if(executionModel == spv::ExecutionModelVertex)
1517 {
1518 // Vertex attributes follow robustBufferAccess rules.
1519 return robustBufferAccess ? OutOfBoundsBehavior::RobustBufferAccess
1520 : OutOfBoundsBehavior::UndefinedBehavior;
1521 }
1522 // Fall through to default case.
1523 default:
1524 // TODO(b/137183137): Optimize if the pointer resulted from OpInBoundsAccessChain.
1525 // TODO(b/131224163): Optimize cases statically known to be within bounds.
1526 return OutOfBoundsBehavior::UndefinedValue;
Nicolas Capens157ba262019-12-10 17:49:14 -05001527 }
1528
1529 return OutOfBoundsBehavior::Nullify;
1530}
1531
1532// emit-time
1533
1534void SpirvShader::emitProlog(SpirvRoutine *routine) const
1535{
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001536 for(auto insn : *this)
Nicolas Capens157ba262019-12-10 17:49:14 -05001537 {
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001538 switch(insn.opcode())
Nicolas Capens157ba262019-12-10 17:49:14 -05001539 {
Ben Claytonbc1c0672019-12-17 20:37:37 +00001540 case spv::OpVariable:
1541 {
Nicolas Capens71186752020-04-09 01:05:31 -04001542 auto resultPointerType = getType(insn.resultTypeId());
Ben Claytonbc1c0672019-12-17 20:37:37 +00001543 auto pointeeType = getType(resultPointerType.element);
Nicolas Capens157ba262019-12-10 17:49:14 -05001544
Nicolas Capensff9f9b52020-04-14 00:46:38 -04001545 if(pointeeType.componentCount > 0) // TODO: what to do about zero-slot objects?
Ben Claytonbc1c0672019-12-17 20:37:37 +00001546 {
Nicolas Capensff9f9b52020-04-14 00:46:38 -04001547 routine->createVariable(insn.resultId(), pointeeType.componentCount);
Ben Claytonbc1c0672019-12-17 20:37:37 +00001548 }
1549 break;
1550 }
1551 case spv::OpPhi:
1552 {
Nicolas Capens71186752020-04-09 01:05:31 -04001553 auto type = getType(insn.resultTypeId());
Nicolas Capensff9f9b52020-04-14 00:46:38 -04001554 routine->phis.emplace(insn.resultId(), SpirvRoutine::Variable(type.componentCount));
Ben Claytonbc1c0672019-12-17 20:37:37 +00001555 break;
1556 }
1557
1558 case spv::OpImageDrefGather:
1559 case spv::OpImageFetch:
1560 case spv::OpImageGather:
1561 case spv::OpImageQueryLod:
1562 case spv::OpImageSampleDrefExplicitLod:
1563 case spv::OpImageSampleDrefImplicitLod:
1564 case spv::OpImageSampleExplicitLod:
1565 case spv::OpImageSampleImplicitLod:
1566 case spv::OpImageSampleProjDrefExplicitLod:
1567 case spv::OpImageSampleProjDrefImplicitLod:
1568 case spv::OpImageSampleProjExplicitLod:
1569 case spv::OpImageSampleProjImplicitLod:
Nicolas Capens71186752020-04-09 01:05:31 -04001570 routine->samplerCache.emplace(insn.resultId(), SpirvRoutine::SamplerCache{});
Ben Claytonbc1c0672019-12-17 20:37:37 +00001571 break;
Nicolas Capens157ba262019-12-10 17:49:14 -05001572
Ben Claytonbc1c0672019-12-17 20:37:37 +00001573 default:
1574 // Nothing else produces interface variables, so can all be safely ignored.
1575 break;
Nicolas Capens157ba262019-12-10 17:49:14 -05001576 }
1577 }
1578}
1579
1580void SpirvShader::emit(SpirvRoutine *routine, RValue<SIMD::Int> const &activeLaneMask, RValue<SIMD::Int> const &storesAndAtomicsMask, const vk::DescriptorSet::Bindings &descriptorSets) const
1581{
1582 EmitState state(routine, entryPoint, activeLaneMask, storesAndAtomicsMask, descriptorSets, robustBufferAccess, executionModel);
1583
Ben Claytonb0ca2a82020-01-08 13:00:57 +00001584 dbgBeginEmit(&state);
1585 defer(dbgEndEmit(&state));
1586
Nicolas Capens157ba262019-12-10 17:49:14 -05001587 // Emit everything up to the first label
1588 // TODO: Separate out dispatch of block from non-block instructions?
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001589 for(auto insn : *this)
Nicolas Capens157ba262019-12-10 17:49:14 -05001590 {
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001591 if(insn.opcode() == spv::OpLabel)
Nicolas Capens157ba262019-12-10 17:49:14 -05001592 {
1593 break;
1594 }
1595 EmitInstruction(insn, &state);
1596 }
1597
1598 // Emit all the blocks starting from entryPoint.
1599 EmitBlocks(getFunction(entryPoint).entry, &state);
1600}
1601
1602void SpirvShader::EmitInstructions(InsnIterator begin, InsnIterator end, EmitState *state) const
1603{
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001604 for(auto insn = begin; insn != end; insn++)
Nicolas Capens157ba262019-12-10 17:49:14 -05001605 {
1606 auto res = EmitInstruction(insn, state);
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001607 switch(res)
Nicolas Capens157ba262019-12-10 17:49:14 -05001608 {
Ben Claytonbc1c0672019-12-17 20:37:37 +00001609 case EmitResult::Continue:
1610 continue;
1611 case EmitResult::Terminator:
1612 break;
1613 default:
1614 UNREACHABLE("Unexpected EmitResult %d", int(res));
1615 break;
Nicolas Capens157ba262019-12-10 17:49:14 -05001616 }
1617 }
1618}
1619
1620SpirvShader::EmitResult SpirvShader::EmitInstruction(InsnIterator insn, EmitState *state) const
1621{
Ben Claytonb0ca2a82020-01-08 13:00:57 +00001622 dbgBeginEmitInstruction(insn, state);
1623 defer(dbgEndEmitInstruction(insn, state));
1624
Nicolas Capens157ba262019-12-10 17:49:14 -05001625 auto opcode = insn.opcode();
1626
Ben Claytonfc951cd2019-05-15 17:16:56 +01001627#if SPIRV_SHADER_ENABLE_DBG
1628 {
1629 auto text = spvtools::spvInstructionBinaryToText(
1630 SPV_ENV_VULKAN_1_1,
1631 insn.wordPointer(0),
1632 insn.wordCount(),
1633 insns.data(),
1634 insns.size(),
1635 SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
1636 SPIRV_SHADER_DBG("{0}", text);
1637 }
1638#endif // ENABLE_DBG_MSGS
1639
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001640 switch(opcode)
Nicolas Capens157ba262019-12-10 17:49:14 -05001641 {
Ben Claytonbc1c0672019-12-17 20:37:37 +00001642 case spv::OpTypeVoid:
1643 case spv::OpTypeInt:
1644 case spv::OpTypeFloat:
1645 case spv::OpTypeBool:
1646 case spv::OpTypeVector:
1647 case spv::OpTypeArray:
1648 case spv::OpTypeRuntimeArray:
1649 case spv::OpTypeMatrix:
1650 case spv::OpTypeStruct:
1651 case spv::OpTypePointer:
1652 case spv::OpTypeFunction:
1653 case spv::OpTypeImage:
1654 case spv::OpTypeSampledImage:
1655 case spv::OpTypeSampler:
1656 case spv::OpExecutionMode:
1657 case spv::OpMemoryModel:
1658 case spv::OpFunction:
1659 case spv::OpFunctionEnd:
1660 case spv::OpConstant:
1661 case spv::OpConstantNull:
1662 case spv::OpConstantTrue:
1663 case spv::OpConstantFalse:
1664 case spv::OpConstantComposite:
1665 case spv::OpSpecConstant:
1666 case spv::OpSpecConstantTrue:
1667 case spv::OpSpecConstantFalse:
1668 case spv::OpSpecConstantComposite:
1669 case spv::OpSpecConstantOp:
1670 case spv::OpUndef:
1671 case spv::OpExtension:
1672 case spv::OpCapability:
1673 case spv::OpEntryPoint:
1674 case spv::OpExtInstImport:
1675 case spv::OpDecorate:
1676 case spv::OpMemberDecorate:
1677 case spv::OpGroupDecorate:
1678 case spv::OpGroupMemberDecorate:
1679 case spv::OpDecorationGroup:
1680 case spv::OpName:
1681 case spv::OpMemberName:
1682 case spv::OpSource:
1683 case spv::OpSourceContinued:
1684 case spv::OpSourceExtension:
Ben Claytonbc1c0672019-12-17 20:37:37 +00001685 case spv::OpNoLine:
1686 case spv::OpModuleProcessed:
1687 case spv::OpString:
1688 // Nothing to do at emit time. These are either fully handled at analysis time,
1689 // or don't require any work at all.
1690 return EmitResult::Continue;
Nicolas Capens157ba262019-12-10 17:49:14 -05001691
Ben Claytonb0ca2a82020-01-08 13:00:57 +00001692 case spv::OpLine:
1693 return EmitLine(insn, state);
1694
Ben Claytonbc1c0672019-12-17 20:37:37 +00001695 case spv::OpLabel:
1696 return EmitResult::Continue;
Nicolas Capens157ba262019-12-10 17:49:14 -05001697
Ben Claytonbc1c0672019-12-17 20:37:37 +00001698 case spv::OpVariable:
1699 return EmitVariable(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001700
Ben Claytonbc1c0672019-12-17 20:37:37 +00001701 case spv::OpLoad:
1702 case spv::OpAtomicLoad:
1703 return EmitLoad(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001704
Ben Claytonbc1c0672019-12-17 20:37:37 +00001705 case spv::OpStore:
1706 case spv::OpAtomicStore:
1707 return EmitStore(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001708
Ben Claytonbc1c0672019-12-17 20:37:37 +00001709 case spv::OpAtomicIAdd:
1710 case spv::OpAtomicISub:
1711 case spv::OpAtomicSMin:
1712 case spv::OpAtomicSMax:
1713 case spv::OpAtomicUMin:
1714 case spv::OpAtomicUMax:
1715 case spv::OpAtomicAnd:
1716 case spv::OpAtomicOr:
1717 case spv::OpAtomicXor:
1718 case spv::OpAtomicIIncrement:
1719 case spv::OpAtomicIDecrement:
1720 case spv::OpAtomicExchange:
1721 return EmitAtomicOp(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001722
Ben Claytonbc1c0672019-12-17 20:37:37 +00001723 case spv::OpAtomicCompareExchange:
1724 return EmitAtomicCompareExchange(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001725
Ben Claytonbc1c0672019-12-17 20:37:37 +00001726 case spv::OpAccessChain:
1727 case spv::OpInBoundsAccessChain:
1728 return EmitAccessChain(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001729
Ben Claytonbc1c0672019-12-17 20:37:37 +00001730 case spv::OpCompositeConstruct:
1731 return EmitCompositeConstruct(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001732
Ben Claytonbc1c0672019-12-17 20:37:37 +00001733 case spv::OpCompositeInsert:
1734 return EmitCompositeInsert(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001735
Ben Claytonbc1c0672019-12-17 20:37:37 +00001736 case spv::OpCompositeExtract:
1737 return EmitCompositeExtract(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001738
Ben Claytonbc1c0672019-12-17 20:37:37 +00001739 case spv::OpVectorShuffle:
1740 return EmitVectorShuffle(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001741
Ben Claytonbc1c0672019-12-17 20:37:37 +00001742 case spv::OpVectorExtractDynamic:
1743 return EmitVectorExtractDynamic(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001744
Ben Claytonbc1c0672019-12-17 20:37:37 +00001745 case spv::OpVectorInsertDynamic:
1746 return EmitVectorInsertDynamic(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001747
Ben Claytonbc1c0672019-12-17 20:37:37 +00001748 case spv::OpVectorTimesScalar:
1749 case spv::OpMatrixTimesScalar:
1750 return EmitVectorTimesScalar(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001751
Ben Claytonbc1c0672019-12-17 20:37:37 +00001752 case spv::OpMatrixTimesVector:
1753 return EmitMatrixTimesVector(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001754
Ben Claytonbc1c0672019-12-17 20:37:37 +00001755 case spv::OpVectorTimesMatrix:
1756 return EmitVectorTimesMatrix(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001757
Ben Claytonbc1c0672019-12-17 20:37:37 +00001758 case spv::OpMatrixTimesMatrix:
1759 return EmitMatrixTimesMatrix(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001760
Ben Claytonbc1c0672019-12-17 20:37:37 +00001761 case spv::OpOuterProduct:
1762 return EmitOuterProduct(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001763
Ben Claytonbc1c0672019-12-17 20:37:37 +00001764 case spv::OpTranspose:
1765 return EmitTranspose(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001766
Ben Claytonbc1c0672019-12-17 20:37:37 +00001767 case spv::OpNot:
1768 case spv::OpBitFieldInsert:
1769 case spv::OpBitFieldSExtract:
1770 case spv::OpBitFieldUExtract:
1771 case spv::OpBitReverse:
1772 case spv::OpBitCount:
1773 case spv::OpSNegate:
1774 case spv::OpFNegate:
1775 case spv::OpLogicalNot:
1776 case spv::OpConvertFToU:
1777 case spv::OpConvertFToS:
1778 case spv::OpConvertSToF:
1779 case spv::OpConvertUToF:
1780 case spv::OpBitcast:
1781 case spv::OpIsInf:
1782 case spv::OpIsNan:
1783 case spv::OpDPdx:
1784 case spv::OpDPdxCoarse:
1785 case spv::OpDPdy:
1786 case spv::OpDPdyCoarse:
1787 case spv::OpFwidth:
1788 case spv::OpFwidthCoarse:
1789 case spv::OpDPdxFine:
1790 case spv::OpDPdyFine:
1791 case spv::OpFwidthFine:
1792 case spv::OpQuantizeToF16:
1793 return EmitUnaryOp(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001794
Ben Claytonbc1c0672019-12-17 20:37:37 +00001795 case spv::OpIAdd:
1796 case spv::OpISub:
1797 case spv::OpIMul:
1798 case spv::OpSDiv:
1799 case spv::OpUDiv:
1800 case spv::OpFAdd:
1801 case spv::OpFSub:
1802 case spv::OpFMul:
1803 case spv::OpFDiv:
1804 case spv::OpFMod:
1805 case spv::OpFRem:
1806 case spv::OpFOrdEqual:
1807 case spv::OpFUnordEqual:
1808 case spv::OpFOrdNotEqual:
1809 case spv::OpFUnordNotEqual:
1810 case spv::OpFOrdLessThan:
1811 case spv::OpFUnordLessThan:
1812 case spv::OpFOrdGreaterThan:
1813 case spv::OpFUnordGreaterThan:
1814 case spv::OpFOrdLessThanEqual:
1815 case spv::OpFUnordLessThanEqual:
1816 case spv::OpFOrdGreaterThanEqual:
1817 case spv::OpFUnordGreaterThanEqual:
1818 case spv::OpSMod:
1819 case spv::OpSRem:
1820 case spv::OpUMod:
1821 case spv::OpIEqual:
1822 case spv::OpINotEqual:
1823 case spv::OpUGreaterThan:
1824 case spv::OpSGreaterThan:
1825 case spv::OpUGreaterThanEqual:
1826 case spv::OpSGreaterThanEqual:
1827 case spv::OpULessThan:
1828 case spv::OpSLessThan:
1829 case spv::OpULessThanEqual:
1830 case spv::OpSLessThanEqual:
1831 case spv::OpShiftRightLogical:
1832 case spv::OpShiftRightArithmetic:
1833 case spv::OpShiftLeftLogical:
1834 case spv::OpBitwiseOr:
1835 case spv::OpBitwiseXor:
1836 case spv::OpBitwiseAnd:
1837 case spv::OpLogicalOr:
1838 case spv::OpLogicalAnd:
1839 case spv::OpLogicalEqual:
1840 case spv::OpLogicalNotEqual:
1841 case spv::OpUMulExtended:
1842 case spv::OpSMulExtended:
1843 case spv::OpIAddCarry:
1844 case spv::OpISubBorrow:
1845 return EmitBinaryOp(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001846
Ben Claytonbc1c0672019-12-17 20:37:37 +00001847 case spv::OpDot:
1848 return EmitDot(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001849
Ben Claytonbc1c0672019-12-17 20:37:37 +00001850 case spv::OpSelect:
1851 return EmitSelect(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001852
Ben Claytonbc1c0672019-12-17 20:37:37 +00001853 case spv::OpExtInst:
1854 return EmitExtendedInstruction(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001855
Ben Claytonbc1c0672019-12-17 20:37:37 +00001856 case spv::OpAny:
1857 return EmitAny(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001858
Ben Claytonbc1c0672019-12-17 20:37:37 +00001859 case spv::OpAll:
1860 return EmitAll(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001861
Ben Claytonbc1c0672019-12-17 20:37:37 +00001862 case spv::OpBranch:
1863 return EmitBranch(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001864
Ben Claytonbc1c0672019-12-17 20:37:37 +00001865 case spv::OpPhi:
1866 return EmitPhi(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001867
Ben Claytonbc1c0672019-12-17 20:37:37 +00001868 case spv::OpSelectionMerge:
1869 case spv::OpLoopMerge:
1870 return EmitResult::Continue;
Nicolas Capens157ba262019-12-10 17:49:14 -05001871
Ben Claytonbc1c0672019-12-17 20:37:37 +00001872 case spv::OpBranchConditional:
1873 return EmitBranchConditional(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001874
Ben Claytonbc1c0672019-12-17 20:37:37 +00001875 case spv::OpSwitch:
1876 return EmitSwitch(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001877
Ben Claytonbc1c0672019-12-17 20:37:37 +00001878 case spv::OpUnreachable:
1879 return EmitUnreachable(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001880
Ben Claytonbc1c0672019-12-17 20:37:37 +00001881 case spv::OpReturn:
1882 return EmitReturn(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001883
Ben Claytonbc1c0672019-12-17 20:37:37 +00001884 case spv::OpFunctionCall:
1885 return EmitFunctionCall(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001886
Ben Claytonbc1c0672019-12-17 20:37:37 +00001887 case spv::OpKill:
1888 return EmitKill(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001889
Ben Claytonbc1c0672019-12-17 20:37:37 +00001890 case spv::OpImageSampleImplicitLod:
1891 return EmitImageSampleImplicitLod(None, insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001892
Ben Claytonbc1c0672019-12-17 20:37:37 +00001893 case spv::OpImageSampleExplicitLod:
1894 return EmitImageSampleExplicitLod(None, insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001895
Ben Claytonbc1c0672019-12-17 20:37:37 +00001896 case spv::OpImageSampleDrefImplicitLod:
1897 return EmitImageSampleImplicitLod(Dref, insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001898
Ben Claytonbc1c0672019-12-17 20:37:37 +00001899 case spv::OpImageSampleDrefExplicitLod:
1900 return EmitImageSampleExplicitLod(Dref, insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001901
Ben Claytonbc1c0672019-12-17 20:37:37 +00001902 case spv::OpImageSampleProjImplicitLod:
1903 return EmitImageSampleImplicitLod(Proj, insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001904
Ben Claytonbc1c0672019-12-17 20:37:37 +00001905 case spv::OpImageSampleProjExplicitLod:
1906 return EmitImageSampleExplicitLod(Proj, insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001907
Ben Claytonbc1c0672019-12-17 20:37:37 +00001908 case spv::OpImageSampleProjDrefImplicitLod:
1909 return EmitImageSampleImplicitLod(ProjDref, insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001910
Ben Claytonbc1c0672019-12-17 20:37:37 +00001911 case spv::OpImageSampleProjDrefExplicitLod:
1912 return EmitImageSampleExplicitLod(ProjDref, insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001913
Ben Claytonbc1c0672019-12-17 20:37:37 +00001914 case spv::OpImageGather:
1915 return EmitImageGather(None, insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001916
Ben Claytonbc1c0672019-12-17 20:37:37 +00001917 case spv::OpImageDrefGather:
1918 return EmitImageGather(Dref, insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001919
Ben Claytonbc1c0672019-12-17 20:37:37 +00001920 case spv::OpImageFetch:
1921 return EmitImageFetch(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001922
Ben Claytonbc1c0672019-12-17 20:37:37 +00001923 case spv::OpImageQuerySizeLod:
1924 return EmitImageQuerySizeLod(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001925
Ben Claytonbc1c0672019-12-17 20:37:37 +00001926 case spv::OpImageQuerySize:
1927 return EmitImageQuerySize(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001928
Ben Claytonbc1c0672019-12-17 20:37:37 +00001929 case spv::OpImageQueryLod:
1930 return EmitImageQueryLod(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001931
Ben Claytonbc1c0672019-12-17 20:37:37 +00001932 case spv::OpImageQueryLevels:
1933 return EmitImageQueryLevels(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001934
Ben Claytonbc1c0672019-12-17 20:37:37 +00001935 case spv::OpImageQuerySamples:
1936 return EmitImageQuerySamples(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001937
Ben Claytonbc1c0672019-12-17 20:37:37 +00001938 case spv::OpImageRead:
1939 return EmitImageRead(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001940
Ben Claytonbc1c0672019-12-17 20:37:37 +00001941 case spv::OpImageWrite:
1942 return EmitImageWrite(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001943
Ben Claytonbc1c0672019-12-17 20:37:37 +00001944 case spv::OpImageTexelPointer:
1945 return EmitImageTexelPointer(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001946
Ben Claytonbc1c0672019-12-17 20:37:37 +00001947 case spv::OpSampledImage:
1948 case spv::OpImage:
1949 return EmitSampledImageCombineOrSplit(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001950
Ben Claytonbc1c0672019-12-17 20:37:37 +00001951 case spv::OpCopyObject:
1952 return EmitCopyObject(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001953
Ben Claytonbc1c0672019-12-17 20:37:37 +00001954 case spv::OpCopyMemory:
1955 return EmitCopyMemory(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001956
Ben Claytonbc1c0672019-12-17 20:37:37 +00001957 case spv::OpControlBarrier:
1958 return EmitControlBarrier(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001959
Ben Claytonbc1c0672019-12-17 20:37:37 +00001960 case spv::OpMemoryBarrier:
1961 return EmitMemoryBarrier(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001962
Ben Claytonbc1c0672019-12-17 20:37:37 +00001963 case spv::OpGroupNonUniformElect:
1964 case spv::OpGroupNonUniformAll:
1965 case spv::OpGroupNonUniformAny:
1966 case spv::OpGroupNonUniformAllEqual:
1967 case spv::OpGroupNonUniformBroadcast:
1968 case spv::OpGroupNonUniformBroadcastFirst:
1969 case spv::OpGroupNonUniformBallot:
1970 case spv::OpGroupNonUniformInverseBallot:
1971 case spv::OpGroupNonUniformBallotBitExtract:
1972 case spv::OpGroupNonUniformBallotBitCount:
1973 case spv::OpGroupNonUniformBallotFindLSB:
1974 case spv::OpGroupNonUniformBallotFindMSB:
1975 case spv::OpGroupNonUniformShuffle:
1976 case spv::OpGroupNonUniformShuffleXor:
1977 case spv::OpGroupNonUniformShuffleUp:
1978 case spv::OpGroupNonUniformShuffleDown:
1979 case spv::OpGroupNonUniformIAdd:
1980 case spv::OpGroupNonUniformFAdd:
1981 case spv::OpGroupNonUniformIMul:
1982 case spv::OpGroupNonUniformFMul:
1983 case spv::OpGroupNonUniformSMin:
1984 case spv::OpGroupNonUniformUMin:
1985 case spv::OpGroupNonUniformFMin:
1986 case spv::OpGroupNonUniformSMax:
1987 case spv::OpGroupNonUniformUMax:
1988 case spv::OpGroupNonUniformFMax:
1989 case spv::OpGroupNonUniformBitwiseAnd:
1990 case spv::OpGroupNonUniformBitwiseOr:
1991 case spv::OpGroupNonUniformBitwiseXor:
1992 case spv::OpGroupNonUniformLogicalAnd:
1993 case spv::OpGroupNonUniformLogicalOr:
1994 case spv::OpGroupNonUniformLogicalXor:
1995 return EmitGroupNonUniform(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001996
Ben Claytonbc1c0672019-12-17 20:37:37 +00001997 case spv::OpArrayLength:
1998 return EmitArrayLength(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001999
Ben Claytonbc1c0672019-12-17 20:37:37 +00002000 default:
2001 UNREACHABLE("%s", OpcodeName(opcode).c_str());
2002 break;
Nicolas Capens157ba262019-12-10 17:49:14 -05002003 }
2004
2005 return EmitResult::Continue;
2006}
2007
2008SpirvShader::EmitResult SpirvShader::EmitAccessChain(InsnIterator insn, EmitState *state) const
2009{
2010 Type::ID typeId = insn.word(1);
2011 Object::ID resultId = insn.word(2);
2012 Object::ID baseId = insn.word(3);
2013 uint32_t numIndexes = insn.wordCount() - 4;
2014 const uint32_t *indexes = insn.wordPointer(4);
2015 auto &type = getType(typeId);
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002016 ASSERT(type.componentCount == 1);
Nicolas Capens157ba262019-12-10 17:49:14 -05002017 ASSERT(getObject(resultId).kind == Object::Kind::Pointer);
2018
2019 if(type.storageClass == spv::StorageClassPushConstant ||
2020 type.storageClass == spv::StorageClassUniform ||
2021 type.storageClass == spv::StorageClassStorageBuffer)
2022 {
2023 auto ptr = WalkExplicitLayoutAccessChain(baseId, numIndexes, indexes, state);
2024 state->createPointer(resultId, ptr);
2025 }
2026 else
2027 {
2028 auto ptr = WalkAccessChain(baseId, numIndexes, indexes, state);
2029 state->createPointer(resultId, ptr);
2030 }
2031
2032 return EmitResult::Continue;
2033}
2034
2035SpirvShader::EmitResult SpirvShader::EmitCompositeConstruct(InsnIterator insn, EmitState *state) const
2036{
Nicolas Capens71186752020-04-09 01:05:31 -04002037 auto &type = getType(insn.resultTypeId());
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002038 auto &dst = state->createIntermediate(insn.resultId(), type.componentCount);
Nicolas Capens157ba262019-12-10 17:49:14 -05002039 auto offset = 0u;
2040
Nicolas Capens81bc9d92019-12-16 15:05:57 -05002041 for(auto i = 0u; i < insn.wordCount() - 3; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002042 {
2043 Object::ID srcObjectId = insn.word(3u + i);
Ben Claytonbc1c0672019-12-17 20:37:37 +00002044 auto &srcObject = getObject(srcObjectId);
Nicolas Capens72f089c2020-04-08 23:37:08 -04002045 auto &srcObjectTy = getType(srcObject);
Nicolas Capense6f65d92020-04-08 21:55:43 -04002046 Operand srcObjectAccess(this, state, srcObjectId);
Nicolas Capens157ba262019-12-10 17:49:14 -05002047
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002048 for(auto j = 0u; j < srcObjectTy.componentCount; j++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002049 {
2050 dst.move(offset++, srcObjectAccess.Float(j));
2051 }
2052 }
2053
2054 return EmitResult::Continue;
2055}
2056
2057SpirvShader::EmitResult SpirvShader::EmitCompositeInsert(InsnIterator insn, EmitState *state) const
2058{
2059 Type::ID resultTypeId = insn.word(1);
2060 auto &type = getType(resultTypeId);
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002061 auto &dst = state->createIntermediate(insn.resultId(), type.componentCount);
Nicolas Capens157ba262019-12-10 17:49:14 -05002062 auto &newPartObject = getObject(insn.word(3));
Nicolas Capens72f089c2020-04-08 23:37:08 -04002063 auto &newPartObjectTy = getType(newPartObject);
Nicolas Capens157ba262019-12-10 17:49:14 -05002064 auto firstNewComponent = WalkLiteralAccessChain(resultTypeId, insn.wordCount() - 5, insn.wordPointer(5));
2065
Nicolas Capense6f65d92020-04-08 21:55:43 -04002066 Operand srcObjectAccess(this, state, insn.word(4));
2067 Operand newPartObjectAccess(this, state, insn.word(3));
Nicolas Capens157ba262019-12-10 17:49:14 -05002068
2069 // old components before
Nicolas Capens81bc9d92019-12-16 15:05:57 -05002070 for(auto i = 0u; i < firstNewComponent; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002071 {
2072 dst.move(i, srcObjectAccess.Float(i));
2073 }
2074 // new part
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002075 for(auto i = 0u; i < newPartObjectTy.componentCount; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002076 {
2077 dst.move(firstNewComponent + i, newPartObjectAccess.Float(i));
2078 }
2079 // old components after
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002080 for(auto i = firstNewComponent + newPartObjectTy.componentCount; i < type.componentCount; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002081 {
2082 dst.move(i, srcObjectAccess.Float(i));
2083 }
2084
2085 return EmitResult::Continue;
2086}
2087
2088SpirvShader::EmitResult SpirvShader::EmitCompositeExtract(InsnIterator insn, EmitState *state) const
2089{
Nicolas Capens71186752020-04-09 01:05:31 -04002090 auto &type = getType(insn.resultTypeId());
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002091 auto &dst = state->createIntermediate(insn.resultId(), type.componentCount);
Nicolas Capens157ba262019-12-10 17:49:14 -05002092 auto &compositeObject = getObject(insn.word(3));
2093 Type::ID compositeTypeId = compositeObject.definition.word(1);
2094 auto firstComponent = WalkLiteralAccessChain(compositeTypeId, insn.wordCount() - 4, insn.wordPointer(4));
2095
Nicolas Capense6f65d92020-04-08 21:55:43 -04002096 Operand compositeObjectAccess(this, state, insn.word(3));
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002097 for(auto i = 0u; i < type.componentCount; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002098 {
2099 dst.move(i, compositeObjectAccess.Float(firstComponent + i));
2100 }
2101
2102 return EmitResult::Continue;
2103}
2104
2105SpirvShader::EmitResult SpirvShader::EmitVectorShuffle(InsnIterator insn, EmitState *state) const
2106{
Nicolas Capens71186752020-04-09 01:05:31 -04002107 auto &type = getType(insn.resultTypeId());
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002108 auto &dst = state->createIntermediate(insn.resultId(), type.componentCount);
Nicolas Capens157ba262019-12-10 17:49:14 -05002109
2110 // Note: number of components in result type, first half type, and second
2111 // half type are all independent.
Nicolas Capens72f089c2020-04-08 23:37:08 -04002112 auto &firstHalfType = getType(getObject(insn.word(3)));
Nicolas Capens157ba262019-12-10 17:49:14 -05002113
Nicolas Capense6f65d92020-04-08 21:55:43 -04002114 Operand firstHalfAccess(this, state, insn.word(3));
2115 Operand secondHalfAccess(this, state, insn.word(4));
Nicolas Capens157ba262019-12-10 17:49:14 -05002116
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002117 for(auto i = 0u; i < type.componentCount; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002118 {
2119 auto selector = insn.word(5 + i);
Nicolas Capens81bc9d92019-12-16 15:05:57 -05002120 if(selector == static_cast<uint32_t>(-1))
Nicolas Capens157ba262019-12-10 17:49:14 -05002121 {
2122 // Undefined value. Until we decide to do real undef values, zero is as good
2123 // a value as any
2124 dst.move(i, RValue<SIMD::Float>(0.0f));
2125 }
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002126 else if(selector < firstHalfType.componentCount)
Nicolas Capens157ba262019-12-10 17:49:14 -05002127 {
2128 dst.move(i, firstHalfAccess.Float(selector));
2129 }
2130 else
2131 {
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002132 dst.move(i, secondHalfAccess.Float(selector - firstHalfType.componentCount));
Nicolas Capens157ba262019-12-10 17:49:14 -05002133 }
2134 }
2135
2136 return EmitResult::Continue;
2137}
2138
2139SpirvShader::EmitResult SpirvShader::EmitVectorExtractDynamic(InsnIterator insn, EmitState *state) const
2140{
Nicolas Capens71186752020-04-09 01:05:31 -04002141 auto &type = getType(insn.resultTypeId());
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002142 auto &dst = state->createIntermediate(insn.resultId(), type.componentCount);
Nicolas Capens72f089c2020-04-08 23:37:08 -04002143 auto &srcType = getType(getObject(insn.word(3)));
Nicolas Capens157ba262019-12-10 17:49:14 -05002144
Nicolas Capense6f65d92020-04-08 21:55:43 -04002145 Operand src(this, state, insn.word(3));
2146 Operand index(this, state, insn.word(4));
Nicolas Capens157ba262019-12-10 17:49:14 -05002147
2148 SIMD::UInt v = SIMD::UInt(0);
2149
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002150 for(auto i = 0u; i < srcType.componentCount; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002151 {
2152 v |= CmpEQ(index.UInt(0), SIMD::UInt(i)) & src.UInt(i);
2153 }
2154
2155 dst.move(0, v);
2156 return EmitResult::Continue;
2157}
2158
2159SpirvShader::EmitResult SpirvShader::EmitVectorInsertDynamic(InsnIterator insn, EmitState *state) const
2160{
Nicolas Capens71186752020-04-09 01:05:31 -04002161 auto &type = getType(insn.resultTypeId());
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002162 auto &dst = state->createIntermediate(insn.resultId(), type.componentCount);
Nicolas Capens157ba262019-12-10 17:49:14 -05002163
Nicolas Capense6f65d92020-04-08 21:55:43 -04002164 Operand src(this, state, insn.word(3));
2165 Operand component(this, state, insn.word(4));
2166 Operand index(this, state, insn.word(5));
Nicolas Capens157ba262019-12-10 17:49:14 -05002167
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002168 for(auto i = 0u; i < type.componentCount; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002169 {
2170 SIMD::UInt mask = CmpEQ(SIMD::UInt(i), index.UInt(0));
2171 dst.move(i, (src.UInt(i) & ~mask) | (component.UInt(0) & mask));
2172 }
2173 return EmitResult::Continue;
2174}
2175
2176SpirvShader::EmitResult SpirvShader::EmitSelect(InsnIterator insn, EmitState *state) const
2177{
Nicolas Capens71186752020-04-09 01:05:31 -04002178 auto &type = getType(insn.resultTypeId());
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002179 auto &dst = state->createIntermediate(insn.resultId(), type.componentCount);
Nicolas Capense6f65d92020-04-08 21:55:43 -04002180 auto cond = Operand(this, state, insn.word(3));
Nicolas Capens2f4b6032020-04-09 02:01:50 -04002181 auto condIsScalar = (cond.componentCount == 1);
Nicolas Capense6f65d92020-04-08 21:55:43 -04002182 auto lhs = Operand(this, state, insn.word(4));
2183 auto rhs = Operand(this, state, insn.word(5));
Nicolas Capens157ba262019-12-10 17:49:14 -05002184
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002185 for(auto i = 0u; i < type.componentCount; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002186 {
2187 auto sel = cond.Int(condIsScalar ? 0 : i);
Ben Claytonbc1c0672019-12-17 20:37:37 +00002188 dst.move(i, (sel & lhs.Int(i)) | (~sel & rhs.Int(i))); // TODO: IfThenElse()
Nicolas Capens157ba262019-12-10 17:49:14 -05002189 }
2190
Ben Claytonfc951cd2019-05-15 17:16:56 +01002191 SPIRV_SHADER_DBG("{0}: {1}", insn.word(2), dst);
2192 SPIRV_SHADER_DBG("{0}: {1}", insn.word(3), cond);
2193 SPIRV_SHADER_DBG("{0}: {1}", insn.word(4), lhs);
2194 SPIRV_SHADER_DBG("{0}: {1}", insn.word(5), rhs);
2195
Nicolas Capens157ba262019-12-10 17:49:14 -05002196 return EmitResult::Continue;
2197}
2198
2199SpirvShader::EmitResult SpirvShader::EmitAny(InsnIterator insn, EmitState *state) const
2200{
Nicolas Capens71186752020-04-09 01:05:31 -04002201 auto &type = getType(insn.resultTypeId());
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002202 ASSERT(type.componentCount == 1);
2203 auto &dst = state->createIntermediate(insn.resultId(), type.componentCount);
Nicolas Capens72f089c2020-04-08 23:37:08 -04002204 auto &srcType = getType(getObject(insn.word(3)));
Nicolas Capense6f65d92020-04-08 21:55:43 -04002205 auto src = Operand(this, state, insn.word(3));
Nicolas Capens157ba262019-12-10 17:49:14 -05002206
2207 SIMD::UInt result = src.UInt(0);
2208
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002209 for(auto i = 1u; i < srcType.componentCount; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002210 {
2211 result |= src.UInt(i);
2212 }
2213
2214 dst.move(0, result);
2215 return EmitResult::Continue;
2216}
2217
2218SpirvShader::EmitResult SpirvShader::EmitAll(InsnIterator insn, EmitState *state) const
2219{
Nicolas Capens71186752020-04-09 01:05:31 -04002220 auto &type = getType(insn.resultTypeId());
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002221 ASSERT(type.componentCount == 1);
2222 auto &dst = state->createIntermediate(insn.resultId(), type.componentCount);
Nicolas Capens72f089c2020-04-08 23:37:08 -04002223 auto &srcType = getType(getObject(insn.word(3)));
Nicolas Capense6f65d92020-04-08 21:55:43 -04002224 auto src = Operand(this, state, insn.word(3));
Nicolas Capens157ba262019-12-10 17:49:14 -05002225
2226 SIMD::UInt result = src.UInt(0);
2227
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002228 for(auto i = 1u; i < srcType.componentCount; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002229 {
2230 result &= src.UInt(i);
2231 }
2232
2233 dst.move(0, result);
2234 return EmitResult::Continue;
2235}
2236
2237SpirvShader::EmitResult SpirvShader::EmitAtomicOp(InsnIterator insn, EmitState *state) const
2238{
2239 auto &resultType = getType(Type::ID(insn.word(1)));
2240 Object::ID resultId = insn.word(2);
2241 Object::ID semanticsId = insn.word(5);
2242 auto memorySemantics = static_cast<spv::MemorySemanticsMask>(getObject(semanticsId).constantValue[0]);
2243 auto memoryOrder = MemoryOrder(memorySemantics);
2244 // Where no value is provided (increment/decrement) use an implicit value of 1.
Nicolas Capense6f65d92020-04-08 21:55:43 -04002245 auto value = (insn.wordCount() == 7) ? Operand(this, state, insn.word(6)).UInt(0) : RValue<SIMD::UInt>(1);
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002246 auto &dst = state->createIntermediate(resultId, resultType.componentCount);
Nicolas Capens157ba262019-12-10 17:49:14 -05002247 auto ptr = state->getPointer(insn.word(3));
2248 auto ptrOffsets = ptr.offsets();
2249
2250 SIMD::UInt x(0);
2251 auto mask = state->activeLaneMask() & state->storesAndAtomicsMask();
Nicolas Capens81bc9d92019-12-16 15:05:57 -05002252 for(int j = 0; j < SIMD::Width; j++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002253 {
2254 If(Extract(mask, j) != 0)
2255 {
2256 auto offset = Extract(ptrOffsets, j);
2257 auto laneValue = Extract(value, j);
2258 UInt v;
Nicolas Capens81bc9d92019-12-16 15:05:57 -05002259 switch(insn.opcode())
Nicolas Capens157ba262019-12-10 17:49:14 -05002260 {
Ben Claytonbc1c0672019-12-17 20:37:37 +00002261 case spv::OpAtomicIAdd:
2262 case spv::OpAtomicIIncrement:
2263 v = AddAtomic(Pointer<UInt>(&ptr.base[offset]), laneValue, memoryOrder);
2264 break;
2265 case spv::OpAtomicISub:
2266 case spv::OpAtomicIDecrement:
2267 v = SubAtomic(Pointer<UInt>(&ptr.base[offset]), laneValue, memoryOrder);
2268 break;
2269 case spv::OpAtomicAnd:
2270 v = AndAtomic(Pointer<UInt>(&ptr.base[offset]), laneValue, memoryOrder);
2271 break;
2272 case spv::OpAtomicOr:
2273 v = OrAtomic(Pointer<UInt>(&ptr.base[offset]), laneValue, memoryOrder);
2274 break;
2275 case spv::OpAtomicXor:
2276 v = XorAtomic(Pointer<UInt>(&ptr.base[offset]), laneValue, memoryOrder);
2277 break;
2278 case spv::OpAtomicSMin:
2279 v = As<UInt>(MinAtomic(Pointer<Int>(&ptr.base[offset]), As<Int>(laneValue), memoryOrder));
2280 break;
2281 case spv::OpAtomicSMax:
2282 v = As<UInt>(MaxAtomic(Pointer<Int>(&ptr.base[offset]), As<Int>(laneValue), memoryOrder));
2283 break;
2284 case spv::OpAtomicUMin:
2285 v = MinAtomic(Pointer<UInt>(&ptr.base[offset]), laneValue, memoryOrder);
2286 break;
2287 case spv::OpAtomicUMax:
2288 v = MaxAtomic(Pointer<UInt>(&ptr.base[offset]), laneValue, memoryOrder);
2289 break;
2290 case spv::OpAtomicExchange:
2291 v = ExchangeAtomic(Pointer<UInt>(&ptr.base[offset]), laneValue, memoryOrder);
2292 break;
2293 default:
2294 UNREACHABLE("%s", OpcodeName(insn.opcode()).c_str());
2295 break;
Nicolas Capens157ba262019-12-10 17:49:14 -05002296 }
2297 x = Insert(x, v, j);
2298 }
2299 }
2300
2301 dst.move(0, x);
2302 return EmitResult::Continue;
2303}
2304
2305SpirvShader::EmitResult SpirvShader::EmitAtomicCompareExchange(InsnIterator insn, EmitState *state) const
2306{
2307 // Separate from EmitAtomicOp due to different instruction encoding
2308 auto &resultType = getType(Type::ID(insn.word(1)));
2309 Object::ID resultId = insn.word(2);
2310
2311 auto memorySemanticsEqual = static_cast<spv::MemorySemanticsMask>(getObject(insn.word(5)).constantValue[0]);
2312 auto memoryOrderEqual = MemoryOrder(memorySemanticsEqual);
2313 auto memorySemanticsUnequal = static_cast<spv::MemorySemanticsMask>(getObject(insn.word(6)).constantValue[0]);
2314 auto memoryOrderUnequal = MemoryOrder(memorySemanticsUnequal);
2315
Nicolas Capense6f65d92020-04-08 21:55:43 -04002316 auto value = Operand(this, state, insn.word(7));
2317 auto comparator = Operand(this, state, insn.word(8));
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002318 auto &dst = state->createIntermediate(resultId, resultType.componentCount);
Nicolas Capens157ba262019-12-10 17:49:14 -05002319 auto ptr = state->getPointer(insn.word(3));
2320 auto ptrOffsets = ptr.offsets();
2321
2322 SIMD::UInt x(0);
2323 auto mask = state->activeLaneMask() & state->storesAndAtomicsMask();
Nicolas Capens81bc9d92019-12-16 15:05:57 -05002324 for(int j = 0; j < SIMD::Width; j++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002325 {
2326 If(Extract(mask, j) != 0)
2327 {
2328 auto offset = Extract(ptrOffsets, j);
2329 auto laneValue = Extract(value.UInt(0), j);
2330 auto laneComparator = Extract(comparator.UInt(0), j);
2331 UInt v = CompareExchangeAtomic(Pointer<UInt>(&ptr.base[offset]), laneValue, laneComparator, memoryOrderEqual, memoryOrderUnequal);
2332 x = Insert(x, v, j);
2333 }
2334 }
2335
2336 dst.move(0, x);
2337 return EmitResult::Continue;
2338}
2339
2340SpirvShader::EmitResult SpirvShader::EmitCopyObject(InsnIterator insn, EmitState *state) const
2341{
Nicolas Capens71186752020-04-09 01:05:31 -04002342 auto type = getType(insn.resultTypeId());
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002343 auto &dst = state->createIntermediate(insn.resultId(), type.componentCount);
Nicolas Capense6f65d92020-04-08 21:55:43 -04002344 auto src = Operand(this, state, insn.word(3));
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002345 for(uint32_t i = 0; i < type.componentCount; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002346 {
2347 dst.move(i, src.Int(i));
2348 }
2349 return EmitResult::Continue;
2350}
2351
2352SpirvShader::EmitResult SpirvShader::EmitArrayLength(InsnIterator insn, EmitState *state) const
2353{
Nicolas Capens157ba262019-12-10 17:49:14 -05002354 auto structPtrId = Object::ID(insn.word(3));
2355 auto arrayFieldIdx = insn.word(4);
2356
Nicolas Capens71186752020-04-09 01:05:31 -04002357 auto &resultType = getType(insn.resultTypeId());
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002358 ASSERT(resultType.componentCount == 1);
Nicolas Capens157ba262019-12-10 17:49:14 -05002359 ASSERT(resultType.definition.opcode() == spv::OpTypeInt);
2360
Nicolas Capens72f089c2020-04-08 23:37:08 -04002361 auto &structPtrTy = getType(getObject(structPtrId));
Nicolas Capens157ba262019-12-10 17:49:14 -05002362 auto &structTy = getType(structPtrTy.element);
Alexis Hetu74d3f372020-02-14 15:32:37 -05002363 auto arrayId = Type::ID(structTy.definition.word(2 + arrayFieldIdx));
Nicolas Capens157ba262019-12-10 17:49:14 -05002364
Nicolas Capens71186752020-04-09 01:05:31 -04002365 auto &result = state->createIntermediate(insn.resultId(), 1);
Nicolas Capens157ba262019-12-10 17:49:14 -05002366 auto structBase = GetPointerToData(structPtrId, 0, state);
2367
Alexis Hetu74d3f372020-02-14 15:32:37 -05002368 Decorations structDecorations = {};
2369 ApplyDecorationsForIdMember(&structDecorations, structPtrTy.element, arrayFieldIdx);
2370 ASSERT(structDecorations.HasOffset);
Nicolas Capens157ba262019-12-10 17:49:14 -05002371
Alexis Hetu74d3f372020-02-14 15:32:37 -05002372 auto arrayBase = structBase + structDecorations.Offset;
Nicolas Capens157ba262019-12-10 17:49:14 -05002373 auto arraySizeInBytes = SIMD::Int(arrayBase.limit()) - arrayBase.offsets();
Alexis Hetu74d3f372020-02-14 15:32:37 -05002374
2375 Decorations arrayDecorations = {};
2376 ApplyDecorationsForId(&arrayDecorations, arrayId);
2377 ASSERT(arrayDecorations.HasArrayStride);
2378 auto arrayLength = arraySizeInBytes / SIMD::Int(arrayDecorations.ArrayStride);
Nicolas Capens157ba262019-12-10 17:49:14 -05002379
2380 result.move(0, SIMD::Int(arrayLength));
2381
2382 return EmitResult::Continue;
2383}
2384
Ben Claytonb36dbbe2020-01-08 12:18:43 +00002385SpirvShader::EmitResult SpirvShader::EmitExtendedInstruction(InsnIterator insn, EmitState *state) const
2386{
2387 auto ext = getExtension(insn.word(3));
2388 switch(ext.name)
2389 {
2390 case Extension::GLSLstd450:
2391 return EmitExtGLSLstd450(insn, state);
Ben Claytoncd55f052020-01-14 11:56:00 +00002392 case Extension::OpenCLDebugInfo100:
2393 return EmitOpenCLDebugInfo100(insn, state);
Ben Claytonb36dbbe2020-01-08 12:18:43 +00002394 default:
2395 UNREACHABLE("Unknown Extension::Name<%d>", int(ext.name));
2396 }
2397 return EmitResult::Continue;
2398}
2399
Nicolas Capens157ba262019-12-10 17:49:14 -05002400uint32_t SpirvShader::GetConstScalarInt(Object::ID id) const
2401{
2402 auto &scopeObj = getObject(id);
2403 ASSERT(scopeObj.kind == Object::Kind::Constant);
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002404 ASSERT(getType(scopeObj).componentCount == 1);
Nicolas Capens157ba262019-12-10 17:49:14 -05002405 return scopeObj.constantValue[0];
2406}
2407
2408void SpirvShader::emitEpilog(SpirvRoutine *routine) const
2409{
Nicolas Capens81bc9d92019-12-16 15:05:57 -05002410 for(auto insn : *this)
Nicolas Capens157ba262019-12-10 17:49:14 -05002411 {
Nicolas Capens81bc9d92019-12-16 15:05:57 -05002412 switch(insn.opcode())
Nicolas Capens157ba262019-12-10 17:49:14 -05002413 {
Ben Claytonbc1c0672019-12-17 20:37:37 +00002414 case spv::OpVariable:
Nicolas Capens157ba262019-12-10 17:49:14 -05002415 {
Nicolas Capens71186752020-04-09 01:05:31 -04002416 auto &object = getObject(insn.resultId());
Nicolas Capens72f089c2020-04-08 23:37:08 -04002417 auto &objectTy = getType(object);
Ben Claytonbc1c0672019-12-17 20:37:37 +00002418 if(object.kind == Object::Kind::InterfaceVariable && objectTy.storageClass == spv::StorageClassOutput)
2419 {
Nicolas Capens71186752020-04-09 01:05:31 -04002420 auto &dst = routine->getVariable(insn.resultId());
Ben Claytonbc1c0672019-12-17 20:37:37 +00002421 int offset = 0;
Nicolas Capens71186752020-04-09 01:05:31 -04002422 VisitInterface(insn.resultId(),
Ben Claytonbc1c0672019-12-17 20:37:37 +00002423 [&](Decorations const &d, AttribType type) {
2424 auto scalarSlot = d.Location << 2 | d.Component;
2425 routine->outputs[scalarSlot] = dst[offset++];
2426 });
2427 }
2428 break;
Nicolas Capens157ba262019-12-10 17:49:14 -05002429 }
Ben Claytonbc1c0672019-12-17 20:37:37 +00002430 default:
2431 break;
Nicolas Capens157ba262019-12-10 17:49:14 -05002432 }
2433 }
2434
2435 // Clear phis that are no longer used. This serves two purposes:
2436 // (1) The phi rr::Variables are destructed, preventing pointless
2437 // materialization.
2438 // (2) Frees memory that will never be used again.
2439 routine->phis.clear();
2440}
2441
2442VkShaderStageFlagBits SpirvShader::executionModelToStage(spv::ExecutionModel model)
2443{
Nicolas Capens81bc9d92019-12-16 15:05:57 -05002444 switch(model)
Nicolas Capens157ba262019-12-10 17:49:14 -05002445 {
Ben Claytonbc1c0672019-12-17 20:37:37 +00002446 case spv::ExecutionModelVertex: return VK_SHADER_STAGE_VERTEX_BIT;
2447 // case spv::ExecutionModelTessellationControl: return VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
2448 // case spv::ExecutionModelTessellationEvaluation: return VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
2449 // case spv::ExecutionModelGeometry: return VK_SHADER_STAGE_GEOMETRY_BIT;
2450 case spv::ExecutionModelFragment: return VK_SHADER_STAGE_FRAGMENT_BIT;
2451 case spv::ExecutionModelGLCompute: return VK_SHADER_STAGE_COMPUTE_BIT;
2452 // case spv::ExecutionModelKernel: return VkShaderStageFlagBits(0); // Not supported by vulkan.
2453 // case spv::ExecutionModelTaskNV: return VK_SHADER_STAGE_TASK_BIT_NV;
2454 // case spv::ExecutionModelMeshNV: return VK_SHADER_STAGE_MESH_BIT_NV;
2455 // case spv::ExecutionModelRayGenerationNV: return VK_SHADER_STAGE_RAYGEN_BIT_NV;
2456 // case spv::ExecutionModelIntersectionNV: return VK_SHADER_STAGE_INTERSECTION_BIT_NV;
2457 // case spv::ExecutionModelAnyHitNV: return VK_SHADER_STAGE_ANY_HIT_BIT_NV;
2458 // case spv::ExecutionModelClosestHitNV: return VK_SHADER_STAGE_CLOSEST_HIT_BIT_NV;
2459 // case spv::ExecutionModelMissNV: return VK_SHADER_STAGE_MISS_BIT_NV;
2460 // case spv::ExecutionModelCallableNV: return VK_SHADER_STAGE_CALLABLE_BIT_NV;
2461 default:
2462 UNSUPPORTED("ExecutionModel: %d", int(model));
2463 return VkShaderStageFlagBits(0);
Nicolas Capens157ba262019-12-10 17:49:14 -05002464 }
2465}
2466
Nicolas Capens2f4b6032020-04-09 02:01:50 -04002467SpirvShader::Operand::Operand(const SpirvShader *shader, const EmitState *state, SpirvShader::Object::ID objectId)
2468 : Operand(state, shader->getObject(objectId))
Ben Claytonbc1c0672019-12-17 20:37:37 +00002469{}
Nicolas Capens157ba262019-12-10 17:49:14 -05002470
Nicolas Capens2f4b6032020-04-09 02:01:50 -04002471SpirvShader::Operand::Operand(const EmitState *state, const Object &object)
2472 : constant(object.constantValue.data())
2473 , intermediate(object.kind == SpirvShader::Object::Kind::Intermediate ? &state->getIntermediate(object.id()) : nullptr)
2474 , componentCount(intermediate ? intermediate->componentCount : object.constantValue.size())
2475{
2476 ASSERT(intermediate || (object.kind == SpirvShader::Object::Kind::Constant));
2477}
2478
Nicolas Capens20220a02020-04-09 02:48:16 -04002479SpirvShader::Operand::Operand(const Intermediate &value)
2480 : constant(nullptr)
2481 , intermediate(&value)
2482 , componentCount(value.componentCount)
2483{
2484}
2485
Ben Claytonbc1c0672019-12-17 20:37:37 +00002486SpirvRoutine::SpirvRoutine(vk::PipelineLayout const *pipelineLayout)
2487 : pipelineLayout(pipelineLayout)
Nicolas Capens157ba262019-12-10 17:49:14 -05002488{
2489}
2490
2491void SpirvRoutine::setImmutableInputBuiltins(SpirvShader const *shader)
2492{
Ben Claytonbc1c0672019-12-17 20:37:37 +00002493 setInputBuiltin(shader, spv::BuiltInSubgroupLocalInvocationId, [&](const SpirvShader::BuiltinMapping &builtin, Array<SIMD::Float> &value) {
Nicolas Capens157ba262019-12-10 17:49:14 -05002494 ASSERT(builtin.SizeInComponents == 1);
2495 value[builtin.FirstComponent] = As<SIMD::Float>(SIMD::Int(0, 1, 2, 3));
2496 });
2497
Ben Claytonbc1c0672019-12-17 20:37:37 +00002498 setInputBuiltin(shader, spv::BuiltInSubgroupEqMask, [&](const SpirvShader::BuiltinMapping &builtin, Array<SIMD::Float> &value) {
Nicolas Capens157ba262019-12-10 17:49:14 -05002499 ASSERT(builtin.SizeInComponents == 4);
2500 value[builtin.FirstComponent + 0] = As<SIMD::Float>(SIMD::Int(1, 2, 4, 8));
2501 value[builtin.FirstComponent + 1] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2502 value[builtin.FirstComponent + 2] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2503 value[builtin.FirstComponent + 3] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2504 });
2505
Ben Claytonbc1c0672019-12-17 20:37:37 +00002506 setInputBuiltin(shader, spv::BuiltInSubgroupGeMask, [&](const SpirvShader::BuiltinMapping &builtin, Array<SIMD::Float> &value) {
Nicolas Capens157ba262019-12-10 17:49:14 -05002507 ASSERT(builtin.SizeInComponents == 4);
2508 value[builtin.FirstComponent + 0] = As<SIMD::Float>(SIMD::Int(15, 14, 12, 8));
2509 value[builtin.FirstComponent + 1] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2510 value[builtin.FirstComponent + 2] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2511 value[builtin.FirstComponent + 3] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2512 });
2513
Ben Claytonbc1c0672019-12-17 20:37:37 +00002514 setInputBuiltin(shader, spv::BuiltInSubgroupGtMask, [&](const SpirvShader::BuiltinMapping &builtin, Array<SIMD::Float> &value) {
Nicolas Capens157ba262019-12-10 17:49:14 -05002515 ASSERT(builtin.SizeInComponents == 4);
2516 value[builtin.FirstComponent + 0] = As<SIMD::Float>(SIMD::Int(14, 12, 8, 0));
2517 value[builtin.FirstComponent + 1] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2518 value[builtin.FirstComponent + 2] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2519 value[builtin.FirstComponent + 3] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2520 });
2521
Ben Claytonbc1c0672019-12-17 20:37:37 +00002522 setInputBuiltin(shader, spv::BuiltInSubgroupLeMask, [&](const SpirvShader::BuiltinMapping &builtin, Array<SIMD::Float> &value) {
Nicolas Capens157ba262019-12-10 17:49:14 -05002523 ASSERT(builtin.SizeInComponents == 4);
2524 value[builtin.FirstComponent + 0] = As<SIMD::Float>(SIMD::Int(1, 3, 7, 15));
2525 value[builtin.FirstComponent + 1] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2526 value[builtin.FirstComponent + 2] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2527 value[builtin.FirstComponent + 3] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2528 });
2529
Ben Claytonbc1c0672019-12-17 20:37:37 +00002530 setInputBuiltin(shader, spv::BuiltInSubgroupLtMask, [&](const SpirvShader::BuiltinMapping &builtin, Array<SIMD::Float> &value) {
Nicolas Capens157ba262019-12-10 17:49:14 -05002531 ASSERT(builtin.SizeInComponents == 4);
2532 value[builtin.FirstComponent + 0] = As<SIMD::Float>(SIMD::Int(0, 1, 3, 7));
2533 value[builtin.FirstComponent + 1] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2534 value[builtin.FirstComponent + 2] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2535 value[builtin.FirstComponent + 3] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2536 });
2537
Ben Claytonbc1c0672019-12-17 20:37:37 +00002538 setInputBuiltin(shader, spv::BuiltInDeviceIndex, [&](const SpirvShader::BuiltinMapping &builtin, Array<SIMD::Float> &value) {
Nicolas Capens157ba262019-12-10 17:49:14 -05002539 ASSERT(builtin.SizeInComponents == 1);
2540 // Only a single physical device is supported.
2541 value[builtin.FirstComponent] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2542 });
2543}
2544
2545} // namespace sw