blob: 3d330b8e85a5e4844525760e507fee40cdce1df1 [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 Claytonbc1c067be2019-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 Claytonbc1c067be2019-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 Claytonbc1c067be2019-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
Ben Clayton964b9e32021-06-25 09:00:22 +010064 // The identifiers of all OpVariables that define the entry point's IO variables.
65 std::unordered_set<Object::ID> interfaceIds;
Nicolas Capens157ba262019-12-10 17:49:14 -050066
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 {
Nicolas Capens112faf42019-12-13 17:32:26 -050077 case spv::OpEntryPoint:
Nicolas Capens157ba262019-12-10 17:49:14 -050078 {
Ben Claytonbc1c067be2019-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;
Ben Clayton964b9e32021-06-25 09:00:22 +010087
88 auto interfaceIdsOffset = 3 + insn.stringSizeInWords(3);
89 for(uint32_t i = interfaceIdsOffset; i < insn.wordCount(); i++)
90 {
91 interfaceIds.emplace(insn.word(i));
92 }
Ben Claytonbc1c067be2019-12-17 20:37:37 +000093 }
Nicolas Capens157ba262019-12-10 17:49:14 -050094 }
Nicolas Capens112faf42019-12-13 17:32:26 -050095 break;
Nicolas Capens157ba262019-12-10 17:49:14 -050096
Nicolas Capens112faf42019-12-13 17:32:26 -050097 case spv::OpExecutionMode:
98 ProcessExecutionMode(insn);
99 break;
Nicolas Capens157ba262019-12-10 17:49:14 -0500100
Nicolas Capens112faf42019-12-13 17:32:26 -0500101 case spv::OpDecorate:
Nicolas Capens157ba262019-12-10 17:49:14 -0500102 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000103 TypeOrObjectID targetId = insn.word(1);
104 auto decoration = static_cast<spv::Decoration>(insn.word(2));
105 uint32_t value = insn.wordCount() > 3 ? insn.word(3) : 0;
106
107 decorations[targetId].Apply(decoration, value);
108
109 switch(decoration)
110 {
Nicolas Capens112faf42019-12-13 17:32:26 -0500111 case spv::DecorationDescriptorSet:
112 descriptorDecorations[targetId].DescriptorSet = value;
113 break;
114 case spv::DecorationBinding:
115 descriptorDecorations[targetId].Binding = value;
116 break;
117 case spv::DecorationInputAttachmentIndex:
118 descriptorDecorations[targetId].InputAttachmentIndex = value;
119 break;
120 case spv::DecorationSample:
121 modes.ContainsSampleQualifier = true;
122 break;
123 default:
124 // Only handling descriptor decorations here.
125 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000126 }
127
128 if(decoration == spv::DecorationCentroid)
Nicolas Capens112faf42019-12-13 17:32:26 -0500129 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000130 modes.NeedsCentroid = true;
Nicolas Capens112faf42019-12-13 17:32:26 -0500131 }
Nicolas Capens157ba262019-12-10 17:49:14 -0500132 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500133 break;
Nicolas Capens157ba262019-12-10 17:49:14 -0500134
Nicolas Capens112faf42019-12-13 17:32:26 -0500135 case spv::OpMemberDecorate:
Nicolas Capens157ba262019-12-10 17:49:14 -0500136 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000137 Type::ID targetId = insn.word(1);
138 auto memberIndex = insn.word(2);
139 auto decoration = static_cast<spv::Decoration>(insn.word(3));
140 uint32_t value = insn.wordCount() > 4 ? insn.word(4) : 0;
141
142 auto &d = memberDecorations[targetId];
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500143 if(memberIndex >= d.size())
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000144 d.resize(memberIndex + 1); // on demand; exact size would require another pass...
145
146 d[memberIndex].Apply(decoration, value);
147
148 if(decoration == spv::DecorationCentroid)
Nicolas Capens112faf42019-12-13 17:32:26 -0500149 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000150 modes.NeedsCentroid = true;
Nicolas Capens112faf42019-12-13 17:32:26 -0500151 }
Nicolas Capens157ba262019-12-10 17:49:14 -0500152 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500153 break;
Nicolas Capens157ba262019-12-10 17:49:14 -0500154
Nicolas Capens112faf42019-12-13 17:32:26 -0500155 case spv::OpDecorateId:
Sean Risser79a271a2020-12-02 16:56:03 -0500156 {
157 auto decoration = static_cast<spv::Decoration>(insn.word(2));
158
159 // Currently OpDecorateId only supports UniformId, which provides information for
160 // potential optimizations that we don't perform, and CounterBuffer, which is used
161 // by HLSL to build the graphics pipeline with shader reflection. At the driver level,
162 // the CounterBuffer decoration does nothing, so we can safely ignore both decorations.
163 ASSERT(decoration == spv::DecorationUniformId || decoration == spv::DecorationCounterBuffer);
Sean Risser79a271a2020-12-02 16:56:03 -0500164 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500165 break;
Sean Risser79a271a2020-12-02 16:56:03 -0500166
Nicolas Capens112faf42019-12-13 17:32:26 -0500167 case spv::OpDecorateString:
168 case spv::OpMemberDecorateString:
169 // We assume these are for HLSL semantics, ignore them.
170 break;
Sean Risser79a271a2020-12-02 16:56:03 -0500171
Nicolas Capens112faf42019-12-13 17:32:26 -0500172 case spv::OpDecorationGroup:
173 // Nothing to do here. We don't need to record the definition of the group; we'll just have
174 // the bundle of decorations float around. If we were to ever walk the decorations directly,
175 // we might think about introducing this as a real Object.
176 break;
Nicolas Capens157ba262019-12-10 17:49:14 -0500177
Nicolas Capens112faf42019-12-13 17:32:26 -0500178 case spv::OpGroupDecorate:
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000179 {
180 uint32_t group = insn.word(1);
181 auto const &groupDecorations = decorations[group];
182 auto const &descriptorGroupDecorations = descriptorDecorations[group];
183 for(auto i = 2u; i < insn.wordCount(); i++)
184 {
185 // Remaining operands are targets to apply the group to.
186 uint32_t target = insn.word(i);
187 decorations[target].Apply(groupDecorations);
188 descriptorDecorations[target].Apply(descriptorGroupDecorations);
189 }
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000190 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500191 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000192
Nicolas Capens112faf42019-12-13 17:32:26 -0500193 case spv::OpGroupMemberDecorate:
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000194 {
195 auto const &srcDecorations = decorations[insn.word(1)];
196 for(auto i = 2u; i < insn.wordCount(); i += 2)
197 {
198 // remaining operands are pairs of <id>, literal for members to apply to.
199 auto &d = memberDecorations[insn.word(i)];
200 auto memberIndex = insn.word(i + 1);
201 if(memberIndex >= d.size())
202 d.resize(memberIndex + 1); // on demand resize, see above...
203 d[memberIndex].Apply(srcDecorations);
204 }
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000205 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500206 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000207
Nicolas Capens112faf42019-12-13 17:32:26 -0500208 case spv::OpLabel:
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000209 {
210 ASSERT(currentBlock.value() == 0);
211 currentBlock = Block::ID(insn.word(1));
212 blockStart = insn;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000213 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500214 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000215
Nicolas Capens112faf42019-12-13 17:32:26 -0500216 // Branch Instructions (subset of Termination Instructions):
217 case spv::OpBranch:
218 case spv::OpBranchConditional:
219 case spv::OpSwitch:
220 case spv::OpReturn:
221 // [[fallthrough]]
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000222
Nicolas Capens112faf42019-12-13 17:32:26 -0500223 // Termination instruction:
224 case spv::OpKill:
225 case spv::OpUnreachable:
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000226 {
227 ASSERT(currentBlock.value() != 0);
228 ASSERT(currentFunction.value() != 0);
229
230 auto blockEnd = insn;
231 blockEnd++;
232 functions[currentFunction].blocks[currentBlock] = Block(blockStart, blockEnd);
233 currentBlock = Block::ID(0);
234
235 if(opcode == spv::OpKill)
236 {
237 modes.ContainsKill = true;
238 }
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000239 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500240 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000241
Nicolas Capens112faf42019-12-13 17:32:26 -0500242 case spv::OpLoopMerge:
243 case spv::OpSelectionMerge:
244 break; // Nothing to do in analysis pass.
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000245
Nicolas Capens112faf42019-12-13 17:32:26 -0500246 case spv::OpTypeVoid:
247 case spv::OpTypeBool:
248 case spv::OpTypeInt:
249 case spv::OpTypeFloat:
250 case spv::OpTypeVector:
251 case spv::OpTypeMatrix:
252 case spv::OpTypeImage:
253 case spv::OpTypeSampler:
254 case spv::OpTypeSampledImage:
255 case spv::OpTypeArray:
256 case spv::OpTypeRuntimeArray:
257 case spv::OpTypeStruct:
258 case spv::OpTypePointer:
259 case spv::OpTypeFunction:
260 DeclareType(insn);
261 break;
Nicolas Capens157ba262019-12-10 17:49:14 -0500262
Nicolas Capens112faf42019-12-13 17:32:26 -0500263 case spv::OpVariable:
Nicolas Capens157ba262019-12-10 17:49:14 -0500264 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000265 Type::ID typeId = insn.word(1);
266 Object::ID resultId = insn.word(2);
267 auto storageClass = static_cast<spv::StorageClass>(insn.word(3));
268
269 auto &object = defs[resultId];
Nicolas Capens157ba262019-12-10 17:49:14 -0500270 object.kind = Object::Kind::Pointer;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000271 object.definition = insn;
Nicolas Capens157ba262019-12-10 17:49:14 -0500272
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000273 ASSERT(getType(typeId).definition.opcode() == spv::OpTypePointer);
274 ASSERT(getType(typeId).storageClass == storageClass);
Nicolas Capens157ba262019-12-10 17:49:14 -0500275
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000276 switch(storageClass)
Nicolas Capens157ba262019-12-10 17:49:14 -0500277 {
Nicolas Capens112faf42019-12-13 17:32:26 -0500278 case spv::StorageClassInput:
279 case spv::StorageClassOutput:
Ben Clayton964b9e32021-06-25 09:00:22 +0100280 if(interfaceIds.count(resultId))
281 {
282 ProcessInterfaceVariable(object);
283 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500284 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000285
Nicolas Capens112faf42019-12-13 17:32:26 -0500286 case spv::StorageClassUniform:
287 case spv::StorageClassStorageBuffer:
288 object.kind = Object::Kind::DescriptorSet;
289 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000290
Nicolas Capens112faf42019-12-13 17:32:26 -0500291 case spv::StorageClassPushConstant:
292 case spv::StorageClassPrivate:
293 case spv::StorageClassFunction:
294 case spv::StorageClassUniformConstant:
295 break; // Correctly handled.
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000296
Nicolas Capens112faf42019-12-13 17:32:26 -0500297 case spv::StorageClassWorkgroup:
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000298 {
299 auto &elTy = getType(getType(typeId).element);
Nicolas Capensff9f9b52020-04-14 00:46:38 -0400300 auto sizeInBytes = elTy.componentCount * static_cast<uint32_t>(sizeof(float));
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000301 workgroupMemory.allocate(resultId, sizeInBytes);
302 object.kind = Object::Kind::Pointer;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000303 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500304 break;
305 case spv::StorageClassAtomicCounter:
306 case spv::StorageClassImage:
307 UNSUPPORTED("StorageClass %d not yet supported", (int)storageClass);
308 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000309
Nicolas Capens112faf42019-12-13 17:32:26 -0500310 case spv::StorageClassCrossWorkgroup:
311 UNSUPPORTED("SPIR-V OpenCL Execution Model (StorageClassCrossWorkgroup)");
312 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000313
Nicolas Capens112faf42019-12-13 17:32:26 -0500314 case spv::StorageClassGeneric:
315 UNSUPPORTED("SPIR-V GenericPointer Capability (StorageClassGeneric)");
316 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000317
Nicolas Capens112faf42019-12-13 17:32:26 -0500318 default:
319 UNREACHABLE("Unexpected StorageClass %d", storageClass); // See Appendix A of the Vulkan spec.
320 break;
Nicolas Capens157ba262019-12-10 17:49:14 -0500321 }
322 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500323 break;
Nicolas Capens157ba262019-12-10 17:49:14 -0500324
Nicolas Capens112faf42019-12-13 17:32:26 -0500325 case spv::OpConstant:
326 case spv::OpSpecConstant:
327 CreateConstant(insn).constantValue[0] = insn.word(3);
328 break;
329 case spv::OpConstantFalse:
330 case spv::OpSpecConstantFalse:
331 CreateConstant(insn).constantValue[0] = 0; // Represent Boolean false as zero.
332 break;
333 case spv::OpConstantTrue:
334 case spv::OpSpecConstantTrue:
335 CreateConstant(insn).constantValue[0] = ~0u; // Represent Boolean true as all bits set.
336 break;
337 case spv::OpConstantNull:
338 case spv::OpUndef:
Nicolas Capens157ba262019-12-10 17:49:14 -0500339 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000340 // TODO: consider a real LLVM-level undef. For now, zero is a perfectly good value.
341 // OpConstantNull forms a constant of arbitrary type, all zeros.
342 auto &object = CreateConstant(insn);
Nicolas Capens72f089c2020-04-08 23:37:08 -0400343 auto &objectTy = getType(object);
Nicolas Capensff9f9b52020-04-14 00:46:38 -0400344 for(auto i = 0u; i < objectTy.componentCount; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -0500345 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000346 object.constantValue[i] = 0;
Nicolas Capens157ba262019-12-10 17:49:14 -0500347 }
348 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500349 break;
350 case spv::OpConstantComposite:
351 case spv::OpSpecConstantComposite:
Nicolas Capens157ba262019-12-10 17:49:14 -0500352 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000353 auto &object = CreateConstant(insn);
354 auto offset = 0u;
355 for(auto i = 0u; i < insn.wordCount() - 3; i++)
356 {
357 auto &constituent = getObject(insn.word(i + 3));
Nicolas Capens72f089c2020-04-08 23:37:08 -0400358 auto &constituentTy = getType(constituent);
Nicolas Capensff9f9b52020-04-14 00:46:38 -0400359 for(auto j = 0u; j < constituentTy.componentCount; j++)
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000360 {
361 object.constantValue[offset++] = constituent.constantValue[j];
362 }
363 }
364
365 auto objectId = Object::ID(insn.word(2));
366 auto decorationsIt = decorations.find(objectId);
367 if(decorationsIt != decorations.end() &&
368 decorationsIt->second.BuiltIn == spv::BuiltInWorkgroupSize)
369 {
370 // https://www.khronos.org/registry/vulkan/specs/1.1/html/vkspec.html#interfaces-builtin-variables :
371 // Decorating an object with the WorkgroupSize built-in
372 // decoration will make that object contain the dimensions
373 // of a local workgroup. If an object is decorated with the
374 // WorkgroupSize decoration, this must take precedence over
375 // any execution mode set for LocalSize.
376 // The object decorated with WorkgroupSize must be declared
377 // as a three-component vector of 32-bit integers.
Nicolas Capensff9f9b52020-04-14 00:46:38 -0400378 ASSERT(getType(object).componentCount == 3);
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000379 modes.WorkgroupSizeX = object.constantValue[0];
380 modes.WorkgroupSizeY = object.constantValue[1];
381 modes.WorkgroupSizeZ = object.constantValue[2];
382 }
Nicolas Capens157ba262019-12-10 17:49:14 -0500383 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500384 break;
385 case spv::OpSpecConstantOp:
386 EvalSpecConstantOp(insn);
387 break;
Ben Clayton9b156612019-03-13 19:48:31 +0000388
Nicolas Capens112faf42019-12-13 17:32:26 -0500389 case spv::OpCapability:
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000390 {
391 auto capability = static_cast<spv::Capability>(insn.word(1));
392 switch(capability)
393 {
Nicolas Capens112faf42019-12-13 17:32:26 -0500394 case spv::CapabilityMatrix: capabilities.Matrix = true; break;
395 case spv::CapabilityShader: capabilities.Shader = true; break;
396 case spv::CapabilityStorageImageMultisample: capabilities.StorageImageMultisample = true; break;
397 case spv::CapabilityClipDistance: capabilities.ClipDistance = true; break;
398 case spv::CapabilityCullDistance: capabilities.CullDistance = true; break;
399 case spv::CapabilityImageCubeArray: capabilities.ImageCubeArray = true; break;
400 case spv::CapabilitySampleRateShading: capabilities.SampleRateShading = true; break;
401 case spv::CapabilityInputAttachment: capabilities.InputAttachment = true; break;
402 case spv::CapabilitySampled1D: capabilities.Sampled1D = true; break;
403 case spv::CapabilityImage1D: capabilities.Image1D = true; break;
404 case spv::CapabilitySampledBuffer: capabilities.SampledBuffer = true; break;
405 case spv::CapabilitySampledCubeArray: capabilities.SampledCubeArray = true; break;
406 case spv::CapabilityImageBuffer: capabilities.ImageBuffer = true; break;
407 case spv::CapabilityImageMSArray: capabilities.ImageMSArray = true; break;
408 case spv::CapabilityStorageImageExtendedFormats: capabilities.StorageImageExtendedFormats = true; break;
409 case spv::CapabilityImageQuery: capabilities.ImageQuery = true; break;
410 case spv::CapabilityDerivativeControl: capabilities.DerivativeControl = true; break;
411 case spv::CapabilityInterpolationFunction: capabilities.InterpolationFunction = true; break;
412 case spv::CapabilityGroupNonUniform: capabilities.GroupNonUniform = true; break;
413 case spv::CapabilityGroupNonUniformVote: capabilities.GroupNonUniformVote = true; break;
414 case spv::CapabilityGroupNonUniformArithmetic: capabilities.GroupNonUniformArithmetic = true; break;
415 case spv::CapabilityGroupNonUniformBallot: capabilities.GroupNonUniformBallot = true; break;
416 case spv::CapabilityGroupNonUniformShuffle: capabilities.GroupNonUniformShuffle = true; break;
417 case spv::CapabilityGroupNonUniformShuffleRelative: capabilities.GroupNonUniformShuffleRelative = true; break;
418 case spv::CapabilityDeviceGroup: capabilities.DeviceGroup = true; break;
419 case spv::CapabilityMultiView: capabilities.MultiView = true; break;
420 case spv::CapabilityStencilExportEXT: capabilities.StencilExportEXT = true; break;
421 default:
422 UNSUPPORTED("Unsupported capability %u", insn.word(1));
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000423 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500424
425 // Various capabilities will be declared, but none affect our code generation at this point.
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000426 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500427 break;
Ben Clayton9b156612019-03-13 19:48:31 +0000428
Nicolas Capens112faf42019-12-13 17:32:26 -0500429 case spv::OpMemoryModel:
430 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 -0500431
Nicolas Capens112faf42019-12-13 17:32:26 -0500432 case spv::OpFunction:
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000433 {
434 auto functionId = Function::ID(insn.word(2));
435 ASSERT_MSG(currentFunction == 0, "Functions %d and %d overlap", currentFunction.value(), functionId.value());
436 currentFunction = functionId;
437 auto &function = functions[functionId];
438 function.result = Type::ID(insn.word(1));
439 function.type = Type::ID(insn.word(4));
440 // Scan forward to find the function's label.
Ben Clayton7d098242020-03-13 13:07:12 +0000441 for(auto it = insn; it != end(); it++)
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000442 {
Ben Clayton7d098242020-03-13 13:07:12 +0000443 if(it.opcode() == spv::OpLabel)
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000444 {
Ben Clayton7d098242020-03-13 13:07:12 +0000445 function.entry = Block::ID(it.word(1));
446 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000447 }
448 }
449 ASSERT_MSG(function.entry != 0, "Function<%d> has no label", currentFunction.value());
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000450 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500451 break;
Nicolas Capens157ba262019-12-10 17:49:14 -0500452
Nicolas Capens112faf42019-12-13 17:32:26 -0500453 case spv::OpFunctionEnd:
454 currentFunction = 0;
455 break;
Nicolas Capens157ba262019-12-10 17:49:14 -0500456
Nicolas Capens112faf42019-12-13 17:32:26 -0500457 case spv::OpExtInstImport:
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000458 {
Ben Clayton683bad82020-02-10 23:57:09 +0000459 static constexpr std::pair<const char *, Extension::Name> extensionsByName[] = {
Ben Claytonf6a6a412020-01-09 16:43:37 +0000460 { "GLSL.std.450", Extension::GLSLstd450 },
Ben Claytoncd55f052020-01-14 11:56:00 +0000461 { "OpenCL.DebugInfo.100", Extension::OpenCLDebugInfo100 },
Ben Claytonf6a6a412020-01-09 16:43:37 +0000462 };
Ben Clayton683bad82020-02-10 23:57:09 +0000463 static constexpr auto extensionCount = sizeof(extensionsByName) / sizeof(extensionsByName[0]);
464
Ben Claytonb36dbbe2020-01-08 12:18:43 +0000465 auto id = Extension::ID(insn.word(1));
466 auto name = insn.string(2);
467 auto ext = Extension{ Extension::Unknown };
Ben Clayton683bad82020-02-10 23:57:09 +0000468 for(size_t i = 0; i < extensionCount; i++)
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000469 {
Ben Clayton683bad82020-02-10 23:57:09 +0000470 if(0 == strcmp(name, extensionsByName[i].first))
Ben Claytonb36dbbe2020-01-08 12:18:43 +0000471 {
Ben Clayton683bad82020-02-10 23:57:09 +0000472 ext = Extension{ extensionsByName[i].second };
Ben Claytonb36dbbe2020-01-08 12:18:43 +0000473 break;
474 }
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000475 }
Ben Claytonb36dbbe2020-01-08 12:18:43 +0000476 if(ext.name == Extension::Unknown)
477 {
478 UNSUPPORTED("SPIR-V Extension: %s", name);
479 break;
480 }
Ben Clayton8842c8f2020-01-13 16:57:48 +0000481 extensionsByID.emplace(id, ext);
482 extensionsImported.emplace(ext.name);
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000483 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500484 break;
485 case spv::OpName:
486 case spv::OpMemberName:
487 case spv::OpSource:
488 case spv::OpSourceContinued:
489 case spv::OpSourceExtension:
490 case spv::OpLine:
491 case spv::OpNoLine:
492 case spv::OpModuleProcessed:
493 // No semantic impact
494 break;
Ben Clayton9b156612019-03-13 19:48:31 +0000495
Nicolas Capens112faf42019-12-13 17:32:26 -0500496 case spv::OpString:
497 strings.emplace(insn.word(1), insn.string(2));
498 break;
Ben Clayton9c8823a2020-01-08 12:07:30 +0000499
Nicolas Capens112faf42019-12-13 17:32:26 -0500500 case spv::OpFunctionParameter:
501 // These should have all been removed by preprocessing passes. If we see them here,
502 // our assumptions are wrong and we will probably generate wrong code.
503 UNREACHABLE("%s should have already been lowered.", OpcodeName(opcode));
504 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000505
Nicolas Capens112faf42019-12-13 17:32:26 -0500506 case spv::OpFunctionCall:
507 // TODO(b/141246700): Add full support for spv::OpFunctionCall
508 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000509
Nicolas Capens112faf42019-12-13 17:32:26 -0500510 case spv::OpFConvert:
511 UNSUPPORTED("SPIR-V Float16 or Float64 Capability (OpFConvert)");
512 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000513
Nicolas Capens112faf42019-12-13 17:32:26 -0500514 case spv::OpSConvert:
515 UNSUPPORTED("SPIR-V Int16 or Int64 Capability (OpSConvert)");
516 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000517
Nicolas Capens112faf42019-12-13 17:32:26 -0500518 case spv::OpUConvert:
519 UNSUPPORTED("SPIR-V Int16 or Int64 Capability (OpUConvert)");
520 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000521
Nicolas Capens112faf42019-12-13 17:32:26 -0500522 case spv::OpLoad:
523 case spv::OpAccessChain:
524 case spv::OpInBoundsAccessChain:
525 case spv::OpSampledImage:
526 case spv::OpImage:
Nicolas Capens157ba262019-12-10 17:49:14 -0500527 {
528 // Propagate the descriptor decorations to the result.
529 Object::ID resultId = insn.word(2);
530 Object::ID pointerId = insn.word(3);
531 const auto &d = descriptorDecorations.find(pointerId);
532
533 if(d != descriptorDecorations.end())
534 {
535 descriptorDecorations[resultId] = d->second;
536 }
537
538 DefineResult(insn);
539
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500540 if(opcode == spv::OpAccessChain || opcode == spv::OpInBoundsAccessChain)
Nicolas Capens157ba262019-12-10 17:49:14 -0500541 {
542 Decorations dd{};
543 ApplyDecorationsForAccessChain(&dd, &descriptorDecorations[resultId], pointerId, insn.wordCount() - 4, insn.wordPointer(4));
544 // Note: offset is the one thing that does *not* propagate, as the access chain accounts for it.
545 dd.HasOffset = false;
546 decorations[resultId].Apply(dd);
547 }
548 }
549 break;
Ben Clayton9b156612019-03-13 19:48:31 +0000550
Nicolas Capens112faf42019-12-13 17:32:26 -0500551 case spv::OpCompositeConstruct:
552 case spv::OpCompositeInsert:
553 case spv::OpCompositeExtract:
554 case spv::OpVectorShuffle:
555 case spv::OpVectorTimesScalar:
556 case spv::OpMatrixTimesScalar:
557 case spv::OpMatrixTimesVector:
558 case spv::OpVectorTimesMatrix:
559 case spv::OpMatrixTimesMatrix:
560 case spv::OpOuterProduct:
561 case spv::OpTranspose:
562 case spv::OpVectorExtractDynamic:
563 case spv::OpVectorInsertDynamic:
564 // Unary ops
565 case spv::OpNot:
566 case spv::OpBitFieldInsert:
567 case spv::OpBitFieldSExtract:
568 case spv::OpBitFieldUExtract:
569 case spv::OpBitReverse:
570 case spv::OpBitCount:
571 case spv::OpSNegate:
572 case spv::OpFNegate:
573 case spv::OpLogicalNot:
574 case spv::OpQuantizeToF16:
575 // Binary ops
576 case spv::OpIAdd:
577 case spv::OpISub:
578 case spv::OpIMul:
579 case spv::OpSDiv:
580 case spv::OpUDiv:
581 case spv::OpFAdd:
582 case spv::OpFSub:
583 case spv::OpFMul:
584 case spv::OpFDiv:
585 case spv::OpFMod:
586 case spv::OpFRem:
587 case spv::OpFOrdEqual:
588 case spv::OpFUnordEqual:
589 case spv::OpFOrdNotEqual:
590 case spv::OpFUnordNotEqual:
591 case spv::OpFOrdLessThan:
592 case spv::OpFUnordLessThan:
593 case spv::OpFOrdGreaterThan:
594 case spv::OpFUnordGreaterThan:
595 case spv::OpFOrdLessThanEqual:
596 case spv::OpFUnordLessThanEqual:
597 case spv::OpFOrdGreaterThanEqual:
598 case spv::OpFUnordGreaterThanEqual:
599 case spv::OpSMod:
600 case spv::OpSRem:
601 case spv::OpUMod:
602 case spv::OpIEqual:
603 case spv::OpINotEqual:
604 case spv::OpUGreaterThan:
605 case spv::OpSGreaterThan:
606 case spv::OpUGreaterThanEqual:
607 case spv::OpSGreaterThanEqual:
608 case spv::OpULessThan:
609 case spv::OpSLessThan:
610 case spv::OpULessThanEqual:
611 case spv::OpSLessThanEqual:
612 case spv::OpShiftRightLogical:
613 case spv::OpShiftRightArithmetic:
614 case spv::OpShiftLeftLogical:
615 case spv::OpBitwiseOr:
616 case spv::OpBitwiseXor:
617 case spv::OpBitwiseAnd:
618 case spv::OpLogicalOr:
619 case spv::OpLogicalAnd:
620 case spv::OpLogicalEqual:
621 case spv::OpLogicalNotEqual:
622 case spv::OpUMulExtended:
623 case spv::OpSMulExtended:
624 case spv::OpIAddCarry:
625 case spv::OpISubBorrow:
626 case spv::OpDot:
627 case spv::OpConvertFToU:
628 case spv::OpConvertFToS:
629 case spv::OpConvertSToF:
630 case spv::OpConvertUToF:
631 case spv::OpBitcast:
632 case spv::OpSelect:
633 case spv::OpIsInf:
634 case spv::OpIsNan:
635 case spv::OpAny:
636 case spv::OpAll:
637 case spv::OpDPdx:
638 case spv::OpDPdxCoarse:
639 case spv::OpDPdy:
640 case spv::OpDPdyCoarse:
641 case spv::OpFwidth:
642 case spv::OpFwidthCoarse:
643 case spv::OpDPdxFine:
644 case spv::OpDPdyFine:
645 case spv::OpFwidthFine:
646 case spv::OpAtomicLoad:
647 case spv::OpAtomicIAdd:
648 case spv::OpAtomicISub:
649 case spv::OpAtomicSMin:
650 case spv::OpAtomicSMax:
651 case spv::OpAtomicUMin:
652 case spv::OpAtomicUMax:
653 case spv::OpAtomicAnd:
654 case spv::OpAtomicOr:
655 case spv::OpAtomicXor:
656 case spv::OpAtomicIIncrement:
657 case spv::OpAtomicIDecrement:
658 case spv::OpAtomicExchange:
659 case spv::OpAtomicCompareExchange:
660 case spv::OpPhi:
661 case spv::OpImageSampleImplicitLod:
662 case spv::OpImageSampleExplicitLod:
663 case spv::OpImageSampleDrefImplicitLod:
664 case spv::OpImageSampleDrefExplicitLod:
665 case spv::OpImageSampleProjImplicitLod:
666 case spv::OpImageSampleProjExplicitLod:
667 case spv::OpImageSampleProjDrefImplicitLod:
668 case spv::OpImageSampleProjDrefExplicitLod:
669 case spv::OpImageGather:
670 case spv::OpImageDrefGather:
671 case spv::OpImageFetch:
672 case spv::OpImageQuerySizeLod:
673 case spv::OpImageQuerySize:
674 case spv::OpImageQueryLod:
675 case spv::OpImageQueryLevels:
676 case spv::OpImageQuerySamples:
677 case spv::OpImageRead:
678 case spv::OpImageTexelPointer:
679 case spv::OpGroupNonUniformElect:
680 case spv::OpGroupNonUniformAll:
681 case spv::OpGroupNonUniformAny:
682 case spv::OpGroupNonUniformAllEqual:
683 case spv::OpGroupNonUniformBroadcast:
684 case spv::OpGroupNonUniformBroadcastFirst:
685 case spv::OpGroupNonUniformBallot:
686 case spv::OpGroupNonUniformInverseBallot:
687 case spv::OpGroupNonUniformBallotBitExtract:
688 case spv::OpGroupNonUniformBallotBitCount:
689 case spv::OpGroupNonUniformBallotFindLSB:
690 case spv::OpGroupNonUniformBallotFindMSB:
691 case spv::OpGroupNonUniformShuffle:
692 case spv::OpGroupNonUniformShuffleXor:
693 case spv::OpGroupNonUniformShuffleUp:
694 case spv::OpGroupNonUniformShuffleDown:
695 case spv::OpGroupNonUniformIAdd:
696 case spv::OpGroupNonUniformFAdd:
697 case spv::OpGroupNonUniformIMul:
698 case spv::OpGroupNonUniformFMul:
699 case spv::OpGroupNonUniformSMin:
700 case spv::OpGroupNonUniformUMin:
701 case spv::OpGroupNonUniformFMin:
702 case spv::OpGroupNonUniformSMax:
703 case spv::OpGroupNonUniformUMax:
704 case spv::OpGroupNonUniformFMax:
705 case spv::OpGroupNonUniformBitwiseAnd:
706 case spv::OpGroupNonUniformBitwiseOr:
707 case spv::OpGroupNonUniformBitwiseXor:
708 case spv::OpGroupNonUniformLogicalAnd:
709 case spv::OpGroupNonUniformLogicalOr:
710 case spv::OpGroupNonUniformLogicalXor:
711 case spv::OpCopyObject:
712 case spv::OpCopyLogical:
713 case spv::OpArrayLength:
714 // Instructions that yield an intermediate value or divergent pointer
715 DefineResult(insn);
716 break;
717
718 case spv::OpExtInst:
719 switch(getExtension(insn.word(3)).name)
720 {
721 case Extension::GLSLstd450:
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000722 DefineResult(insn);
723 break;
Nicolas Capens112faf42019-12-13 17:32:26 -0500724 case Extension::OpenCLDebugInfo100:
725 DefineOpenCLDebugInfo100(insn);
Ben Claytonb36dbbe2020-01-08 12:18:43 +0000726 break;
Nicolas Capens112faf42019-12-13 17:32:26 -0500727 default:
728 UNREACHABLE("Unexpected Extension name %d", int(getExtension(insn.word(3)).name));
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000729 break;
Nicolas Capens112faf42019-12-13 17:32:26 -0500730 }
731 break;
Nicolas Capens157ba262019-12-10 17:49:14 -0500732
Nicolas Capens112faf42019-12-13 17:32:26 -0500733 case spv::OpStore:
734 case spv::OpAtomicStore:
735 case spv::OpImageWrite:
736 case spv::OpCopyMemory:
737 case spv::OpMemoryBarrier:
738 // Don't need to do anything during analysis pass
739 break;
Nicolas Capens157ba262019-12-10 17:49:14 -0500740
Nicolas Capens112faf42019-12-13 17:32:26 -0500741 case spv::OpControlBarrier:
742 modes.ContainsControlBarriers = true;
743 break;
744
745 case spv::OpExtension:
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000746 {
747 auto ext = insn.string(1);
748 // Part of core SPIR-V 1.3. Vulkan 1.1 implementations must also accept the pre-1.3
749 // extension per Appendix A, `Vulkan Environment for SPIR-V`.
750 if(!strcmp(ext, "SPV_KHR_storage_buffer_storage_class")) break;
751 if(!strcmp(ext, "SPV_KHR_shader_draw_parameters")) break;
752 if(!strcmp(ext, "SPV_KHR_16bit_storage")) break;
753 if(!strcmp(ext, "SPV_KHR_variable_pointers")) break;
754 if(!strcmp(ext, "SPV_KHR_device_group")) break;
755 if(!strcmp(ext, "SPV_KHR_multiview")) break;
Alexis Hetu1ee36c92020-02-20 14:07:26 -0500756 if(!strcmp(ext, "SPV_EXT_shader_stencil_export")) break;
Sean Risser0063eca2020-10-26 17:08:42 -0400757 if(!strcmp(ext, "SPV_KHR_float_controls")) break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000758 UNSUPPORTED("SPIR-V Extension: %s", ext);
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000759 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500760 break;
Ben Claytonc0cf68b2019-03-21 17:46:08 +0000761
Nicolas Capens112faf42019-12-13 17:32:26 -0500762 default:
763 UNSUPPORTED("%s", OpcodeName(opcode));
Nicolas Capens157ba262019-12-10 17:49:14 -0500764 }
Chris Forbesd5aed492019-02-02 15:18:52 -0800765 }
Chris Forbesc61271e2019-02-19 17:01:28 -0800766
Nicolas Capens157ba262019-12-10 17:49:14 -0500767 ASSERT_MSG(entryPoint != 0, "Entry point '%s' not found", entryPointName);
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500768 for(auto &it : functions)
Nicolas Capensfabdec52019-03-21 17:04:05 -0400769 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500770 it.second.AssignBlockFields();
Nicolas Capensfabdec52019-03-21 17:04:05 -0400771 }
Ben Claytonb0ca2a82020-01-08 13:00:57 +0000772
Ben Clayton0d6791c2020-04-22 21:55:27 +0100773#ifdef SPIRV_SHADER_CFG_GRAPHVIZ_DOT_FILEPATH
774 {
775 char path[1024];
776 snprintf(path, sizeof(path), SPIRV_SHADER_CFG_GRAPHVIZ_DOT_FILEPATH, codeSerialID);
777 WriteCFGGraphVizDotFile(path);
778 }
779#endif
780
Ben Claytonb0ca2a82020-01-08 13:00:57 +0000781 dbgCreateFile();
782}
783
784SpirvShader::~SpirvShader()
785{
786 dbgTerm();
Nicolas Capens157ba262019-12-10 17:49:14 -0500787}
Nicolas Capensfabdec52019-03-21 17:04:05 -0400788
Nicolas Capens157ba262019-12-10 17:49:14 -0500789void SpirvShader::DeclareType(InsnIterator insn)
790{
791 Type::ID resultId = insn.word(1);
792
793 auto &type = types[resultId];
794 type.definition = insn;
Nicolas Capensff9f9b52020-04-14 00:46:38 -0400795 type.componentCount = ComputeTypeSize(insn);
Nicolas Capens157ba262019-12-10 17:49:14 -0500796
797 // A structure is a builtin block if it has a builtin
798 // member. All members of such a structure are builtins.
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500799 switch(insn.opcode())
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000800 {
Nicolas Capens112faf42019-12-13 17:32:26 -0500801 case spv::OpTypeStruct:
Nicolas Capens157ba262019-12-10 17:49:14 -0500802 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000803 auto d = memberDecorations.find(resultId);
804 if(d != memberDecorations.end())
Nicolas Capens157ba262019-12-10 17:49:14 -0500805 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000806 for(auto &m : d->second)
Nicolas Capens157ba262019-12-10 17:49:14 -0500807 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000808 if(m.HasBuiltIn)
809 {
810 type.isBuiltInBlock = true;
811 break;
812 }
Nicolas Capens157ba262019-12-10 17:49:14 -0500813 }
814 }
815 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500816 break;
817 case spv::OpTypePointer:
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000818 {
819 Type::ID elementTypeId = insn.word(3);
820 type.element = elementTypeId;
821 type.isBuiltInBlock = getType(elementTypeId).isBuiltInBlock;
822 type.storageClass = static_cast<spv::StorageClass>(insn.word(2));
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000823 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500824 break;
825 case spv::OpTypeVector:
826 case spv::OpTypeMatrix:
827 case spv::OpTypeArray:
828 case spv::OpTypeRuntimeArray:
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000829 {
830 Type::ID elementTypeId = insn.word(2);
831 type.element = elementTypeId;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000832 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500833 break;
834 default:
835 break;
Nicolas Capens157ba262019-12-10 17:49:14 -0500836 }
837}
838
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000839SpirvShader::Object &SpirvShader::CreateConstant(InsnIterator insn)
Nicolas Capens157ba262019-12-10 17:49:14 -0500840{
841 Type::ID typeId = insn.word(1);
842 Object::ID resultId = insn.word(2);
843 auto &object = defs[resultId];
844 auto &objectTy = getType(typeId);
Nicolas Capens157ba262019-12-10 17:49:14 -0500845 object.kind = Object::Kind::Constant;
846 object.definition = insn;
Nicolas Capens2f4b6032020-04-09 02:01:50 -0400847 object.constantValue.resize(objectTy.componentCount);
Nicolas Capens72f089c2020-04-08 23:37:08 -0400848
Nicolas Capens157ba262019-12-10 17:49:14 -0500849 return object;
850}
851
852void SpirvShader::ProcessInterfaceVariable(Object &object)
853{
Nicolas Capens72f089c2020-04-08 23:37:08 -0400854 auto &objectTy = getType(object);
Nicolas Capens157ba262019-12-10 17:49:14 -0500855 ASSERT(objectTy.storageClass == spv::StorageClassInput || objectTy.storageClass == spv::StorageClassOutput);
856
857 ASSERT(objectTy.opcode() == spv::OpTypePointer);
858 auto pointeeTy = getType(objectTy.element);
859
860 auto &builtinInterface = (objectTy.storageClass == spv::StorageClassInput) ? inputBuiltins : outputBuiltins;
861 auto &userDefinedInterface = (objectTy.storageClass == spv::StorageClassInput) ? inputs : outputs;
862
863 ASSERT(object.opcode() == spv::OpVariable);
864 Object::ID resultId = object.definition.word(2);
865
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500866 if(objectTy.isBuiltInBlock)
Nicolas Capens157ba262019-12-10 17:49:14 -0500867 {
Nicolas Capens71186752020-04-09 01:05:31 -0400868 // Walk the builtin block, registering each of its members separately.
Nicolas Capens157ba262019-12-10 17:49:14 -0500869 auto m = memberDecorations.find(objectTy.element);
Nicolas Capens71186752020-04-09 01:05:31 -0400870 ASSERT(m != memberDecorations.end()); // Otherwise we wouldn't have marked the type chain
Nicolas Capens157ba262019-12-10 17:49:14 -0500871 auto &structType = pointeeTy.definition;
Nicolas Capens71186752020-04-09 01:05:31 -0400872 auto memberIndex = 0u;
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000873 auto offset = 0u;
Nicolas Capens71186752020-04-09 01:05:31 -0400874
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500875 for(auto &member : m->second)
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000876 {
Nicolas Capens71186752020-04-09 01:05:31 -0400877 auto &memberType = getType(structType.word(2 + memberIndex));
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000878
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500879 if(member.HasBuiltIn)
Ben Clayton9b62c5e2019-03-08 09:32:34 +0000880 {
Nicolas Capensff9f9b52020-04-14 00:46:38 -0400881 builtinInterface[member.BuiltIn] = { resultId, offset, memberType.componentCount };
Ben Clayton9b62c5e2019-03-08 09:32:34 +0000882 }
Ben Claytonc0cf68b2019-03-21 17:46:08 +0000883
Nicolas Capensff9f9b52020-04-14 00:46:38 -0400884 offset += memberType.componentCount;
Nicolas Capens71186752020-04-09 01:05:31 -0400885 ++memberIndex;
Nicolas Capens157ba262019-12-10 17:49:14 -0500886 }
Nicolas Capens71186752020-04-09 01:05:31 -0400887
Nicolas Capens157ba262019-12-10 17:49:14 -0500888 return;
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000889 }
890
Nicolas Capens157ba262019-12-10 17:49:14 -0500891 auto d = decorations.find(resultId);
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500892 if(d != decorations.end() && d->second.HasBuiltIn)
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000893 {
Nicolas Capensff9f9b52020-04-14 00:46:38 -0400894 builtinInterface[d->second.BuiltIn] = { resultId, 0, pointeeTy.componentCount };
Nicolas Capens157ba262019-12-10 17:49:14 -0500895 }
896 else
897 {
898 object.kind = Object::Kind::InterfaceVariable;
899 VisitInterface(resultId,
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000900 [&userDefinedInterface](Decorations const &d, AttribType type) {
901 // Populate a single scalar slot in the interface from a collection of decorations and the intended component type.
902 auto scalarSlot = (d.Location << 2) | d.Component;
903 ASSERT(scalarSlot >= 0 &&
904 scalarSlot < static_cast<int32_t>(userDefinedInterface.size()));
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000905
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000906 auto &slot = userDefinedInterface[scalarSlot];
907 slot.Type = type;
908 slot.Flat = d.Flat;
909 slot.NoPerspective = d.NoPerspective;
910 slot.Centroid = d.Centroid;
911 });
Nicolas Capens157ba262019-12-10 17:49:14 -0500912 }
913}
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000914
Alexis Hetu945f1442021-01-14 11:39:56 -0500915uint32_t SpirvShader::GetNumInputComponents(int32_t location) const
916{
917 ASSERT(location >= 0);
918
919 // Verify how many component(s) per input
920 // 1 to 4, for float, vec2, vec3, vec4.
921 // Note that matrices are divided over multiple inputs
922 uint32_t num_components_per_input = 0;
923 for(; num_components_per_input < 4; ++num_components_per_input)
924 {
925 if(inputs[(location << 2) | num_components_per_input].Type == ATTRIBTYPE_UNUSED)
926 {
927 break;
928 }
929 }
930
931 return num_components_per_input;
932}
933
Nicolas Capens157ba262019-12-10 17:49:14 -0500934void SpirvShader::ProcessExecutionMode(InsnIterator insn)
935{
Nicolas Capens57eb48a2020-05-15 17:07:07 -0400936 Function::ID function = insn.word(1);
937 if(function != entryPoint)
938 {
939 return;
940 }
941
Nicolas Capens157ba262019-12-10 17:49:14 -0500942 auto mode = static_cast<spv::ExecutionMode>(insn.word(2));
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500943 switch(mode)
Nicolas Capens157ba262019-12-10 17:49:14 -0500944 {
Nicolas Capens112faf42019-12-13 17:32:26 -0500945 case spv::ExecutionModeEarlyFragmentTests:
946 modes.EarlyFragmentTests = true;
947 break;
948 case spv::ExecutionModeDepthReplacing:
949 modes.DepthReplacing = true;
950 break;
951 case spv::ExecutionModeDepthGreater:
952 // TODO(b/177915067): Can be used to optimize depth test, currently unused.
953 modes.DepthGreater = true;
954 break;
955 case spv::ExecutionModeDepthLess:
956 // TODO(b/177915067): Can be used to optimize depth test, currently unused.
957 modes.DepthLess = true;
958 break;
959 case spv::ExecutionModeDepthUnchanged:
960 // TODO(b/177915067): Can be used to optimize depth test, currently unused.
961 modes.DepthUnchanged = true;
962 break;
963 case spv::ExecutionModeLocalSize:
964 modes.WorkgroupSizeX = insn.word(3);
965 modes.WorkgroupSizeY = insn.word(4);
966 modes.WorkgroupSizeZ = insn.word(5);
967 break;
968 case spv::ExecutionModeOriginUpperLeft:
969 // This is always the case for a Vulkan shader. Do nothing.
970 break;
971 default:
972 UNREACHABLE("Execution mode: %d", int(mode));
Nicolas Capens157ba262019-12-10 17:49:14 -0500973 }
974}
Ben Claytonc0cf68b2019-03-21 17:46:08 +0000975
Nicolas Capens157ba262019-12-10 17:49:14 -0500976uint32_t SpirvShader::ComputeTypeSize(InsnIterator insn)
977{
978 // Types are always built from the bottom up (with the exception of forward ptrs, which
979 // don't appear in Vulkan shaders. Therefore, we can always assume our component parts have
980 // already been described (and so their sizes determined)
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500981 switch(insn.opcode())
Nicolas Capens157ba262019-12-10 17:49:14 -0500982 {
Nicolas Capens112faf42019-12-13 17:32:26 -0500983 case spv::OpTypeVoid:
984 case spv::OpTypeSampler:
985 case spv::OpTypeImage:
986 case spv::OpTypeSampledImage:
987 case spv::OpTypeFunction:
988 case spv::OpTypeRuntimeArray:
989 // Objects that don't consume any space.
990 // Descriptor-backed objects currently only need exist at compile-time.
991 // Runtime arrays don't appear in places where their size would be interesting
992 return 0;
Nicolas Capens157ba262019-12-10 17:49:14 -0500993
Nicolas Capens112faf42019-12-13 17:32:26 -0500994 case spv::OpTypeBool:
995 case spv::OpTypeFloat:
996 case spv::OpTypeInt:
997 // All the fundamental types are 1 component. If we ever add support for 8/16/64-bit components,
998 // we might need to change this, but only 32 bit components are required for Vulkan 1.1.
999 return 1;
Nicolas Capens157ba262019-12-10 17:49:14 -05001000
Nicolas Capens112faf42019-12-13 17:32:26 -05001001 case spv::OpTypeVector:
1002 case spv::OpTypeMatrix:
1003 // Vectors and matrices both consume element count * element size.
1004 return getType(insn.word(2)).componentCount * insn.word(3);
Nicolas Capens157ba262019-12-10 17:49:14 -05001005
Nicolas Capens112faf42019-12-13 17:32:26 -05001006 case spv::OpTypeArray:
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001007 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001008 // Element count * element size. Array sizes come from constant ids.
1009 auto arraySize = GetConstScalarInt(insn.word(3));
Nicolas Capensff9f9b52020-04-14 00:46:38 -04001010 return getType(insn.word(2)).componentCount * arraySize;
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001011 }
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001012
Nicolas Capens112faf42019-12-13 17:32:26 -05001013 case spv::OpTypeStruct:
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001014 {
1015 uint32_t size = 0;
1016 for(uint32_t i = 2u; i < insn.wordCount(); i++)
1017 {
Nicolas Capensff9f9b52020-04-14 00:46:38 -04001018 size += getType(insn.word(i)).componentCount;
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001019 }
1020 return size;
1021 }
Nicolas Capens157ba262019-12-10 17:49:14 -05001022
Nicolas Capens112faf42019-12-13 17:32:26 -05001023 case spv::OpTypePointer:
1024 // Runtime representation of a pointer is a per-lane index.
1025 // Note: clients are expected to look through the pointer if they want the pointee size instead.
1026 return 1;
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001027
Nicolas Capens112faf42019-12-13 17:32:26 -05001028 default:
1029 UNREACHABLE("%s", OpcodeName(insn.opcode()));
1030 return 0;
Nicolas Capens157ba262019-12-10 17:49:14 -05001031 }
1032}
1033
1034int SpirvShader::VisitInterfaceInner(Type::ID id, Decorations d, const InterfaceVisitor &f) const
1035{
1036 // Recursively walks variable definition and its type tree, taking into account
1037 // any explicit Location or Component decorations encountered; where explicit
1038 // Locations or Components are not specified, assigns them sequentially.
1039 // Collected decorations are carried down toward the leaves and across
1040 // siblings; Effect of decorations intentionally does not flow back up the tree.
1041 //
1042 // F is a functor to be called with the effective decoration set for every component.
1043 //
1044 // Returns the next available location, and calls f().
1045
1046 // This covers the rules in Vulkan 1.1 spec, 14.1.4 Location Assignment.
1047
1048 ApplyDecorationsForId(&d, id);
1049
1050 auto const &obj = getType(id);
1051 switch(obj.opcode())
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001052 {
Nicolas Capens112faf42019-12-13 17:32:26 -05001053 case spv::OpTypePointer:
1054 return VisitInterfaceInner(obj.definition.word(3), d, f);
1055 case spv::OpTypeMatrix:
1056 for(auto i = 0u; i < obj.definition.word(3); i++, d.Location++)
1057 {
1058 // consumes same components of N consecutive locations
1059 VisitInterfaceInner(obj.definition.word(2), d, f);
1060 }
1061 return d.Location;
1062 case spv::OpTypeVector:
1063 for(auto i = 0u; i < obj.definition.word(3); i++, d.Component++)
1064 {
1065 // consumes N consecutive components in the same location
1066 VisitInterfaceInner(obj.definition.word(2), d, f);
1067 }
1068 return d.Location + 1;
1069 case spv::OpTypeFloat:
1070 f(d, ATTRIBTYPE_FLOAT);
1071 return d.Location + 1;
1072 case spv::OpTypeInt:
1073 f(d, obj.definition.word(3) ? ATTRIBTYPE_INT : ATTRIBTYPE_UINT);
1074 return d.Location + 1;
1075 case spv::OpTypeBool:
1076 f(d, ATTRIBTYPE_UINT);
1077 return d.Location + 1;
1078 case spv::OpTypeStruct:
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001079 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001080 // iterate over members, which may themselves have Location/Component decorations
1081 for(auto i = 0u; i < obj.definition.wordCount() - 2; i++)
1082 {
Alexis Hetub6540802020-08-11 18:12:03 -04001083 Decorations dMember = d;
1084 ApplyDecorationsForIdMember(&dMember, id, i);
1085 d.Location = VisitInterfaceInner(obj.definition.word(i + 2), dMember, f);
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001086 d.Component = 0; // Implicit locations always have component=0
1087 }
1088 return d.Location;
Nicolas Capens157ba262019-12-10 17:49:14 -05001089 }
Nicolas Capens112faf42019-12-13 17:32:26 -05001090 case spv::OpTypeArray:
Nicolas Capens157ba262019-12-10 17:49:14 -05001091 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001092 auto arraySize = GetConstScalarInt(obj.definition.word(3));
1093 for(auto i = 0u; i < arraySize; i++)
1094 {
1095 d.Location = VisitInterfaceInner(obj.definition.word(2), d, f);
1096 }
1097 return d.Location;
Nicolas Capens157ba262019-12-10 17:49:14 -05001098 }
Nicolas Capens112faf42019-12-13 17:32:26 -05001099 default:
1100 // Intentionally partial; most opcodes do not participate in type hierarchies
1101 return 0;
Nicolas Capens157ba262019-12-10 17:49:14 -05001102 }
1103}
1104
1105void SpirvShader::VisitInterface(Object::ID id, const InterfaceVisitor &f) const
1106{
1107 // Walk a variable definition and call f for each component in it.
1108 Decorations d{};
1109 ApplyDecorationsForId(&d, id);
1110
1111 auto def = getObject(id).definition;
1112 ASSERT(def.opcode() == spv::OpVariable);
1113 VisitInterfaceInner(def.word(1), d, f);
1114}
1115
1116void SpirvShader::ApplyDecorationsForAccessChain(Decorations *d, DescriptorDecorations *dd, Object::ID baseId, uint32_t numIndexes, uint32_t const *indexIds) const
1117{
1118 ApplyDecorationsForId(d, baseId);
1119 auto &baseObject = getObject(baseId);
Nicolas Capens72f089c2020-04-08 23:37:08 -04001120 ApplyDecorationsForId(d, baseObject.typeId());
1121 auto typeId = getType(baseObject).element;
Nicolas Capens157ba262019-12-10 17:49:14 -05001122
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001123 for(auto i = 0u; i < numIndexes; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05001124 {
1125 ApplyDecorationsForId(d, typeId);
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001126 auto &type = getType(typeId);
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001127 switch(type.opcode())
Nicolas Capens157ba262019-12-10 17:49:14 -05001128 {
Nicolas Capens112faf42019-12-13 17:32:26 -05001129 case spv::OpTypeStruct:
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001130 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001131 int memberIndex = GetConstScalarInt(indexIds[i]);
1132 ApplyDecorationsForIdMember(d, typeId, memberIndex);
1133 typeId = type.definition.word(2u + memberIndex);
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001134 }
Nicolas Capens112faf42019-12-13 17:32:26 -05001135 break;
1136 case spv::OpTypeArray:
1137 case spv::OpTypeRuntimeArray:
1138 if(dd->InputAttachmentIndex >= 0)
1139 {
1140 dd->InputAttachmentIndex += GetConstScalarInt(indexIds[i]);
1141 }
1142 typeId = type.element;
1143 break;
1144 case spv::OpTypeVector:
1145 typeId = type.element;
1146 break;
1147 case spv::OpTypeMatrix:
1148 typeId = type.element;
1149 d->InsideMatrix = true;
1150 break;
1151 default:
1152 UNREACHABLE("%s", OpcodeName(type.definition.opcode()));
Nicolas Capens157ba262019-12-10 17:49:14 -05001153 }
1154 }
1155}
1156
1157SIMD::Pointer SpirvShader::WalkExplicitLayoutAccessChain(Object::ID baseId, uint32_t numIndexes, uint32_t const *indexIds, EmitState const *state) const
1158{
1159 // Produce a offset into external memory in sizeof(float) units
1160
1161 auto &baseObject = getObject(baseId);
Nicolas Capens72f089c2020-04-08 23:37:08 -04001162 Type::ID typeId = getType(baseObject).element;
Nicolas Capens157ba262019-12-10 17:49:14 -05001163 Decorations d = {};
Nicolas Capens72f089c2020-04-08 23:37:08 -04001164 ApplyDecorationsForId(&d, baseObject.typeId());
Nicolas Capens157ba262019-12-10 17:49:14 -05001165
Nicolas Capens479d1432020-01-31 11:19:21 -05001166 Int arrayIndex = 0;
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001167 if(baseObject.kind == Object::Kind::DescriptorSet)
Nicolas Capens157ba262019-12-10 17:49:14 -05001168 {
1169 auto type = getType(typeId).definition.opcode();
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001170 if(type == spv::OpTypeArray || type == spv::OpTypeRuntimeArray)
Nicolas Capens157ba262019-12-10 17:49:14 -05001171 {
Nicolas Capens479d1432020-01-31 11:19:21 -05001172 auto &obj = getObject(indexIds[0]);
1173 ASSERT(obj.kind == Object::Kind::Constant || obj.kind == Object::Kind::Intermediate);
1174 if(obj.kind == Object::Kind::Constant)
1175 {
1176 arrayIndex = GetConstScalarInt(indexIds[0]);
1177 }
1178 else
1179 {
1180 // Note: the value of indexIds[0] must be dynamically uniform.
1181 arrayIndex = Extract(state->getIntermediate(indexIds[0]).Int(0), 0);
1182 }
Nicolas Capens157ba262019-12-10 17:49:14 -05001183
1184 numIndexes--;
1185 indexIds++;
1186 typeId = getType(typeId).element;
1187 }
1188 }
1189
1190 auto ptr = GetPointerToData(baseId, arrayIndex, state);
1191
1192 int constantOffset = 0;
1193
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001194 for(auto i = 0u; i < numIndexes; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05001195 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001196 auto &type = getType(typeId);
Nicolas Capens157ba262019-12-10 17:49:14 -05001197 ApplyDecorationsForId(&d, typeId);
1198
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001199 switch(type.definition.opcode())
Nicolas Capens157ba262019-12-10 17:49:14 -05001200 {
Nicolas Capens112faf42019-12-13 17:32:26 -05001201 case spv::OpTypeStruct:
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001202 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001203 int memberIndex = GetConstScalarInt(indexIds[i]);
1204 ApplyDecorationsForIdMember(&d, typeId, memberIndex);
1205 ASSERT(d.HasOffset);
1206 constantOffset += d.Offset;
1207 typeId = type.definition.word(2u + memberIndex);
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001208 }
Nicolas Capens112faf42019-12-13 17:32:26 -05001209 break;
1210 case spv::OpTypeArray:
1211 case spv::OpTypeRuntimeArray:
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001212 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001213 // TODO: b/127950082: Check bounds.
1214 ASSERT(d.HasArrayStride);
1215 auto &obj = getObject(indexIds[i]);
1216 if(obj.kind == Object::Kind::Constant)
1217 {
1218 constantOffset += d.ArrayStride * GetConstScalarInt(indexIds[i]);
1219 }
1220 else
1221 {
1222 ptr += SIMD::Int(d.ArrayStride) * state->getIntermediate(indexIds[i]).Int(0);
1223 }
1224 typeId = type.element;
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001225 }
Nicolas Capens112faf42019-12-13 17:32:26 -05001226 break;
1227 case spv::OpTypeMatrix:
Chris Forbes17813932019-04-18 11:45:54 -07001228 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001229 // TODO: b/127950082: Check bounds.
1230 ASSERT(d.HasMatrixStride);
1231 d.InsideMatrix = true;
1232 auto columnStride = (d.HasRowMajor && d.RowMajor) ? static_cast<int32_t>(sizeof(float)) : d.MatrixStride;
1233 auto &obj = getObject(indexIds[i]);
1234 if(obj.kind == Object::Kind::Constant)
1235 {
1236 constantOffset += columnStride * GetConstScalarInt(indexIds[i]);
1237 }
1238 else
1239 {
1240 ptr += SIMD::Int(columnStride) * state->getIntermediate(indexIds[i]).Int(0);
1241 }
1242 typeId = type.element;
Chris Forbes17813932019-04-18 11:45:54 -07001243 }
Nicolas Capens112faf42019-12-13 17:32:26 -05001244 break;
1245 case spv::OpTypeVector:
Chris Forbesa16238d2019-04-18 16:31:54 -07001246 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001247 auto elemStride = (d.InsideMatrix && d.HasRowMajor && d.RowMajor) ? d.MatrixStride : static_cast<int32_t>(sizeof(float));
1248 auto &obj = getObject(indexIds[i]);
1249 if(obj.kind == Object::Kind::Constant)
1250 {
1251 constantOffset += elemStride * GetConstScalarInt(indexIds[i]);
1252 }
1253 else
1254 {
1255 ptr += SIMD::Int(elemStride) * state->getIntermediate(indexIds[i]).Int(0);
1256 }
1257 typeId = type.element;
Chris Forbesa16238d2019-04-18 16:31:54 -07001258 }
Nicolas Capens112faf42019-12-13 17:32:26 -05001259 break;
1260 default:
1261 UNREACHABLE("%s", OpcodeName(type.definition.opcode()));
Ben Clayton60f15ec2019-05-09 17:50:01 +01001262 }
1263 }
1264
Nicolas Capens157ba262019-12-10 17:49:14 -05001265 ptr += constantOffset;
1266 return ptr;
1267}
Ben Clayton59cd59b2019-06-25 19:07:48 +01001268
Nicolas Capens157ba262019-12-10 17:49:14 -05001269SIMD::Pointer SpirvShader::WalkAccessChain(Object::ID baseId, uint32_t numIndexes, uint32_t const *indexIds, EmitState const *state) const
1270{
1271 // TODO: avoid doing per-lane work in some cases if we can?
1272 auto routine = state->routine;
1273 auto &baseObject = getObject(baseId);
Nicolas Capens72f089c2020-04-08 23:37:08 -04001274 Type::ID typeId = getType(baseObject).element;
Nicolas Capens157ba262019-12-10 17:49:14 -05001275
1276 auto ptr = state->getPointer(baseId);
1277
1278 int constantOffset = 0;
1279
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001280 for(auto i = 0u; i < numIndexes; i++)
Ben Clayton76e9bc02019-02-26 15:02:18 +00001281 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001282 auto &type = getType(typeId);
Nicolas Capens157ba262019-12-10 17:49:14 -05001283 switch(type.opcode())
1284 {
Nicolas Capens112faf42019-12-13 17:32:26 -05001285 case spv::OpTypeStruct:
Nicolas Capens157ba262019-12-10 17:49:14 -05001286 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001287 int memberIndex = GetConstScalarInt(indexIds[i]);
1288 int offsetIntoStruct = 0;
1289 for(auto j = 0; j < memberIndex; j++)
Nicolas Capens157ba262019-12-10 17:49:14 -05001290 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001291 auto memberType = type.definition.word(2u + j);
Nicolas Capensff9f9b52020-04-14 00:46:38 -04001292 offsetIntoStruct += getType(memberType).componentCount * sizeof(float);
Nicolas Capens157ba262019-12-10 17:49:14 -05001293 }
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001294 constantOffset += offsetIntoStruct;
1295 typeId = type.definition.word(2u + memberIndex);
Nicolas Capens157ba262019-12-10 17:49:14 -05001296 }
Nicolas Capens112faf42019-12-13 17:32:26 -05001297 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001298
Nicolas Capens112faf42019-12-13 17:32:26 -05001299 case spv::OpTypeVector:
1300 case spv::OpTypeMatrix:
1301 case spv::OpTypeArray:
1302 case spv::OpTypeRuntimeArray:
Nicolas Capens157ba262019-12-10 17:49:14 -05001303 {
Nicolas Capens479d1432020-01-31 11:19:21 -05001304 // TODO(b/127950082): Check bounds.
Nicolas Capens72f089c2020-04-08 23:37:08 -04001305 if(getType(baseObject).storageClass == spv::StorageClassUniformConstant)
Nicolas Capens157ba262019-12-10 17:49:14 -05001306 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001307 // indexing into an array of descriptors.
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001308 auto d = descriptorDecorations.at(baseId);
1309 ASSERT(d.DescriptorSet >= 0);
1310 ASSERT(d.Binding >= 0);
Nicolas Capensc7d5ec32020-04-22 01:11:37 -04001311 uint32_t descriptorSize = routine->pipelineLayout->getDescriptorSize(d.DescriptorSet, d.Binding);
Nicolas Capens479d1432020-01-31 11:19:21 -05001312
1313 auto &obj = getObject(indexIds[i]);
1314 if(obj.kind == Object::Kind::Constant)
1315 {
1316 ptr.base += descriptorSize * GetConstScalarInt(indexIds[i]);
1317 }
1318 else
1319 {
1320 // Note: the value of indexIds[i] must be dynamically uniform.
1321 ptr.base += descriptorSize * Extract(state->getIntermediate(indexIds[i]).Int(0), 0);
1322 }
Nicolas Capens157ba262019-12-10 17:49:14 -05001323 }
1324 else
1325 {
Nicolas Capensff9f9b52020-04-14 00:46:38 -04001326 auto stride = getType(type.element).componentCount * static_cast<uint32_t>(sizeof(float));
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001327 auto &obj = getObject(indexIds[i]);
1328 if(obj.kind == Object::Kind::Constant)
1329 {
1330 ptr += stride * GetConstScalarInt(indexIds[i]);
1331 }
1332 else
1333 {
1334 ptr += SIMD::Int(stride) * state->getIntermediate(indexIds[i]).Int(0);
1335 }
Nicolas Capens157ba262019-12-10 17:49:14 -05001336 }
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001337 typeId = type.element;
Nicolas Capens157ba262019-12-10 17:49:14 -05001338 }
Nicolas Capens112faf42019-12-13 17:32:26 -05001339 break;
Nicolas Capens157ba262019-12-10 17:49:14 -05001340
Nicolas Capens112faf42019-12-13 17:32:26 -05001341 default:
1342 UNREACHABLE("%s", OpcodeName(type.opcode()));
Nicolas Capens157ba262019-12-10 17:49:14 -05001343 }
Ben Clayton76e9bc02019-02-26 15:02:18 +00001344 }
1345
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001346 if(constantOffset != 0)
Ben Clayton30ee92e2019-08-13 14:21:44 +01001347 {
Nicolas Capens157ba262019-12-10 17:49:14 -05001348 ptr += constantOffset;
1349 }
1350 return ptr;
1351}
Ben Clayton30ee92e2019-08-13 14:21:44 +01001352
Nicolas Capens157ba262019-12-10 17:49:14 -05001353uint32_t SpirvShader::WalkLiteralAccessChain(Type::ID typeId, uint32_t numIndexes, uint32_t const *indexes) const
1354{
1355 uint32_t componentOffset = 0;
Ben Clayton30ee92e2019-08-13 14:21:44 +01001356
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001357 for(auto i = 0u; i < numIndexes; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05001358 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001359 auto &type = getType(typeId);
Nicolas Capens157ba262019-12-10 17:49:14 -05001360 switch(type.opcode())
Ben Clayton30ee92e2019-08-13 14:21:44 +01001361 {
Nicolas Capens112faf42019-12-13 17:32:26 -05001362 case spv::OpTypeStruct:
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001363 {
1364 int memberIndex = indexes[i];
1365 int offsetIntoStruct = 0;
1366 for(auto j = 0; j < memberIndex; j++)
1367 {
1368 auto memberType = type.definition.word(2u + j);
Nicolas Capensff9f9b52020-04-14 00:46:38 -04001369 offsetIntoStruct += getType(memberType).componentCount;
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001370 }
1371 componentOffset += offsetIntoStruct;
1372 typeId = type.definition.word(2u + memberIndex);
Nicolas Capens157ba262019-12-10 17:49:14 -05001373 }
Nicolas Capens112faf42019-12-13 17:32:26 -05001374 break;
Ben Clayton30ee92e2019-08-13 14:21:44 +01001375
Nicolas Capens112faf42019-12-13 17:32:26 -05001376 case spv::OpTypeVector:
1377 case spv::OpTypeMatrix:
1378 case spv::OpTypeArray:
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001379 {
1380 auto elementType = type.definition.word(2);
Nicolas Capensff9f9b52020-04-14 00:46:38 -04001381 auto stride = getType(elementType).componentCount;
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001382 componentOffset += stride * indexes[i];
1383 typeId = elementType;
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001384 }
Nicolas Capens112faf42019-12-13 17:32:26 -05001385 break;
Ben Clayton30ee92e2019-08-13 14:21:44 +01001386
Nicolas Capens112faf42019-12-13 17:32:26 -05001387 default:
1388 UNREACHABLE("%s", OpcodeName(type.opcode()));
Nicolas Capens157ba262019-12-10 17:49:14 -05001389 }
1390 }
Ben Clayton30ee92e2019-08-13 14:21:44 +01001391
Nicolas Capens157ba262019-12-10 17:49:14 -05001392 return componentOffset;
1393}
Ben Clayton30ee92e2019-08-13 14:21:44 +01001394
Nicolas Capens157ba262019-12-10 17:49:14 -05001395void SpirvShader::Decorations::Apply(spv::Decoration decoration, uint32_t arg)
1396{
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001397 switch(decoration)
Nicolas Capens157ba262019-12-10 17:49:14 -05001398 {
Nicolas Capens112faf42019-12-13 17:32:26 -05001399 case spv::DecorationLocation:
1400 HasLocation = true;
1401 Location = static_cast<int32_t>(arg);
1402 break;
1403 case spv::DecorationComponent:
1404 HasComponent = true;
1405 Component = arg;
1406 break;
1407 case spv::DecorationBuiltIn:
1408 HasBuiltIn = true;
1409 BuiltIn = static_cast<spv::BuiltIn>(arg);
1410 break;
1411 case spv::DecorationFlat:
1412 Flat = true;
1413 break;
1414 case spv::DecorationNoPerspective:
1415 NoPerspective = true;
1416 break;
1417 case spv::DecorationCentroid:
1418 Centroid = true;
1419 break;
1420 case spv::DecorationBlock:
1421 Block = true;
1422 break;
1423 case spv::DecorationBufferBlock:
1424 BufferBlock = true;
1425 break;
1426 case spv::DecorationOffset:
1427 HasOffset = true;
1428 Offset = static_cast<int32_t>(arg);
1429 break;
1430 case spv::DecorationArrayStride:
1431 HasArrayStride = true;
1432 ArrayStride = static_cast<int32_t>(arg);
1433 break;
1434 case spv::DecorationMatrixStride:
1435 HasMatrixStride = true;
1436 MatrixStride = static_cast<int32_t>(arg);
1437 break;
1438 case spv::DecorationRelaxedPrecision:
1439 RelaxedPrecision = true;
1440 break;
1441 case spv::DecorationRowMajor:
1442 HasRowMajor = true;
1443 RowMajor = true;
1444 break;
1445 case spv::DecorationColMajor:
1446 HasRowMajor = true;
1447 RowMajor = false;
1448 default:
1449 // Intentionally partial, there are many decorations we just don't care about.
1450 break;
Ben Clayton30ee92e2019-08-13 14:21:44 +01001451 }
Chris Forbesc25b8072018-12-10 15:10:39 -08001452}
Nicolas Capens157ba262019-12-10 17:49:14 -05001453
1454void SpirvShader::Decorations::Apply(const sw::SpirvShader::Decorations &src)
1455{
1456 // Apply a decoration group to this set of decorations
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001457 if(src.HasBuiltIn)
Nicolas Capens157ba262019-12-10 17:49:14 -05001458 {
1459 HasBuiltIn = true;
1460 BuiltIn = src.BuiltIn;
1461 }
1462
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001463 if(src.HasLocation)
Nicolas Capens157ba262019-12-10 17:49:14 -05001464 {
1465 HasLocation = true;
1466 Location = src.Location;
1467 }
1468
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001469 if(src.HasComponent)
Nicolas Capens157ba262019-12-10 17:49:14 -05001470 {
1471 HasComponent = true;
1472 Component = src.Component;
1473 }
1474
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001475 if(src.HasOffset)
Nicolas Capens157ba262019-12-10 17:49:14 -05001476 {
1477 HasOffset = true;
1478 Offset = src.Offset;
1479 }
1480
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001481 if(src.HasArrayStride)
Nicolas Capens157ba262019-12-10 17:49:14 -05001482 {
1483 HasArrayStride = true;
1484 ArrayStride = src.ArrayStride;
1485 }
1486
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001487 if(src.HasMatrixStride)
Nicolas Capens157ba262019-12-10 17:49:14 -05001488 {
1489 HasMatrixStride = true;
1490 MatrixStride = src.MatrixStride;
1491 }
1492
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001493 if(src.HasRowMajor)
Nicolas Capens157ba262019-12-10 17:49:14 -05001494 {
1495 HasRowMajor = true;
1496 RowMajor = src.RowMajor;
1497 }
1498
1499 Flat |= src.Flat;
1500 NoPerspective |= src.NoPerspective;
1501 Centroid |= src.Centroid;
1502 Block |= src.Block;
1503 BufferBlock |= src.BufferBlock;
1504 RelaxedPrecision |= src.RelaxedPrecision;
1505 InsideMatrix |= src.InsideMatrix;
1506}
1507
1508void SpirvShader::DescriptorDecorations::Apply(const sw::SpirvShader::DescriptorDecorations &src)
1509{
1510 if(src.DescriptorSet >= 0)
1511 {
1512 DescriptorSet = src.DescriptorSet;
1513 }
1514
1515 if(src.Binding >= 0)
1516 {
1517 Binding = src.Binding;
1518 }
1519
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001520 if(src.InputAttachmentIndex >= 0)
Nicolas Capens157ba262019-12-10 17:49:14 -05001521 {
1522 InputAttachmentIndex = src.InputAttachmentIndex;
1523 }
1524}
1525
1526void SpirvShader::ApplyDecorationsForId(Decorations *d, TypeOrObjectID id) const
1527{
1528 auto it = decorations.find(id);
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001529 if(it != decorations.end())
Nicolas Capens157ba262019-12-10 17:49:14 -05001530 d->Apply(it->second);
1531}
1532
1533void SpirvShader::ApplyDecorationsForIdMember(Decorations *d, Type::ID id, uint32_t member) const
1534{
1535 auto it = memberDecorations.find(id);
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001536 if(it != memberDecorations.end() && member < it->second.size())
Nicolas Capens157ba262019-12-10 17:49:14 -05001537 {
1538 d->Apply(it->second[member]);
1539 }
1540}
1541
1542void SpirvShader::DefineResult(const InsnIterator &insn)
1543{
1544 Type::ID typeId = insn.word(1);
1545 Object::ID resultId = insn.word(2);
1546 auto &object = defs[resultId];
Nicolas Capens157ba262019-12-10 17:49:14 -05001547
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001548 switch(getType(typeId).opcode())
Nicolas Capens157ba262019-12-10 17:49:14 -05001549 {
Nicolas Capens112faf42019-12-13 17:32:26 -05001550 case spv::OpTypePointer:
1551 case spv::OpTypeImage:
1552 case spv::OpTypeSampledImage:
1553 case spv::OpTypeSampler:
1554 object.kind = Object::Kind::Pointer;
1555 break;
Nicolas Capens157ba262019-12-10 17:49:14 -05001556
Nicolas Capens112faf42019-12-13 17:32:26 -05001557 default:
1558 object.kind = Object::Kind::Intermediate;
Nicolas Capens157ba262019-12-10 17:49:14 -05001559 }
1560
1561 object.definition = insn;
Ben Claytonb0ca2a82020-01-08 13:00:57 +00001562 dbgDeclareResult(insn, resultId);
Nicolas Capens157ba262019-12-10 17:49:14 -05001563}
1564
1565OutOfBoundsBehavior SpirvShader::EmitState::getOutOfBoundsBehavior(spv::StorageClass storageClass) const
1566{
1567 switch(storageClass)
1568 {
Nicolas Capens112faf42019-12-13 17:32:26 -05001569 case spv::StorageClassUniform:
1570 case spv::StorageClassStorageBuffer:
1571 // Buffer resource access. robustBufferAccess feature applies.
1572 return robustBufferAccess ? OutOfBoundsBehavior::RobustBufferAccess
1573 : OutOfBoundsBehavior::UndefinedBehavior;
1574
1575 case spv::StorageClassImage:
1576 // VK_EXT_image_robustness requires nullifying out-of-bounds accesses.
1577 // TODO(b/162327166): Only perform bounds checks when VK_EXT_image_robustness is enabled.
1578 return OutOfBoundsBehavior::Nullify;
1579
1580 case spv::StorageClassInput:
1581 if(executionModel == spv::ExecutionModelVertex)
1582 {
1583 // Vertex attributes follow robustBufferAccess rules.
Nicolas Capens157ba262019-12-10 17:49:14 -05001584 return robustBufferAccess ? OutOfBoundsBehavior::RobustBufferAccess
1585 : OutOfBoundsBehavior::UndefinedBehavior;
Nicolas Capens112faf42019-12-13 17:32:26 -05001586 }
1587 // Fall through to default case.
1588 default:
Nicolas Capense4b77942021-08-03 17:09:41 -04001589 // TODO(b/192310780): StorageClassFunction out-of-bounds accesses are undefined behavior.
Nicolas Capens112faf42019-12-13 17:32:26 -05001590 // TODO(b/137183137): Optimize if the pointer resulted from OpInBoundsAccessChain.
1591 // TODO(b/131224163): Optimize cases statically known to be within bounds.
1592 return OutOfBoundsBehavior::UndefinedValue;
Nicolas Capens157ba262019-12-10 17:49:14 -05001593 }
1594
1595 return OutOfBoundsBehavior::Nullify;
1596}
1597
1598// emit-time
1599
1600void SpirvShader::emitProlog(SpirvRoutine *routine) const
1601{
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001602 for(auto insn : *this)
Nicolas Capens157ba262019-12-10 17:49:14 -05001603 {
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001604 switch(insn.opcode())
Nicolas Capens157ba262019-12-10 17:49:14 -05001605 {
Nicolas Capens112faf42019-12-13 17:32:26 -05001606 case spv::OpVariable:
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001607 {
Nicolas Capens71186752020-04-09 01:05:31 -04001608 auto resultPointerType = getType(insn.resultTypeId());
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001609 auto pointeeType = getType(resultPointerType.element);
Nicolas Capens157ba262019-12-10 17:49:14 -05001610
Nicolas Capensff9f9b52020-04-14 00:46:38 -04001611 if(pointeeType.componentCount > 0) // TODO: what to do about zero-slot objects?
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001612 {
Nicolas Capensff9f9b52020-04-14 00:46:38 -04001613 routine->createVariable(insn.resultId(), pointeeType.componentCount);
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001614 }
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001615 }
Nicolas Capens112faf42019-12-13 17:32:26 -05001616 break;
1617
1618 case spv::OpPhi:
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001619 {
Nicolas Capens71186752020-04-09 01:05:31 -04001620 auto type = getType(insn.resultTypeId());
Nicolas Capensff9f9b52020-04-14 00:46:38 -04001621 routine->phis.emplace(insn.resultId(), SpirvRoutine::Variable(type.componentCount));
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001622 }
Nicolas Capens112faf42019-12-13 17:32:26 -05001623 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001624
Nicolas Capens112faf42019-12-13 17:32:26 -05001625 case spv::OpImageDrefGather:
1626 case spv::OpImageFetch:
1627 case spv::OpImageGather:
1628 case spv::OpImageQueryLod:
1629 case spv::OpImageSampleDrefExplicitLod:
1630 case spv::OpImageSampleDrefImplicitLod:
1631 case spv::OpImageSampleExplicitLod:
1632 case spv::OpImageSampleImplicitLod:
1633 case spv::OpImageSampleProjDrefExplicitLod:
1634 case spv::OpImageSampleProjDrefImplicitLod:
1635 case spv::OpImageSampleProjExplicitLod:
1636 case spv::OpImageSampleProjImplicitLod:
1637 routine->samplerCache.emplace(insn.resultId(), SpirvRoutine::SamplerCache{});
1638 break;
Nicolas Capens157ba262019-12-10 17:49:14 -05001639
Nicolas Capens112faf42019-12-13 17:32:26 -05001640 default:
1641 // Nothing else produces interface variables, so can all be safely ignored.
1642 break;
Nicolas Capens157ba262019-12-10 17:49:14 -05001643 }
1644 }
1645}
1646
Alexis Hetu0bcb71f2021-01-14 12:05:12 -05001647void SpirvShader::emit(SpirvRoutine *routine, RValue<SIMD::Int> const &activeLaneMask, RValue<SIMD::Int> const &storesAndAtomicsMask, const vk::DescriptorSet::Bindings &descriptorSets, unsigned int multiSampleCount) const
Nicolas Capens157ba262019-12-10 17:49:14 -05001648{
Alexis Hetu0bcb71f2021-01-14 12:05:12 -05001649 EmitState state(routine, entryPoint, activeLaneMask, storesAndAtomicsMask, descriptorSets, robustBufferAccess, multiSampleCount, executionModel);
Nicolas Capens157ba262019-12-10 17:49:14 -05001650
Ben Claytonb0ca2a82020-01-08 13:00:57 +00001651 dbgBeginEmit(&state);
1652 defer(dbgEndEmit(&state));
1653
Nicolas Capens157ba262019-12-10 17:49:14 -05001654 // Emit everything up to the first label
1655 // TODO: Separate out dispatch of block from non-block instructions?
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001656 for(auto insn : *this)
Nicolas Capens157ba262019-12-10 17:49:14 -05001657 {
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001658 if(insn.opcode() == spv::OpLabel)
Nicolas Capens157ba262019-12-10 17:49:14 -05001659 {
1660 break;
1661 }
1662 EmitInstruction(insn, &state);
1663 }
1664
1665 // Emit all the blocks starting from entryPoint.
1666 EmitBlocks(getFunction(entryPoint).entry, &state);
1667}
1668
1669void SpirvShader::EmitInstructions(InsnIterator begin, InsnIterator end, EmitState *state) const
1670{
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001671 for(auto insn = begin; insn != end; insn++)
Nicolas Capens157ba262019-12-10 17:49:14 -05001672 {
1673 auto res = EmitInstruction(insn, state);
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001674 switch(res)
Nicolas Capens157ba262019-12-10 17:49:14 -05001675 {
Nicolas Capens112faf42019-12-13 17:32:26 -05001676 case EmitResult::Continue:
1677 continue;
1678 case EmitResult::Terminator:
1679 break;
1680 default:
1681 UNREACHABLE("Unexpected EmitResult %d", int(res));
1682 break;
Nicolas Capens157ba262019-12-10 17:49:14 -05001683 }
1684 }
1685}
1686
1687SpirvShader::EmitResult SpirvShader::EmitInstruction(InsnIterator insn, EmitState *state) const
1688{
Ben Claytonb0ca2a82020-01-08 13:00:57 +00001689 dbgBeginEmitInstruction(insn, state);
1690 defer(dbgEndEmitInstruction(insn, state));
1691
Nicolas Capens157ba262019-12-10 17:49:14 -05001692 auto opcode = insn.opcode();
1693
Ben Claytonfc951cd2019-05-15 17:16:56 +01001694#if SPIRV_SHADER_ENABLE_DBG
1695 {
1696 auto text = spvtools::spvInstructionBinaryToText(
Sean Risser019feda2020-11-09 14:19:27 -05001697 vk::SPIRV_VERSION,
Ben Claytonfc951cd2019-05-15 17:16:56 +01001698 insn.wordPointer(0),
1699 insn.wordCount(),
1700 insns.data(),
1701 insns.size(),
1702 SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
1703 SPIRV_SHADER_DBG("{0}", text);
1704 }
1705#endif // ENABLE_DBG_MSGS
1706
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001707 switch(opcode)
Nicolas Capens157ba262019-12-10 17:49:14 -05001708 {
Nicolas Capens112faf42019-12-13 17:32:26 -05001709 case spv::OpTypeVoid:
1710 case spv::OpTypeInt:
1711 case spv::OpTypeFloat:
1712 case spv::OpTypeBool:
1713 case spv::OpTypeVector:
1714 case spv::OpTypeArray:
1715 case spv::OpTypeRuntimeArray:
1716 case spv::OpTypeMatrix:
1717 case spv::OpTypeStruct:
1718 case spv::OpTypePointer:
1719 case spv::OpTypeFunction:
1720 case spv::OpTypeImage:
1721 case spv::OpTypeSampledImage:
1722 case spv::OpTypeSampler:
1723 case spv::OpExecutionMode:
1724 case spv::OpMemoryModel:
1725 case spv::OpFunction:
1726 case spv::OpFunctionEnd:
1727 case spv::OpConstant:
1728 case spv::OpConstantNull:
1729 case spv::OpConstantTrue:
1730 case spv::OpConstantFalse:
1731 case spv::OpConstantComposite:
1732 case spv::OpSpecConstant:
1733 case spv::OpSpecConstantTrue:
1734 case spv::OpSpecConstantFalse:
1735 case spv::OpSpecConstantComposite:
1736 case spv::OpSpecConstantOp:
1737 case spv::OpUndef:
1738 case spv::OpExtension:
1739 case spv::OpCapability:
1740 case spv::OpEntryPoint:
1741 case spv::OpExtInstImport:
1742 case spv::OpDecorate:
1743 case spv::OpMemberDecorate:
1744 case spv::OpGroupDecorate:
1745 case spv::OpGroupMemberDecorate:
1746 case spv::OpDecorationGroup:
1747 case spv::OpDecorateId:
1748 case spv::OpDecorateString:
1749 case spv::OpMemberDecorateString:
1750 case spv::OpName:
1751 case spv::OpMemberName:
1752 case spv::OpSource:
1753 case spv::OpSourceContinued:
1754 case spv::OpSourceExtension:
1755 case spv::OpNoLine:
1756 case spv::OpModuleProcessed:
1757 case spv::OpString:
1758 // Nothing to do at emit time. These are either fully handled at analysis time,
1759 // or don't require any work at all.
1760 return EmitResult::Continue;
Nicolas Capens157ba262019-12-10 17:49:14 -05001761
Nicolas Capens112faf42019-12-13 17:32:26 -05001762 case spv::OpLine:
1763 return EmitLine(insn, state);
Ben Claytonb0ca2a82020-01-08 13:00:57 +00001764
Nicolas Capens112faf42019-12-13 17:32:26 -05001765 case spv::OpLabel:
1766 return EmitResult::Continue;
Nicolas Capens157ba262019-12-10 17:49:14 -05001767
Nicolas Capens112faf42019-12-13 17:32:26 -05001768 case spv::OpVariable:
1769 return EmitVariable(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001770
Nicolas Capens112faf42019-12-13 17:32:26 -05001771 case spv::OpLoad:
1772 case spv::OpAtomicLoad:
1773 return EmitLoad(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001774
Nicolas Capens112faf42019-12-13 17:32:26 -05001775 case spv::OpStore:
1776 case spv::OpAtomicStore:
1777 return EmitStore(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001778
Nicolas Capens112faf42019-12-13 17:32:26 -05001779 case spv::OpAtomicIAdd:
1780 case spv::OpAtomicISub:
1781 case spv::OpAtomicSMin:
1782 case spv::OpAtomicSMax:
1783 case spv::OpAtomicUMin:
1784 case spv::OpAtomicUMax:
1785 case spv::OpAtomicAnd:
1786 case spv::OpAtomicOr:
1787 case spv::OpAtomicXor:
1788 case spv::OpAtomicIIncrement:
1789 case spv::OpAtomicIDecrement:
1790 case spv::OpAtomicExchange:
1791 return EmitAtomicOp(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001792
Nicolas Capens112faf42019-12-13 17:32:26 -05001793 case spv::OpAtomicCompareExchange:
1794 return EmitAtomicCompareExchange(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001795
Nicolas Capens112faf42019-12-13 17:32:26 -05001796 case spv::OpAccessChain:
1797 case spv::OpInBoundsAccessChain:
1798 return EmitAccessChain(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001799
Nicolas Capens112faf42019-12-13 17:32:26 -05001800 case spv::OpCompositeConstruct:
1801 return EmitCompositeConstruct(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001802
Nicolas Capens112faf42019-12-13 17:32:26 -05001803 case spv::OpCompositeInsert:
1804 return EmitCompositeInsert(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001805
Nicolas Capens112faf42019-12-13 17:32:26 -05001806 case spv::OpCompositeExtract:
1807 return EmitCompositeExtract(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001808
Nicolas Capens112faf42019-12-13 17:32:26 -05001809 case spv::OpVectorShuffle:
1810 return EmitVectorShuffle(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001811
Nicolas Capens112faf42019-12-13 17:32:26 -05001812 case spv::OpVectorExtractDynamic:
1813 return EmitVectorExtractDynamic(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001814
Nicolas Capens112faf42019-12-13 17:32:26 -05001815 case spv::OpVectorInsertDynamic:
1816 return EmitVectorInsertDynamic(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001817
Nicolas Capens112faf42019-12-13 17:32:26 -05001818 case spv::OpVectorTimesScalar:
1819 case spv::OpMatrixTimesScalar:
1820 return EmitVectorTimesScalar(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001821
Nicolas Capens112faf42019-12-13 17:32:26 -05001822 case spv::OpMatrixTimesVector:
1823 return EmitMatrixTimesVector(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001824
Nicolas Capens112faf42019-12-13 17:32:26 -05001825 case spv::OpVectorTimesMatrix:
1826 return EmitVectorTimesMatrix(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001827
Nicolas Capens112faf42019-12-13 17:32:26 -05001828 case spv::OpMatrixTimesMatrix:
1829 return EmitMatrixTimesMatrix(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001830
Nicolas Capens112faf42019-12-13 17:32:26 -05001831 case spv::OpOuterProduct:
1832 return EmitOuterProduct(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001833
Nicolas Capens112faf42019-12-13 17:32:26 -05001834 case spv::OpTranspose:
1835 return EmitTranspose(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001836
Nicolas Capens112faf42019-12-13 17:32:26 -05001837 case spv::OpNot:
1838 case spv::OpBitFieldInsert:
1839 case spv::OpBitFieldSExtract:
1840 case spv::OpBitFieldUExtract:
1841 case spv::OpBitReverse:
1842 case spv::OpBitCount:
1843 case spv::OpSNegate:
1844 case spv::OpFNegate:
1845 case spv::OpLogicalNot:
1846 case spv::OpConvertFToU:
1847 case spv::OpConvertFToS:
1848 case spv::OpConvertSToF:
1849 case spv::OpConvertUToF:
1850 case spv::OpBitcast:
1851 case spv::OpIsInf:
1852 case spv::OpIsNan:
1853 case spv::OpDPdx:
1854 case spv::OpDPdxCoarse:
1855 case spv::OpDPdy:
1856 case spv::OpDPdyCoarse:
1857 case spv::OpFwidth:
1858 case spv::OpFwidthCoarse:
1859 case spv::OpDPdxFine:
1860 case spv::OpDPdyFine:
1861 case spv::OpFwidthFine:
1862 case spv::OpQuantizeToF16:
1863 return EmitUnaryOp(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001864
Nicolas Capens112faf42019-12-13 17:32:26 -05001865 case spv::OpIAdd:
1866 case spv::OpISub:
1867 case spv::OpIMul:
1868 case spv::OpSDiv:
1869 case spv::OpUDiv:
1870 case spv::OpFAdd:
1871 case spv::OpFSub:
1872 case spv::OpFMul:
1873 case spv::OpFDiv:
1874 case spv::OpFMod:
1875 case spv::OpFRem:
1876 case spv::OpFOrdEqual:
1877 case spv::OpFUnordEqual:
1878 case spv::OpFOrdNotEqual:
1879 case spv::OpFUnordNotEqual:
1880 case spv::OpFOrdLessThan:
1881 case spv::OpFUnordLessThan:
1882 case spv::OpFOrdGreaterThan:
1883 case spv::OpFUnordGreaterThan:
1884 case spv::OpFOrdLessThanEqual:
1885 case spv::OpFUnordLessThanEqual:
1886 case spv::OpFOrdGreaterThanEqual:
1887 case spv::OpFUnordGreaterThanEqual:
1888 case spv::OpSMod:
1889 case spv::OpSRem:
1890 case spv::OpUMod:
1891 case spv::OpIEqual:
1892 case spv::OpINotEqual:
1893 case spv::OpUGreaterThan:
1894 case spv::OpSGreaterThan:
1895 case spv::OpUGreaterThanEqual:
1896 case spv::OpSGreaterThanEqual:
1897 case spv::OpULessThan:
1898 case spv::OpSLessThan:
1899 case spv::OpULessThanEqual:
1900 case spv::OpSLessThanEqual:
1901 case spv::OpShiftRightLogical:
1902 case spv::OpShiftRightArithmetic:
1903 case spv::OpShiftLeftLogical:
1904 case spv::OpBitwiseOr:
1905 case spv::OpBitwiseXor:
1906 case spv::OpBitwiseAnd:
1907 case spv::OpLogicalOr:
1908 case spv::OpLogicalAnd:
1909 case spv::OpLogicalEqual:
1910 case spv::OpLogicalNotEqual:
1911 case spv::OpUMulExtended:
1912 case spv::OpSMulExtended:
1913 case spv::OpIAddCarry:
1914 case spv::OpISubBorrow:
1915 return EmitBinaryOp(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001916
Nicolas Capens112faf42019-12-13 17:32:26 -05001917 case spv::OpDot:
1918 return EmitDot(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001919
Nicolas Capens112faf42019-12-13 17:32:26 -05001920 case spv::OpSelect:
1921 return EmitSelect(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001922
Nicolas Capens112faf42019-12-13 17:32:26 -05001923 case spv::OpExtInst:
1924 return EmitExtendedInstruction(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001925
Nicolas Capens112faf42019-12-13 17:32:26 -05001926 case spv::OpAny:
1927 return EmitAny(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001928
Nicolas Capens112faf42019-12-13 17:32:26 -05001929 case spv::OpAll:
1930 return EmitAll(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001931
Nicolas Capens112faf42019-12-13 17:32:26 -05001932 case spv::OpBranch:
1933 return EmitBranch(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001934
Nicolas Capens112faf42019-12-13 17:32:26 -05001935 case spv::OpPhi:
1936 return EmitPhi(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001937
Nicolas Capens112faf42019-12-13 17:32:26 -05001938 case spv::OpSelectionMerge:
1939 case spv::OpLoopMerge:
1940 return EmitResult::Continue;
Nicolas Capens157ba262019-12-10 17:49:14 -05001941
Nicolas Capens112faf42019-12-13 17:32:26 -05001942 case spv::OpBranchConditional:
1943 return EmitBranchConditional(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001944
Nicolas Capens112faf42019-12-13 17:32:26 -05001945 case spv::OpSwitch:
1946 return EmitSwitch(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001947
Nicolas Capens112faf42019-12-13 17:32:26 -05001948 case spv::OpUnreachable:
1949 return EmitUnreachable(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001950
Nicolas Capens112faf42019-12-13 17:32:26 -05001951 case spv::OpReturn:
1952 return EmitReturn(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001953
Nicolas Capens112faf42019-12-13 17:32:26 -05001954 case spv::OpFunctionCall:
1955 return EmitFunctionCall(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001956
Nicolas Capens112faf42019-12-13 17:32:26 -05001957 case spv::OpKill:
1958 return EmitKill(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001959
Nicolas Capens112faf42019-12-13 17:32:26 -05001960 case spv::OpImageSampleImplicitLod:
1961 return EmitImageSampleImplicitLod(None, insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001962
Nicolas Capens112faf42019-12-13 17:32:26 -05001963 case spv::OpImageSampleExplicitLod:
1964 return EmitImageSampleExplicitLod(None, insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001965
Nicolas Capens112faf42019-12-13 17:32:26 -05001966 case spv::OpImageSampleDrefImplicitLod:
1967 return EmitImageSampleImplicitLod(Dref, insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001968
Nicolas Capens112faf42019-12-13 17:32:26 -05001969 case spv::OpImageSampleDrefExplicitLod:
1970 return EmitImageSampleExplicitLod(Dref, insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001971
Nicolas Capens112faf42019-12-13 17:32:26 -05001972 case spv::OpImageSampleProjImplicitLod:
1973 return EmitImageSampleImplicitLod(Proj, insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001974
Nicolas Capens112faf42019-12-13 17:32:26 -05001975 case spv::OpImageSampleProjExplicitLod:
1976 return EmitImageSampleExplicitLod(Proj, insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001977
Nicolas Capens112faf42019-12-13 17:32:26 -05001978 case spv::OpImageSampleProjDrefImplicitLod:
1979 return EmitImageSampleImplicitLod(ProjDref, insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001980
Nicolas Capens112faf42019-12-13 17:32:26 -05001981 case spv::OpImageSampleProjDrefExplicitLod:
1982 return EmitImageSampleExplicitLod(ProjDref, insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001983
Nicolas Capens112faf42019-12-13 17:32:26 -05001984 case spv::OpImageGather:
1985 return EmitImageGather(None, insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001986
Nicolas Capens112faf42019-12-13 17:32:26 -05001987 case spv::OpImageDrefGather:
1988 return EmitImageGather(Dref, insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001989
Nicolas Capens112faf42019-12-13 17:32:26 -05001990 case spv::OpImageFetch:
1991 return EmitImageFetch(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001992
Nicolas Capens112faf42019-12-13 17:32:26 -05001993 case spv::OpImageQuerySizeLod:
1994 return EmitImageQuerySizeLod(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001995
Nicolas Capens112faf42019-12-13 17:32:26 -05001996 case spv::OpImageQuerySize:
1997 return EmitImageQuerySize(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001998
Nicolas Capens112faf42019-12-13 17:32:26 -05001999 case spv::OpImageQueryLod:
2000 return EmitImageQueryLod(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002001
Nicolas Capens112faf42019-12-13 17:32:26 -05002002 case spv::OpImageQueryLevels:
2003 return EmitImageQueryLevels(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002004
Nicolas Capens112faf42019-12-13 17:32:26 -05002005 case spv::OpImageQuerySamples:
2006 return EmitImageQuerySamples(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002007
Nicolas Capens112faf42019-12-13 17:32:26 -05002008 case spv::OpImageRead:
2009 return EmitImageRead(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002010
Nicolas Capens112faf42019-12-13 17:32:26 -05002011 case spv::OpImageWrite:
2012 return EmitImageWrite(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002013
Nicolas Capens112faf42019-12-13 17:32:26 -05002014 case spv::OpImageTexelPointer:
2015 return EmitImageTexelPointer(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002016
Nicolas Capens112faf42019-12-13 17:32:26 -05002017 case spv::OpSampledImage:
2018 case spv::OpImage:
2019 return EmitSampledImageCombineOrSplit(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002020
Nicolas Capens112faf42019-12-13 17:32:26 -05002021 case spv::OpCopyObject:
2022 case spv::OpCopyLogical:
2023 return EmitCopyObject(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002024
Nicolas Capens112faf42019-12-13 17:32:26 -05002025 case spv::OpCopyMemory:
2026 return EmitCopyMemory(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002027
Nicolas Capens112faf42019-12-13 17:32:26 -05002028 case spv::OpControlBarrier:
2029 return EmitControlBarrier(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002030
Nicolas Capens112faf42019-12-13 17:32:26 -05002031 case spv::OpMemoryBarrier:
2032 return EmitMemoryBarrier(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002033
Nicolas Capens112faf42019-12-13 17:32:26 -05002034 case spv::OpGroupNonUniformElect:
2035 case spv::OpGroupNonUniformAll:
2036 case spv::OpGroupNonUniformAny:
2037 case spv::OpGroupNonUniformAllEqual:
2038 case spv::OpGroupNonUniformBroadcast:
2039 case spv::OpGroupNonUniformBroadcastFirst:
2040 case spv::OpGroupNonUniformBallot:
2041 case spv::OpGroupNonUniformInverseBallot:
2042 case spv::OpGroupNonUniformBallotBitExtract:
2043 case spv::OpGroupNonUniformBallotBitCount:
2044 case spv::OpGroupNonUniformBallotFindLSB:
2045 case spv::OpGroupNonUniformBallotFindMSB:
2046 case spv::OpGroupNonUniformShuffle:
2047 case spv::OpGroupNonUniformShuffleXor:
2048 case spv::OpGroupNonUniformShuffleUp:
2049 case spv::OpGroupNonUniformShuffleDown:
2050 case spv::OpGroupNonUniformIAdd:
2051 case spv::OpGroupNonUniformFAdd:
2052 case spv::OpGroupNonUniformIMul:
2053 case spv::OpGroupNonUniformFMul:
2054 case spv::OpGroupNonUniformSMin:
2055 case spv::OpGroupNonUniformUMin:
2056 case spv::OpGroupNonUniformFMin:
2057 case spv::OpGroupNonUniformSMax:
2058 case spv::OpGroupNonUniformUMax:
2059 case spv::OpGroupNonUniformFMax:
2060 case spv::OpGroupNonUniformBitwiseAnd:
2061 case spv::OpGroupNonUniformBitwiseOr:
2062 case spv::OpGroupNonUniformBitwiseXor:
2063 case spv::OpGroupNonUniformLogicalAnd:
2064 case spv::OpGroupNonUniformLogicalOr:
2065 case spv::OpGroupNonUniformLogicalXor:
2066 return EmitGroupNonUniform(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002067
Nicolas Capens112faf42019-12-13 17:32:26 -05002068 case spv::OpArrayLength:
2069 return EmitArrayLength(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002070
Nicolas Capens112faf42019-12-13 17:32:26 -05002071 default:
2072 UNREACHABLE("%s", OpcodeName(opcode));
2073 break;
Nicolas Capens157ba262019-12-10 17:49:14 -05002074 }
2075
2076 return EmitResult::Continue;
2077}
2078
2079SpirvShader::EmitResult SpirvShader::EmitAccessChain(InsnIterator insn, EmitState *state) const
2080{
2081 Type::ID typeId = insn.word(1);
2082 Object::ID resultId = insn.word(2);
2083 Object::ID baseId = insn.word(3);
2084 uint32_t numIndexes = insn.wordCount() - 4;
2085 const uint32_t *indexes = insn.wordPointer(4);
2086 auto &type = getType(typeId);
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002087 ASSERT(type.componentCount == 1);
Nicolas Capens157ba262019-12-10 17:49:14 -05002088 ASSERT(getObject(resultId).kind == Object::Kind::Pointer);
2089
2090 if(type.storageClass == spv::StorageClassPushConstant ||
2091 type.storageClass == spv::StorageClassUniform ||
2092 type.storageClass == spv::StorageClassStorageBuffer)
2093 {
2094 auto ptr = WalkExplicitLayoutAccessChain(baseId, numIndexes, indexes, state);
2095 state->createPointer(resultId, ptr);
2096 }
2097 else
2098 {
2099 auto ptr = WalkAccessChain(baseId, numIndexes, indexes, state);
2100 state->createPointer(resultId, ptr);
2101 }
2102
2103 return EmitResult::Continue;
2104}
2105
2106SpirvShader::EmitResult SpirvShader::EmitCompositeConstruct(InsnIterator insn, EmitState *state) const
2107{
Nicolas Capens71186752020-04-09 01:05:31 -04002108 auto &type = getType(insn.resultTypeId());
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002109 auto &dst = state->createIntermediate(insn.resultId(), type.componentCount);
Nicolas Capens157ba262019-12-10 17:49:14 -05002110 auto offset = 0u;
2111
Nicolas Capens81bc9d92019-12-16 15:05:57 -05002112 for(auto i = 0u; i < insn.wordCount() - 3; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002113 {
2114 Object::ID srcObjectId = insn.word(3u + i);
Ben Claytonbc1c067be2019-12-17 20:37:37 +00002115 auto &srcObject = getObject(srcObjectId);
Nicolas Capens72f089c2020-04-08 23:37:08 -04002116 auto &srcObjectTy = getType(srcObject);
Nicolas Capense6f65d92020-04-08 21:55:43 -04002117 Operand srcObjectAccess(this, state, srcObjectId);
Nicolas Capens157ba262019-12-10 17:49:14 -05002118
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002119 for(auto j = 0u; j < srcObjectTy.componentCount; j++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002120 {
2121 dst.move(offset++, srcObjectAccess.Float(j));
2122 }
2123 }
2124
2125 return EmitResult::Continue;
2126}
2127
2128SpirvShader::EmitResult SpirvShader::EmitCompositeInsert(InsnIterator insn, EmitState *state) const
2129{
2130 Type::ID resultTypeId = insn.word(1);
2131 auto &type = getType(resultTypeId);
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002132 auto &dst = state->createIntermediate(insn.resultId(), type.componentCount);
Nicolas Capens157ba262019-12-10 17:49:14 -05002133 auto &newPartObject = getObject(insn.word(3));
Nicolas Capens72f089c2020-04-08 23:37:08 -04002134 auto &newPartObjectTy = getType(newPartObject);
Nicolas Capens157ba262019-12-10 17:49:14 -05002135 auto firstNewComponent = WalkLiteralAccessChain(resultTypeId, insn.wordCount() - 5, insn.wordPointer(5));
2136
Nicolas Capense6f65d92020-04-08 21:55:43 -04002137 Operand srcObjectAccess(this, state, insn.word(4));
2138 Operand newPartObjectAccess(this, state, insn.word(3));
Nicolas Capens157ba262019-12-10 17:49:14 -05002139
2140 // old components before
Nicolas Capens81bc9d92019-12-16 15:05:57 -05002141 for(auto i = 0u; i < firstNewComponent; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002142 {
2143 dst.move(i, srcObjectAccess.Float(i));
2144 }
2145 // new part
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002146 for(auto i = 0u; i < newPartObjectTy.componentCount; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002147 {
2148 dst.move(firstNewComponent + i, newPartObjectAccess.Float(i));
2149 }
2150 // old components after
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002151 for(auto i = firstNewComponent + newPartObjectTy.componentCount; i < type.componentCount; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002152 {
2153 dst.move(i, srcObjectAccess.Float(i));
2154 }
2155
2156 return EmitResult::Continue;
2157}
2158
2159SpirvShader::EmitResult SpirvShader::EmitCompositeExtract(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 auto &compositeObject = getObject(insn.word(3));
2164 Type::ID compositeTypeId = compositeObject.definition.word(1);
2165 auto firstComponent = WalkLiteralAccessChain(compositeTypeId, insn.wordCount() - 4, insn.wordPointer(4));
2166
Nicolas Capense6f65d92020-04-08 21:55:43 -04002167 Operand compositeObjectAccess(this, state, insn.word(3));
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 dst.move(i, compositeObjectAccess.Float(firstComponent + i));
2171 }
2172
2173 return EmitResult::Continue;
2174}
2175
2176SpirvShader::EmitResult SpirvShader::EmitVectorShuffle(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 Capens157ba262019-12-10 17:49:14 -05002180
2181 // Note: number of components in result type, first half type, and second
2182 // half type are all independent.
Nicolas Capens72f089c2020-04-08 23:37:08 -04002183 auto &firstHalfType = getType(getObject(insn.word(3)));
Nicolas Capens157ba262019-12-10 17:49:14 -05002184
Nicolas Capense6f65d92020-04-08 21:55:43 -04002185 Operand firstHalfAccess(this, state, insn.word(3));
2186 Operand secondHalfAccess(this, state, insn.word(4));
Nicolas Capens157ba262019-12-10 17:49:14 -05002187
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002188 for(auto i = 0u; i < type.componentCount; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002189 {
2190 auto selector = insn.word(5 + i);
Nicolas Capens81bc9d92019-12-16 15:05:57 -05002191 if(selector == static_cast<uint32_t>(-1))
Nicolas Capens157ba262019-12-10 17:49:14 -05002192 {
2193 // Undefined value. Until we decide to do real undef values, zero is as good
2194 // a value as any
2195 dst.move(i, RValue<SIMD::Float>(0.0f));
2196 }
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002197 else if(selector < firstHalfType.componentCount)
Nicolas Capens157ba262019-12-10 17:49:14 -05002198 {
2199 dst.move(i, firstHalfAccess.Float(selector));
2200 }
2201 else
2202 {
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002203 dst.move(i, secondHalfAccess.Float(selector - firstHalfType.componentCount));
Nicolas Capens157ba262019-12-10 17:49:14 -05002204 }
2205 }
2206
2207 return EmitResult::Continue;
2208}
2209
2210SpirvShader::EmitResult SpirvShader::EmitVectorExtractDynamic(InsnIterator insn, EmitState *state) const
2211{
Nicolas Capens71186752020-04-09 01:05:31 -04002212 auto &type = getType(insn.resultTypeId());
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002213 auto &dst = state->createIntermediate(insn.resultId(), type.componentCount);
Nicolas Capens72f089c2020-04-08 23:37:08 -04002214 auto &srcType = getType(getObject(insn.word(3)));
Nicolas Capens157ba262019-12-10 17:49:14 -05002215
Nicolas Capense6f65d92020-04-08 21:55:43 -04002216 Operand src(this, state, insn.word(3));
2217 Operand index(this, state, insn.word(4));
Nicolas Capens157ba262019-12-10 17:49:14 -05002218
2219 SIMD::UInt v = SIMD::UInt(0);
2220
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002221 for(auto i = 0u; i < srcType.componentCount; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002222 {
2223 v |= CmpEQ(index.UInt(0), SIMD::UInt(i)) & src.UInt(i);
2224 }
2225
2226 dst.move(0, v);
2227 return EmitResult::Continue;
2228}
2229
2230SpirvShader::EmitResult SpirvShader::EmitVectorInsertDynamic(InsnIterator insn, EmitState *state) const
2231{
Nicolas Capens71186752020-04-09 01:05:31 -04002232 auto &type = getType(insn.resultTypeId());
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002233 auto &dst = state->createIntermediate(insn.resultId(), type.componentCount);
Nicolas Capens157ba262019-12-10 17:49:14 -05002234
Nicolas Capense6f65d92020-04-08 21:55:43 -04002235 Operand src(this, state, insn.word(3));
2236 Operand component(this, state, insn.word(4));
2237 Operand index(this, state, insn.word(5));
Nicolas Capens157ba262019-12-10 17:49:14 -05002238
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002239 for(auto i = 0u; i < type.componentCount; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002240 {
2241 SIMD::UInt mask = CmpEQ(SIMD::UInt(i), index.UInt(0));
2242 dst.move(i, (src.UInt(i) & ~mask) | (component.UInt(0) & mask));
2243 }
2244 return EmitResult::Continue;
2245}
2246
2247SpirvShader::EmitResult SpirvShader::EmitSelect(InsnIterator insn, EmitState *state) const
2248{
Nicolas Capens71186752020-04-09 01:05:31 -04002249 auto &type = getType(insn.resultTypeId());
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002250 auto &dst = state->createIntermediate(insn.resultId(), type.componentCount);
Nicolas Capense6f65d92020-04-08 21:55:43 -04002251 auto cond = Operand(this, state, insn.word(3));
Nicolas Capens2f4b6032020-04-09 02:01:50 -04002252 auto condIsScalar = (cond.componentCount == 1);
Nicolas Capense6f65d92020-04-08 21:55:43 -04002253 auto lhs = Operand(this, state, insn.word(4));
2254 auto rhs = Operand(this, state, insn.word(5));
Nicolas Capens157ba262019-12-10 17:49:14 -05002255
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002256 for(auto i = 0u; i < type.componentCount; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002257 {
2258 auto sel = cond.Int(condIsScalar ? 0 : i);
Ben Claytonbc1c067be2019-12-17 20:37:37 +00002259 dst.move(i, (sel & lhs.Int(i)) | (~sel & rhs.Int(i))); // TODO: IfThenElse()
Nicolas Capens157ba262019-12-10 17:49:14 -05002260 }
2261
Ben Claytonfc951cd2019-05-15 17:16:56 +01002262 SPIRV_SHADER_DBG("{0}: {1}", insn.word(2), dst);
2263 SPIRV_SHADER_DBG("{0}: {1}", insn.word(3), cond);
2264 SPIRV_SHADER_DBG("{0}: {1}", insn.word(4), lhs);
2265 SPIRV_SHADER_DBG("{0}: {1}", insn.word(5), rhs);
2266
Nicolas Capens157ba262019-12-10 17:49:14 -05002267 return EmitResult::Continue;
2268}
2269
2270SpirvShader::EmitResult SpirvShader::EmitAny(InsnIterator insn, EmitState *state) const
2271{
Nicolas Capens71186752020-04-09 01:05:31 -04002272 auto &type = getType(insn.resultTypeId());
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002273 ASSERT(type.componentCount == 1);
2274 auto &dst = state->createIntermediate(insn.resultId(), type.componentCount);
Nicolas Capens72f089c2020-04-08 23:37:08 -04002275 auto &srcType = getType(getObject(insn.word(3)));
Nicolas Capense6f65d92020-04-08 21:55:43 -04002276 auto src = Operand(this, state, insn.word(3));
Nicolas Capens157ba262019-12-10 17:49:14 -05002277
2278 SIMD::UInt result = src.UInt(0);
2279
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002280 for(auto i = 1u; i < srcType.componentCount; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002281 {
2282 result |= src.UInt(i);
2283 }
2284
2285 dst.move(0, result);
2286 return EmitResult::Continue;
2287}
2288
2289SpirvShader::EmitResult SpirvShader::EmitAll(InsnIterator insn, EmitState *state) const
2290{
Nicolas Capens71186752020-04-09 01:05:31 -04002291 auto &type = getType(insn.resultTypeId());
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002292 ASSERT(type.componentCount == 1);
2293 auto &dst = state->createIntermediate(insn.resultId(), type.componentCount);
Nicolas Capens72f089c2020-04-08 23:37:08 -04002294 auto &srcType = getType(getObject(insn.word(3)));
Nicolas Capense6f65d92020-04-08 21:55:43 -04002295 auto src = Operand(this, state, insn.word(3));
Nicolas Capens157ba262019-12-10 17:49:14 -05002296
2297 SIMD::UInt result = src.UInt(0);
2298
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002299 for(auto i = 1u; i < srcType.componentCount; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002300 {
2301 result &= src.UInt(i);
2302 }
2303
2304 dst.move(0, result);
2305 return EmitResult::Continue;
2306}
2307
2308SpirvShader::EmitResult SpirvShader::EmitAtomicOp(InsnIterator insn, EmitState *state) const
2309{
2310 auto &resultType = getType(Type::ID(insn.word(1)));
2311 Object::ID resultId = insn.word(2);
Nicolas Capens7c84c9e2020-07-24 22:13:44 -04002312 Object::ID pointerId = insn.word(3);
Nicolas Capens157ba262019-12-10 17:49:14 -05002313 Object::ID semanticsId = insn.word(5);
2314 auto memorySemantics = static_cast<spv::MemorySemanticsMask>(getObject(semanticsId).constantValue[0]);
2315 auto memoryOrder = MemoryOrder(memorySemantics);
2316 // Where no value is provided (increment/decrement) use an implicit value of 1.
Nicolas Capense6f65d92020-04-08 21:55:43 -04002317 auto value = (insn.wordCount() == 7) ? Operand(this, state, insn.word(6)).UInt(0) : RValue<SIMD::UInt>(1);
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002318 auto &dst = state->createIntermediate(resultId, resultType.componentCount);
Nicolas Capens7c84c9e2020-07-24 22:13:44 -04002319 auto ptr = state->getPointer(pointerId);
Nicolas Capens157ba262019-12-10 17:49:14 -05002320 auto ptrOffsets = ptr.offsets();
2321
Nicolas Capens7c84c9e2020-07-24 22:13:44 -04002322 SIMD::Int mask = state->activeLaneMask() & state->storesAndAtomicsMask();
2323
2324 if(getObject(pointerId).opcode() == spv::OpImageTexelPointer)
2325 {
2326 mask &= ptr.isInBounds(sizeof(int32_t), OutOfBoundsBehavior::Nullify);
2327 }
2328
2329 SIMD::UInt result(0);
Nicolas Capens81bc9d92019-12-16 15:05:57 -05002330 for(int j = 0; j < SIMD::Width; j++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002331 {
2332 If(Extract(mask, j) != 0)
2333 {
2334 auto offset = Extract(ptrOffsets, j);
2335 auto laneValue = Extract(value, j);
2336 UInt v;
Nicolas Capens81bc9d92019-12-16 15:05:57 -05002337 switch(insn.opcode())
Nicolas Capens157ba262019-12-10 17:49:14 -05002338 {
Nicolas Capens112faf42019-12-13 17:32:26 -05002339 case spv::OpAtomicIAdd:
2340 case spv::OpAtomicIIncrement:
2341 v = AddAtomic(Pointer<UInt>(&ptr.base[offset]), laneValue, memoryOrder);
2342 break;
2343 case spv::OpAtomicISub:
2344 case spv::OpAtomicIDecrement:
2345 v = SubAtomic(Pointer<UInt>(&ptr.base[offset]), laneValue, memoryOrder);
2346 break;
2347 case spv::OpAtomicAnd:
2348 v = AndAtomic(Pointer<UInt>(&ptr.base[offset]), laneValue, memoryOrder);
2349 break;
2350 case spv::OpAtomicOr:
2351 v = OrAtomic(Pointer<UInt>(&ptr.base[offset]), laneValue, memoryOrder);
2352 break;
2353 case spv::OpAtomicXor:
2354 v = XorAtomic(Pointer<UInt>(&ptr.base[offset]), laneValue, memoryOrder);
2355 break;
2356 case spv::OpAtomicSMin:
2357 v = As<UInt>(MinAtomic(Pointer<Int>(&ptr.base[offset]), As<Int>(laneValue), memoryOrder));
2358 break;
2359 case spv::OpAtomicSMax:
2360 v = As<UInt>(MaxAtomic(Pointer<Int>(&ptr.base[offset]), As<Int>(laneValue), memoryOrder));
2361 break;
2362 case spv::OpAtomicUMin:
2363 v = MinAtomic(Pointer<UInt>(&ptr.base[offset]), laneValue, memoryOrder);
2364 break;
2365 case spv::OpAtomicUMax:
2366 v = MaxAtomic(Pointer<UInt>(&ptr.base[offset]), laneValue, memoryOrder);
2367 break;
2368 case spv::OpAtomicExchange:
2369 v = ExchangeAtomic(Pointer<UInt>(&ptr.base[offset]), laneValue, memoryOrder);
2370 break;
2371 default:
2372 UNREACHABLE("%s", OpcodeName(insn.opcode()));
2373 break;
Nicolas Capens157ba262019-12-10 17:49:14 -05002374 }
Nicolas Capens7c84c9e2020-07-24 22:13:44 -04002375 result = Insert(result, v, j);
Nicolas Capens157ba262019-12-10 17:49:14 -05002376 }
2377 }
2378
Nicolas Capens7c84c9e2020-07-24 22:13:44 -04002379 dst.move(0, result);
Nicolas Capens157ba262019-12-10 17:49:14 -05002380 return EmitResult::Continue;
2381}
2382
2383SpirvShader::EmitResult SpirvShader::EmitAtomicCompareExchange(InsnIterator insn, EmitState *state) const
2384{
2385 // Separate from EmitAtomicOp due to different instruction encoding
2386 auto &resultType = getType(Type::ID(insn.word(1)));
2387 Object::ID resultId = insn.word(2);
2388
2389 auto memorySemanticsEqual = static_cast<spv::MemorySemanticsMask>(getObject(insn.word(5)).constantValue[0]);
2390 auto memoryOrderEqual = MemoryOrder(memorySemanticsEqual);
2391 auto memorySemanticsUnequal = static_cast<spv::MemorySemanticsMask>(getObject(insn.word(6)).constantValue[0]);
2392 auto memoryOrderUnequal = MemoryOrder(memorySemanticsUnequal);
2393
Nicolas Capense6f65d92020-04-08 21:55:43 -04002394 auto value = Operand(this, state, insn.word(7));
2395 auto comparator = Operand(this, state, insn.word(8));
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002396 auto &dst = state->createIntermediate(resultId, resultType.componentCount);
Nicolas Capens157ba262019-12-10 17:49:14 -05002397 auto ptr = state->getPointer(insn.word(3));
2398 auto ptrOffsets = ptr.offsets();
2399
2400 SIMD::UInt x(0);
2401 auto mask = state->activeLaneMask() & state->storesAndAtomicsMask();
Nicolas Capens81bc9d92019-12-16 15:05:57 -05002402 for(int j = 0; j < SIMD::Width; j++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002403 {
2404 If(Extract(mask, j) != 0)
2405 {
2406 auto offset = Extract(ptrOffsets, j);
2407 auto laneValue = Extract(value.UInt(0), j);
2408 auto laneComparator = Extract(comparator.UInt(0), j);
2409 UInt v = CompareExchangeAtomic(Pointer<UInt>(&ptr.base[offset]), laneValue, laneComparator, memoryOrderEqual, memoryOrderUnequal);
2410 x = Insert(x, v, j);
2411 }
2412 }
2413
2414 dst.move(0, x);
2415 return EmitResult::Continue;
2416}
2417
2418SpirvShader::EmitResult SpirvShader::EmitCopyObject(InsnIterator insn, EmitState *state) const
2419{
Nicolas Capens71186752020-04-09 01:05:31 -04002420 auto type = getType(insn.resultTypeId());
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002421 auto &dst = state->createIntermediate(insn.resultId(), type.componentCount);
Nicolas Capense6f65d92020-04-08 21:55:43 -04002422 auto src = Operand(this, state, insn.word(3));
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002423 for(uint32_t i = 0; i < type.componentCount; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002424 {
2425 dst.move(i, src.Int(i));
2426 }
2427 return EmitResult::Continue;
2428}
2429
2430SpirvShader::EmitResult SpirvShader::EmitArrayLength(InsnIterator insn, EmitState *state) const
2431{
Nicolas Capens157ba262019-12-10 17:49:14 -05002432 auto structPtrId = Object::ID(insn.word(3));
2433 auto arrayFieldIdx = insn.word(4);
2434
Nicolas Capens71186752020-04-09 01:05:31 -04002435 auto &resultType = getType(insn.resultTypeId());
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002436 ASSERT(resultType.componentCount == 1);
Nicolas Capens157ba262019-12-10 17:49:14 -05002437 ASSERT(resultType.definition.opcode() == spv::OpTypeInt);
2438
Nicolas Capens72f089c2020-04-08 23:37:08 -04002439 auto &structPtrTy = getType(getObject(structPtrId));
Nicolas Capens157ba262019-12-10 17:49:14 -05002440 auto &structTy = getType(structPtrTy.element);
Alexis Hetu74d3f372020-02-14 15:32:37 -05002441 auto arrayId = Type::ID(structTy.definition.word(2 + arrayFieldIdx));
Nicolas Capens157ba262019-12-10 17:49:14 -05002442
Nicolas Capens71186752020-04-09 01:05:31 -04002443 auto &result = state->createIntermediate(insn.resultId(), 1);
Nicolas Capens157ba262019-12-10 17:49:14 -05002444 auto structBase = GetPointerToData(structPtrId, 0, state);
2445
Alexis Hetu74d3f372020-02-14 15:32:37 -05002446 Decorations structDecorations = {};
2447 ApplyDecorationsForIdMember(&structDecorations, structPtrTy.element, arrayFieldIdx);
2448 ASSERT(structDecorations.HasOffset);
Nicolas Capens157ba262019-12-10 17:49:14 -05002449
Alexis Hetu74d3f372020-02-14 15:32:37 -05002450 auto arrayBase = structBase + structDecorations.Offset;
Nicolas Capens157ba262019-12-10 17:49:14 -05002451 auto arraySizeInBytes = SIMD::Int(arrayBase.limit()) - arrayBase.offsets();
Alexis Hetu74d3f372020-02-14 15:32:37 -05002452
2453 Decorations arrayDecorations = {};
2454 ApplyDecorationsForId(&arrayDecorations, arrayId);
2455 ASSERT(arrayDecorations.HasArrayStride);
2456 auto arrayLength = arraySizeInBytes / SIMD::Int(arrayDecorations.ArrayStride);
Nicolas Capens157ba262019-12-10 17:49:14 -05002457
2458 result.move(0, SIMD::Int(arrayLength));
2459
2460 return EmitResult::Continue;
2461}
2462
Ben Claytonb36dbbe2020-01-08 12:18:43 +00002463SpirvShader::EmitResult SpirvShader::EmitExtendedInstruction(InsnIterator insn, EmitState *state) const
2464{
2465 auto ext = getExtension(insn.word(3));
2466 switch(ext.name)
2467 {
Nicolas Capens112faf42019-12-13 17:32:26 -05002468 case Extension::GLSLstd450:
2469 return EmitExtGLSLstd450(insn, state);
2470 case Extension::OpenCLDebugInfo100:
2471 return EmitOpenCLDebugInfo100(insn, state);
2472 default:
2473 UNREACHABLE("Unknown Extension::Name<%d>", int(ext.name));
Ben Claytonb36dbbe2020-01-08 12:18:43 +00002474 }
2475 return EmitResult::Continue;
2476}
2477
Nicolas Capens157ba262019-12-10 17:49:14 -05002478uint32_t SpirvShader::GetConstScalarInt(Object::ID id) const
2479{
2480 auto &scopeObj = getObject(id);
2481 ASSERT(scopeObj.kind == Object::Kind::Constant);
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002482 ASSERT(getType(scopeObj).componentCount == 1);
Nicolas Capens157ba262019-12-10 17:49:14 -05002483 return scopeObj.constantValue[0];
2484}
2485
2486void SpirvShader::emitEpilog(SpirvRoutine *routine) const
2487{
Nicolas Capens81bc9d92019-12-16 15:05:57 -05002488 for(auto insn : *this)
Nicolas Capens157ba262019-12-10 17:49:14 -05002489 {
Nicolas Capens81bc9d92019-12-16 15:05:57 -05002490 switch(insn.opcode())
Nicolas Capens157ba262019-12-10 17:49:14 -05002491 {
Nicolas Capens112faf42019-12-13 17:32:26 -05002492 case spv::OpVariable:
Nicolas Capens157ba262019-12-10 17:49:14 -05002493 {
Nicolas Capens71186752020-04-09 01:05:31 -04002494 auto &object = getObject(insn.resultId());
Nicolas Capens72f089c2020-04-08 23:37:08 -04002495 auto &objectTy = getType(object);
Ben Claytonbc1c067be2019-12-17 20:37:37 +00002496 if(object.kind == Object::Kind::InterfaceVariable && objectTy.storageClass == spv::StorageClassOutput)
2497 {
Nicolas Capens71186752020-04-09 01:05:31 -04002498 auto &dst = routine->getVariable(insn.resultId());
Ben Claytonbc1c067be2019-12-17 20:37:37 +00002499 int offset = 0;
Nicolas Capens71186752020-04-09 01:05:31 -04002500 VisitInterface(insn.resultId(),
Ben Claytonbc1c067be2019-12-17 20:37:37 +00002501 [&](Decorations const &d, AttribType type) {
2502 auto scalarSlot = d.Location << 2 | d.Component;
2503 routine->outputs[scalarSlot] = dst[offset++];
2504 });
2505 }
Nicolas Capens157ba262019-12-10 17:49:14 -05002506 }
Nicolas Capens112faf42019-12-13 17:32:26 -05002507 break;
2508 default:
2509 break;
Nicolas Capens157ba262019-12-10 17:49:14 -05002510 }
2511 }
Alexis Hetu09df3eb2021-01-14 10:46:33 -05002512}
Nicolas Capens157ba262019-12-10 17:49:14 -05002513
Alexis Hetu09df3eb2021-01-14 10:46:33 -05002514void SpirvShader::clearPhis(SpirvRoutine *routine) const
2515{
Nicolas Capens157ba262019-12-10 17:49:14 -05002516 // Clear phis that are no longer used. This serves two purposes:
2517 // (1) The phi rr::Variables are destructed, preventing pointless
2518 // materialization.
2519 // (2) Frees memory that will never be used again.
2520 routine->phis.clear();
2521}
2522
2523VkShaderStageFlagBits SpirvShader::executionModelToStage(spv::ExecutionModel model)
2524{
Nicolas Capens81bc9d92019-12-16 15:05:57 -05002525 switch(model)
Nicolas Capens157ba262019-12-10 17:49:14 -05002526 {
Nicolas Capens112faf42019-12-13 17:32:26 -05002527 case spv::ExecutionModelVertex: return VK_SHADER_STAGE_VERTEX_BIT;
2528 // case spv::ExecutionModelTessellationControl: return VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
2529 // case spv::ExecutionModelTessellationEvaluation: return VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
2530 // case spv::ExecutionModelGeometry: return VK_SHADER_STAGE_GEOMETRY_BIT;
2531 case spv::ExecutionModelFragment: return VK_SHADER_STAGE_FRAGMENT_BIT;
2532 case spv::ExecutionModelGLCompute: return VK_SHADER_STAGE_COMPUTE_BIT;
2533 // case spv::ExecutionModelKernel: return VkShaderStageFlagBits(0); // Not supported by vulkan.
2534 // case spv::ExecutionModelTaskNV: return VK_SHADER_STAGE_TASK_BIT_NV;
2535 // case spv::ExecutionModelMeshNV: return VK_SHADER_STAGE_MESH_BIT_NV;
2536 // case spv::ExecutionModelRayGenerationNV: return VK_SHADER_STAGE_RAYGEN_BIT_NV;
2537 // case spv::ExecutionModelIntersectionNV: return VK_SHADER_STAGE_INTERSECTION_BIT_NV;
2538 // case spv::ExecutionModelAnyHitNV: return VK_SHADER_STAGE_ANY_HIT_BIT_NV;
2539 // case spv::ExecutionModelClosestHitNV: return VK_SHADER_STAGE_CLOSEST_HIT_BIT_NV;
2540 // case spv::ExecutionModelMissNV: return VK_SHADER_STAGE_MISS_BIT_NV;
2541 // case spv::ExecutionModelCallableNV: return VK_SHADER_STAGE_CALLABLE_BIT_NV;
2542 default:
2543 UNSUPPORTED("ExecutionModel: %d", int(model));
2544 return VkShaderStageFlagBits(0);
Nicolas Capens157ba262019-12-10 17:49:14 -05002545 }
2546}
2547
Nicolas Capens2f4b6032020-04-09 02:01:50 -04002548SpirvShader::Operand::Operand(const SpirvShader *shader, const EmitState *state, SpirvShader::Object::ID objectId)
2549 : Operand(state, shader->getObject(objectId))
Ben Claytonbc1c067be2019-12-17 20:37:37 +00002550{}
Nicolas Capens157ba262019-12-10 17:49:14 -05002551
Nicolas Capens2f4b6032020-04-09 02:01:50 -04002552SpirvShader::Operand::Operand(const EmitState *state, const Object &object)
Nicolas Capens3c0e0582020-08-26 11:04:37 -04002553 : constant(object.kind == SpirvShader::Object::Kind::Constant ? object.constantValue.data() : nullptr)
Nicolas Capens2f4b6032020-04-09 02:01:50 -04002554 , intermediate(object.kind == SpirvShader::Object::Kind::Intermediate ? &state->getIntermediate(object.id()) : nullptr)
2555 , componentCount(intermediate ? intermediate->componentCount : object.constantValue.size())
2556{
Nicolas Capens3c0e0582020-08-26 11:04:37 -04002557 ASSERT(intermediate || constant);
Nicolas Capens2f4b6032020-04-09 02:01:50 -04002558}
2559
Nicolas Capens20220a02020-04-09 02:48:16 -04002560SpirvShader::Operand::Operand(const Intermediate &value)
2561 : constant(nullptr)
2562 , intermediate(&value)
2563 , componentCount(value.componentCount)
2564{
2565}
2566
Nicolas Capens3c0e0582020-08-26 11:04:37 -04002567bool SpirvShader::Operand::isConstantZero() const
2568{
2569 if(!constant)
2570 {
2571 return false;
2572 }
2573
2574 for(uint32_t i = 0; i < componentCount; i++)
2575 {
2576 if(constant[i] != 0)
2577 {
2578 return false;
2579 }
2580 }
2581
2582 return true;
2583}
2584
Ben Claytonbc1c067be2019-12-17 20:37:37 +00002585SpirvRoutine::SpirvRoutine(vk::PipelineLayout const *pipelineLayout)
2586 : pipelineLayout(pipelineLayout)
Nicolas Capens157ba262019-12-10 17:49:14 -05002587{
2588}
2589
2590void SpirvRoutine::setImmutableInputBuiltins(SpirvShader const *shader)
2591{
Ben Claytonbc1c067be2019-12-17 20:37:37 +00002592 setInputBuiltin(shader, spv::BuiltInSubgroupLocalInvocationId, [&](const SpirvShader::BuiltinMapping &builtin, Array<SIMD::Float> &value) {
Nicolas Capens157ba262019-12-10 17:49:14 -05002593 ASSERT(builtin.SizeInComponents == 1);
2594 value[builtin.FirstComponent] = As<SIMD::Float>(SIMD::Int(0, 1, 2, 3));
2595 });
2596
Ben Claytonbc1c067be2019-12-17 20:37:37 +00002597 setInputBuiltin(shader, spv::BuiltInSubgroupEqMask, [&](const SpirvShader::BuiltinMapping &builtin, Array<SIMD::Float> &value) {
Nicolas Capens157ba262019-12-10 17:49:14 -05002598 ASSERT(builtin.SizeInComponents == 4);
2599 value[builtin.FirstComponent + 0] = As<SIMD::Float>(SIMD::Int(1, 2, 4, 8));
2600 value[builtin.FirstComponent + 1] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2601 value[builtin.FirstComponent + 2] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2602 value[builtin.FirstComponent + 3] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2603 });
2604
Ben Claytonbc1c067be2019-12-17 20:37:37 +00002605 setInputBuiltin(shader, spv::BuiltInSubgroupGeMask, [&](const SpirvShader::BuiltinMapping &builtin, Array<SIMD::Float> &value) {
Nicolas Capens157ba262019-12-10 17:49:14 -05002606 ASSERT(builtin.SizeInComponents == 4);
2607 value[builtin.FirstComponent + 0] = As<SIMD::Float>(SIMD::Int(15, 14, 12, 8));
2608 value[builtin.FirstComponent + 1] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2609 value[builtin.FirstComponent + 2] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2610 value[builtin.FirstComponent + 3] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2611 });
2612
Ben Claytonbc1c067be2019-12-17 20:37:37 +00002613 setInputBuiltin(shader, spv::BuiltInSubgroupGtMask, [&](const SpirvShader::BuiltinMapping &builtin, Array<SIMD::Float> &value) {
Nicolas Capens157ba262019-12-10 17:49:14 -05002614 ASSERT(builtin.SizeInComponents == 4);
2615 value[builtin.FirstComponent + 0] = As<SIMD::Float>(SIMD::Int(14, 12, 8, 0));
2616 value[builtin.FirstComponent + 1] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2617 value[builtin.FirstComponent + 2] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2618 value[builtin.FirstComponent + 3] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2619 });
2620
Ben Claytonbc1c067be2019-12-17 20:37:37 +00002621 setInputBuiltin(shader, spv::BuiltInSubgroupLeMask, [&](const SpirvShader::BuiltinMapping &builtin, Array<SIMD::Float> &value) {
Nicolas Capens157ba262019-12-10 17:49:14 -05002622 ASSERT(builtin.SizeInComponents == 4);
2623 value[builtin.FirstComponent + 0] = As<SIMD::Float>(SIMD::Int(1, 3, 7, 15));
2624 value[builtin.FirstComponent + 1] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2625 value[builtin.FirstComponent + 2] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2626 value[builtin.FirstComponent + 3] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2627 });
2628
Ben Claytonbc1c067be2019-12-17 20:37:37 +00002629 setInputBuiltin(shader, spv::BuiltInSubgroupLtMask, [&](const SpirvShader::BuiltinMapping &builtin, Array<SIMD::Float> &value) {
Nicolas Capens157ba262019-12-10 17:49:14 -05002630 ASSERT(builtin.SizeInComponents == 4);
2631 value[builtin.FirstComponent + 0] = As<SIMD::Float>(SIMD::Int(0, 1, 3, 7));
2632 value[builtin.FirstComponent + 1] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2633 value[builtin.FirstComponent + 2] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2634 value[builtin.FirstComponent + 3] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2635 });
2636
Ben Claytonbc1c067be2019-12-17 20:37:37 +00002637 setInputBuiltin(shader, spv::BuiltInDeviceIndex, [&](const SpirvShader::BuiltinMapping &builtin, Array<SIMD::Float> &value) {
Nicolas Capens157ba262019-12-10 17:49:14 -05002638 ASSERT(builtin.SizeInComponents == 1);
2639 // Only a single physical device is supported.
2640 value[builtin.FirstComponent] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2641 });
2642}
2643
2644} // namespace sw