blob: 3760358faafaf6ddaa43031a961e0708c12b555f [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 VkShaderStageFlagBits pipelineStage,
30 const char *entryPointName,
Nicolas Capens0c227672021-09-15 10:34:14 -040031 SpirvBinary const &insns,
Ben Claytonbc1c067be2019-12-17 20:37:37 +000032 const vk::RenderPass *renderPass,
33 uint32_t subpassIndex,
Ben Clayton7d0ce412019-12-03 13:26:31 +000034 bool robustBufferAccess,
35 const std::shared_ptr<vk::dbg::Context> &dbgctx)
Ben Claytonbc1c067be2019-12-17 20:37:37 +000036 : insns{ insns }
37 , inputs{ MAX_INTERFACE_COMPONENTS }
38 , outputs{ MAX_INTERFACE_COMPONENTS }
Ben Claytonbc1c067be2019-12-17 20:37:37 +000039 , robustBufferAccess(robustBufferAccess)
Chris Forbesaf4ed532018-12-06 18:33:27 -080040{
Nicolas Capens157ba262019-12-10 17:49:14 -050041 ASSERT(insns.size() > 0);
Ben Clayton9e4bc1b2019-04-16 16:52:02 -040042
Ben Claytonb0ca2a82020-01-08 13:00:57 +000043 if(dbgctx)
44 {
45 dbgInit(dbgctx);
46 }
47
Nicolas Capens81bc9d92019-12-16 15:05:57 -050048 if(renderPass)
Chris Forbesaf4ed532018-12-06 18:33:27 -080049 {
Nicolas Capens157ba262019-12-10 17:49:14 -050050 // capture formats of any input attachments present
51 auto subpass = renderPass->getSubpass(subpassIndex);
52 inputAttachmentFormats.reserve(subpass.inputAttachmentCount);
Nicolas Capens81bc9d92019-12-16 15:05:57 -050053 for(auto i = 0u; i < subpass.inputAttachmentCount; i++)
Chris Forbes24466042019-04-22 10:54:23 -070054 {
Nicolas Capens157ba262019-12-10 17:49:14 -050055 auto attachmentIndex = subpass.pInputAttachments[i].attachment;
56 inputAttachmentFormats.push_back(attachmentIndex != VK_ATTACHMENT_UNUSED
Ben Claytonbc1c067be2019-12-17 20:37:37 +000057 ? renderPass->getAttachment(attachmentIndex).format
58 : VK_FORMAT_UNDEFINED);
Ben Clayton64f78f52019-03-21 17:21:06 +000059 }
Chris Forbesaf4ed532018-12-06 18:33:27 -080060 }
61
Ben Clayton964b9e32021-06-25 09:00:22 +010062 // The identifiers of all OpVariables that define the entry point's IO variables.
63 std::unordered_set<Object::ID> interfaceIds;
Nicolas Capens157ba262019-12-10 17:49:14 -050064
65 Function::ID currentFunction;
66 Block::ID currentBlock;
67 InsnIterator blockStart;
68
Nicolas Capens81bc9d92019-12-16 15:05:57 -050069 for(auto insn : *this)
Ben Clayton0bb83b82019-02-26 11:41:07 +000070 {
Nicolas Capens157ba262019-12-10 17:49:14 -050071 spv::Op opcode = insn.opcode();
Nicolas Capens82eb22e2019-04-10 01:15:43 -040072
Nicolas Capens81bc9d92019-12-16 15:05:57 -050073 switch(opcode)
Ben Clayton9b156612019-03-13 19:48:31 +000074 {
Nicolas Capens112faf42019-12-13 17:32:26 -050075 case spv::OpEntryPoint:
Nicolas Capens157ba262019-12-10 17:49:14 -050076 {
Nicolas Capens5806db92021-09-27 07:07:27 +000077 spv::ExecutionModel executionModel = spv::ExecutionModel(insn.word(1));
78 Function::ID entryPoint = Function::ID(insn.word(2));
79 const char *name = insn.string(3);
80 VkShaderStageFlagBits stage = executionModelToStage(executionModel);
81
Ben Claytonbc1c067be2019-12-17 20:37:37 +000082 if(stage == pipelineStage && strcmp(name, entryPointName) == 0)
83 {
Nicolas Capens5806db92021-09-27 07:07:27 +000084 ASSERT_MSG(this->entryPoint == 0, "Duplicate entry point with name '%s' and stage %d", name, int(stage));
85 this->entryPoint = entryPoint;
86 this->executionModel = executionModel;
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:
Nicolas Capens15941842021-08-13 15:24:28 -0400121 analysis.ContainsSampleQualifier = true;
Nicolas Capens112faf42019-12-13 17:32:26 -0500122 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 {
Nicolas Capens15941842021-08-13 15:24:28 -0400130 analysis.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 {
Nicolas Capens15941842021-08-13 15:24:28 -0400150 analysis.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:
Nicolas Capens4fd9ef92022-01-14 16:11:27 -0500168 {
169 auto decoration = static_cast<spv::Decoration>(insn.word(2));
170
171 // We assume these are for HLSL semantics, ignore them (b/214576937).
172 ASSERT(decoration == spv::DecorationUserSemantic);
173 }
174 break;
175
Nicolas Capens112faf42019-12-13 17:32:26 -0500176 case spv::OpMemberDecorateString:
Nicolas Capens4fd9ef92022-01-14 16:11:27 -0500177 {
178 auto decoration = static_cast<spv::Decoration>(insn.word(3));
179
180 // We assume these are for HLSL semantics, ignore them (b/214576937).
181 ASSERT(decoration == spv::DecorationUserSemantic);
182 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500183 break;
Sean Risser79a271a2020-12-02 16:56:03 -0500184
Nicolas Capens112faf42019-12-13 17:32:26 -0500185 case spv::OpDecorationGroup:
186 // Nothing to do here. We don't need to record the definition of the group; we'll just have
187 // the bundle of decorations float around. If we were to ever walk the decorations directly,
188 // we might think about introducing this as a real Object.
189 break;
Nicolas Capens157ba262019-12-10 17:49:14 -0500190
Nicolas Capens112faf42019-12-13 17:32:26 -0500191 case spv::OpGroupDecorate:
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000192 {
193 uint32_t group = insn.word(1);
194 auto const &groupDecorations = decorations[group];
195 auto const &descriptorGroupDecorations = descriptorDecorations[group];
196 for(auto i = 2u; i < insn.wordCount(); i++)
197 {
198 // Remaining operands are targets to apply the group to.
199 uint32_t target = insn.word(i);
200 decorations[target].Apply(groupDecorations);
201 descriptorDecorations[target].Apply(descriptorGroupDecorations);
202 }
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000203 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500204 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000205
Nicolas Capens112faf42019-12-13 17:32:26 -0500206 case spv::OpGroupMemberDecorate:
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000207 {
208 auto const &srcDecorations = decorations[insn.word(1)];
209 for(auto i = 2u; i < insn.wordCount(); i += 2)
210 {
211 // remaining operands are pairs of <id>, literal for members to apply to.
212 auto &d = memberDecorations[insn.word(i)];
213 auto memberIndex = insn.word(i + 1);
214 if(memberIndex >= d.size())
215 d.resize(memberIndex + 1); // on demand resize, see above...
216 d[memberIndex].Apply(srcDecorations);
217 }
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000218 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500219 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000220
Nicolas Capens112faf42019-12-13 17:32:26 -0500221 case spv::OpLabel:
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000222 {
Nicolas Capensff9bb522021-11-08 21:29:29 -0500223 ASSERT(currentBlock == 0);
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000224 currentBlock = Block::ID(insn.word(1));
225 blockStart = insn;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000226 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500227 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000228
Nicolas Capens112faf42019-12-13 17:32:26 -0500229 // Branch Instructions (subset of Termination Instructions):
230 case spv::OpBranch:
231 case spv::OpBranchConditional:
232 case spv::OpSwitch:
233 case spv::OpReturn:
234 // [[fallthrough]]
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000235
Nicolas Capens112faf42019-12-13 17:32:26 -0500236 // Termination instruction:
237 case spv::OpKill:
238 case spv::OpUnreachable:
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000239 {
Nicolas Capensff9bb522021-11-08 21:29:29 -0500240 ASSERT(currentBlock != 0);
241 ASSERT(currentFunction != 0);
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000242
243 auto blockEnd = insn;
244 blockEnd++;
245 functions[currentFunction].blocks[currentBlock] = Block(blockStart, blockEnd);
246 currentBlock = Block::ID(0);
247
248 if(opcode == spv::OpKill)
249 {
Nicolas Capens15941842021-08-13 15:24:28 -0400250 analysis.ContainsKill = true;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000251 }
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000252 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500253 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000254
Nicolas Capens112faf42019-12-13 17:32:26 -0500255 case spv::OpLoopMerge:
256 case spv::OpSelectionMerge:
257 break; // Nothing to do in analysis pass.
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000258
Nicolas Capens112faf42019-12-13 17:32:26 -0500259 case spv::OpTypeVoid:
260 case spv::OpTypeBool:
261 case spv::OpTypeInt:
262 case spv::OpTypeFloat:
263 case spv::OpTypeVector:
264 case spv::OpTypeMatrix:
265 case spv::OpTypeImage:
266 case spv::OpTypeSampler:
267 case spv::OpTypeSampledImage:
268 case spv::OpTypeArray:
269 case spv::OpTypeRuntimeArray:
270 case spv::OpTypeStruct:
271 case spv::OpTypePointer:
272 case spv::OpTypeFunction:
273 DeclareType(insn);
274 break;
Nicolas Capens157ba262019-12-10 17:49:14 -0500275
Nicolas Capens112faf42019-12-13 17:32:26 -0500276 case spv::OpVariable:
Nicolas Capens157ba262019-12-10 17:49:14 -0500277 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000278 Type::ID typeId = insn.word(1);
279 Object::ID resultId = insn.word(2);
280 auto storageClass = static_cast<spv::StorageClass>(insn.word(3));
281
282 auto &object = defs[resultId];
Nicolas Capens157ba262019-12-10 17:49:14 -0500283 object.kind = Object::Kind::Pointer;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000284 object.definition = insn;
Nicolas Capens157ba262019-12-10 17:49:14 -0500285
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000286 ASSERT(getType(typeId).definition.opcode() == spv::OpTypePointer);
287 ASSERT(getType(typeId).storageClass == storageClass);
Nicolas Capens157ba262019-12-10 17:49:14 -0500288
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000289 switch(storageClass)
Nicolas Capens157ba262019-12-10 17:49:14 -0500290 {
Nicolas Capens112faf42019-12-13 17:32:26 -0500291 case spv::StorageClassInput:
292 case spv::StorageClassOutput:
Ben Clayton964b9e32021-06-25 09:00:22 +0100293 if(interfaceIds.count(resultId))
294 {
295 ProcessInterfaceVariable(object);
296 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500297 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000298
Nicolas Capens112faf42019-12-13 17:32:26 -0500299 case spv::StorageClassUniform:
300 case spv::StorageClassStorageBuffer:
301 object.kind = Object::Kind::DescriptorSet;
302 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000303
Nicolas Capens112faf42019-12-13 17:32:26 -0500304 case spv::StorageClassPushConstant:
305 case spv::StorageClassPrivate:
306 case spv::StorageClassFunction:
307 case spv::StorageClassUniformConstant:
308 break; // Correctly handled.
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000309
Nicolas Capens112faf42019-12-13 17:32:26 -0500310 case spv::StorageClassWorkgroup:
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000311 {
312 auto &elTy = getType(getType(typeId).element);
Nicolas Capensff9f9b52020-04-14 00:46:38 -0400313 auto sizeInBytes = elTy.componentCount * static_cast<uint32_t>(sizeof(float));
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000314 workgroupMemory.allocate(resultId, sizeInBytes);
315 object.kind = Object::Kind::Pointer;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000316 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500317 break;
318 case spv::StorageClassAtomicCounter:
319 case spv::StorageClassImage:
320 UNSUPPORTED("StorageClass %d not yet supported", (int)storageClass);
321 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000322
Nicolas Capens112faf42019-12-13 17:32:26 -0500323 case spv::StorageClassCrossWorkgroup:
324 UNSUPPORTED("SPIR-V OpenCL Execution Model (StorageClassCrossWorkgroup)");
325 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000326
Nicolas Capens112faf42019-12-13 17:32:26 -0500327 case spv::StorageClassGeneric:
328 UNSUPPORTED("SPIR-V GenericPointer Capability (StorageClassGeneric)");
329 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000330
Nicolas Capens112faf42019-12-13 17:32:26 -0500331 default:
332 UNREACHABLE("Unexpected StorageClass %d", storageClass); // See Appendix A of the Vulkan spec.
333 break;
Nicolas Capens157ba262019-12-10 17:49:14 -0500334 }
335 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500336 break;
Nicolas Capens157ba262019-12-10 17:49:14 -0500337
Nicolas Capens112faf42019-12-13 17:32:26 -0500338 case spv::OpConstant:
339 case spv::OpSpecConstant:
340 CreateConstant(insn).constantValue[0] = insn.word(3);
341 break;
342 case spv::OpConstantFalse:
343 case spv::OpSpecConstantFalse:
344 CreateConstant(insn).constantValue[0] = 0; // Represent Boolean false as zero.
345 break;
346 case spv::OpConstantTrue:
347 case spv::OpSpecConstantTrue:
348 CreateConstant(insn).constantValue[0] = ~0u; // Represent Boolean true as all bits set.
349 break;
350 case spv::OpConstantNull:
351 case spv::OpUndef:
Nicolas Capens157ba262019-12-10 17:49:14 -0500352 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000353 // TODO: consider a real LLVM-level undef. For now, zero is a perfectly good value.
354 // OpConstantNull forms a constant of arbitrary type, all zeros.
355 auto &object = CreateConstant(insn);
Nicolas Capens72f089c2020-04-08 23:37:08 -0400356 auto &objectTy = getType(object);
Nicolas Capensff9f9b52020-04-14 00:46:38 -0400357 for(auto i = 0u; i < objectTy.componentCount; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -0500358 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000359 object.constantValue[i] = 0;
Nicolas Capens157ba262019-12-10 17:49:14 -0500360 }
361 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500362 break;
363 case spv::OpConstantComposite:
364 case spv::OpSpecConstantComposite:
Nicolas Capens157ba262019-12-10 17:49:14 -0500365 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000366 auto &object = CreateConstant(insn);
367 auto offset = 0u;
368 for(auto i = 0u; i < insn.wordCount() - 3; i++)
369 {
370 auto &constituent = getObject(insn.word(i + 3));
Nicolas Capens72f089c2020-04-08 23:37:08 -0400371 auto &constituentTy = getType(constituent);
Nicolas Capensff9f9b52020-04-14 00:46:38 -0400372 for(auto j = 0u; j < constituentTy.componentCount; j++)
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000373 {
374 object.constantValue[offset++] = constituent.constantValue[j];
375 }
376 }
377
378 auto objectId = Object::ID(insn.word(2));
379 auto decorationsIt = decorations.find(objectId);
380 if(decorationsIt != decorations.end() &&
381 decorationsIt->second.BuiltIn == spv::BuiltInWorkgroupSize)
382 {
383 // https://www.khronos.org/registry/vulkan/specs/1.1/html/vkspec.html#interfaces-builtin-variables :
384 // Decorating an object with the WorkgroupSize built-in
385 // decoration will make that object contain the dimensions
386 // of a local workgroup. If an object is decorated with the
387 // WorkgroupSize decoration, this must take precedence over
388 // any execution mode set for LocalSize.
389 // The object decorated with WorkgroupSize must be declared
390 // as a three-component vector of 32-bit integers.
Nicolas Capensff9f9b52020-04-14 00:46:38 -0400391 ASSERT(getType(object).componentCount == 3);
Nicolas Capens15941842021-08-13 15:24:28 -0400392 executionModes.WorkgroupSizeX = object.constantValue[0];
393 executionModes.WorkgroupSizeY = object.constantValue[1];
394 executionModes.WorkgroupSizeZ = object.constantValue[2];
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000395 }
Nicolas Capens157ba262019-12-10 17:49:14 -0500396 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500397 break;
398 case spv::OpSpecConstantOp:
399 EvalSpecConstantOp(insn);
400 break;
Ben Clayton9b156612019-03-13 19:48:31 +0000401
Nicolas Capens112faf42019-12-13 17:32:26 -0500402 case spv::OpCapability:
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000403 {
404 auto capability = static_cast<spv::Capability>(insn.word(1));
405 switch(capability)
406 {
Nicolas Capens112faf42019-12-13 17:32:26 -0500407 case spv::CapabilityMatrix: capabilities.Matrix = true; break;
408 case spv::CapabilityShader: capabilities.Shader = true; break;
409 case spv::CapabilityStorageImageMultisample: capabilities.StorageImageMultisample = true; break;
410 case spv::CapabilityClipDistance: capabilities.ClipDistance = true; break;
411 case spv::CapabilityCullDistance: capabilities.CullDistance = true; break;
412 case spv::CapabilityImageCubeArray: capabilities.ImageCubeArray = true; break;
413 case spv::CapabilitySampleRateShading: capabilities.SampleRateShading = true; break;
414 case spv::CapabilityInputAttachment: capabilities.InputAttachment = true; break;
415 case spv::CapabilitySampled1D: capabilities.Sampled1D = true; break;
416 case spv::CapabilityImage1D: capabilities.Image1D = true; break;
417 case spv::CapabilitySampledBuffer: capabilities.SampledBuffer = true; break;
418 case spv::CapabilitySampledCubeArray: capabilities.SampledCubeArray = true; break;
419 case spv::CapabilityImageBuffer: capabilities.ImageBuffer = true; break;
420 case spv::CapabilityImageMSArray: capabilities.ImageMSArray = true; break;
421 case spv::CapabilityStorageImageExtendedFormats: capabilities.StorageImageExtendedFormats = true; break;
422 case spv::CapabilityImageQuery: capabilities.ImageQuery = true; break;
423 case spv::CapabilityDerivativeControl: capabilities.DerivativeControl = true; break;
424 case spv::CapabilityInterpolationFunction: capabilities.InterpolationFunction = true; break;
Nicolas Capensf0e8ec22021-11-12 13:57:14 -0500425 case spv::CapabilityStorageImageWriteWithoutFormat: capabilities.StorageImageWriteWithoutFormat = true; break;
Nicolas Capens112faf42019-12-13 17:32:26 -0500426 case spv::CapabilityGroupNonUniform: capabilities.GroupNonUniform = true; break;
427 case spv::CapabilityGroupNonUniformVote: capabilities.GroupNonUniformVote = true; break;
428 case spv::CapabilityGroupNonUniformArithmetic: capabilities.GroupNonUniformArithmetic = true; break;
429 case spv::CapabilityGroupNonUniformBallot: capabilities.GroupNonUniformBallot = true; break;
430 case spv::CapabilityGroupNonUniformShuffle: capabilities.GroupNonUniformShuffle = true; break;
431 case spv::CapabilityGroupNonUniformShuffleRelative: capabilities.GroupNonUniformShuffleRelative = true; break;
432 case spv::CapabilityDeviceGroup: capabilities.DeviceGroup = true; break;
433 case spv::CapabilityMultiView: capabilities.MultiView = true; break;
434 case spv::CapabilityStencilExportEXT: capabilities.StencilExportEXT = true; break;
Nicolas Capens4c629802021-12-08 02:05:19 -0500435 case spv::CapabilityVulkanMemoryModel: capabilities.VulkanMemoryModel = true; break;
436 case spv::CapabilityVulkanMemoryModelDeviceScope: capabilities.VulkanMemoryModelDeviceScope = true; break;
Nicolas Capens112faf42019-12-13 17:32:26 -0500437 default:
438 UNSUPPORTED("Unsupported capability %u", insn.word(1));
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000439 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500440
441 // Various capabilities will be declared, but none affect our code generation at this point.
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000442 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500443 break;
Ben Clayton9b156612019-03-13 19:48:31 +0000444
Nicolas Capens112faf42019-12-13 17:32:26 -0500445 case spv::OpMemoryModel:
Nicolas Capens4c629802021-12-08 02:05:19 -0500446 {
447 addressingModel = static_cast<spv::AddressingModel>(insn.word(1));
448 memoryModel = static_cast<spv::MemoryModel>(insn.word(2));
449 }
450 break;
Nicolas Capens157ba262019-12-10 17:49:14 -0500451
Nicolas Capens112faf42019-12-13 17:32:26 -0500452 case spv::OpFunction:
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000453 {
454 auto functionId = Function::ID(insn.word(2));
455 ASSERT_MSG(currentFunction == 0, "Functions %d and %d overlap", currentFunction.value(), functionId.value());
456 currentFunction = functionId;
457 auto &function = functions[functionId];
458 function.result = Type::ID(insn.word(1));
459 function.type = Type::ID(insn.word(4));
460 // Scan forward to find the function's label.
Ben Clayton7d098242020-03-13 13:07:12 +0000461 for(auto it = insn; it != end(); it++)
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000462 {
Ben Clayton7d098242020-03-13 13:07:12 +0000463 if(it.opcode() == spv::OpLabel)
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000464 {
Ben Clayton7d098242020-03-13 13:07:12 +0000465 function.entry = Block::ID(it.word(1));
466 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000467 }
468 }
469 ASSERT_MSG(function.entry != 0, "Function<%d> has no label", currentFunction.value());
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000470 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500471 break;
Nicolas Capens157ba262019-12-10 17:49:14 -0500472
Nicolas Capens112faf42019-12-13 17:32:26 -0500473 case spv::OpFunctionEnd:
474 currentFunction = 0;
475 break;
Nicolas Capens157ba262019-12-10 17:49:14 -0500476
Nicolas Capens112faf42019-12-13 17:32:26 -0500477 case spv::OpExtInstImport:
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000478 {
Ben Clayton683bad82020-02-10 23:57:09 +0000479 static constexpr std::pair<const char *, Extension::Name> extensionsByName[] = {
Ben Claytonf6a6a412020-01-09 16:43:37 +0000480 { "GLSL.std.450", Extension::GLSLstd450 },
Ben Claytoncd55f052020-01-14 11:56:00 +0000481 { "OpenCL.DebugInfo.100", Extension::OpenCLDebugInfo100 },
Ben Claytonf6a6a412020-01-09 16:43:37 +0000482 };
Ben Clayton683bad82020-02-10 23:57:09 +0000483 static constexpr auto extensionCount = sizeof(extensionsByName) / sizeof(extensionsByName[0]);
484
Ben Claytonb36dbbe2020-01-08 12:18:43 +0000485 auto id = Extension::ID(insn.word(1));
486 auto name = insn.string(2);
487 auto ext = Extension{ Extension::Unknown };
Ben Clayton683bad82020-02-10 23:57:09 +0000488 for(size_t i = 0; i < extensionCount; i++)
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000489 {
Ben Clayton683bad82020-02-10 23:57:09 +0000490 if(0 == strcmp(name, extensionsByName[i].first))
Ben Claytonb36dbbe2020-01-08 12:18:43 +0000491 {
Ben Clayton683bad82020-02-10 23:57:09 +0000492 ext = Extension{ extensionsByName[i].second };
Ben Claytonb36dbbe2020-01-08 12:18:43 +0000493 break;
494 }
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000495 }
Ben Claytonb36dbbe2020-01-08 12:18:43 +0000496 if(ext.name == Extension::Unknown)
497 {
498 UNSUPPORTED("SPIR-V Extension: %s", name);
499 break;
500 }
Ben Clayton8842c8f2020-01-13 16:57:48 +0000501 extensionsByID.emplace(id, ext);
502 extensionsImported.emplace(ext.name);
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000503 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500504 break;
505 case spv::OpName:
506 case spv::OpMemberName:
507 case spv::OpSource:
508 case spv::OpSourceContinued:
509 case spv::OpSourceExtension:
510 case spv::OpLine:
511 case spv::OpNoLine:
512 case spv::OpModuleProcessed:
513 // No semantic impact
514 break;
Ben Clayton9b156612019-03-13 19:48:31 +0000515
Nicolas Capens112faf42019-12-13 17:32:26 -0500516 case spv::OpString:
517 strings.emplace(insn.word(1), insn.string(2));
518 break;
Ben Clayton9c8823a2020-01-08 12:07:30 +0000519
Nicolas Capens112faf42019-12-13 17:32:26 -0500520 case spv::OpFunctionParameter:
521 // These should have all been removed by preprocessing passes. If we see them here,
522 // our assumptions are wrong and we will probably generate wrong code.
523 UNREACHABLE("%s should have already been lowered.", OpcodeName(opcode));
524 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000525
Nicolas Capens112faf42019-12-13 17:32:26 -0500526 case spv::OpFunctionCall:
527 // TODO(b/141246700): Add full support for spv::OpFunctionCall
528 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000529
Nicolas Capens112faf42019-12-13 17:32:26 -0500530 case spv::OpFConvert:
531 UNSUPPORTED("SPIR-V Float16 or Float64 Capability (OpFConvert)");
532 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000533
Nicolas Capens112faf42019-12-13 17:32:26 -0500534 case spv::OpSConvert:
535 UNSUPPORTED("SPIR-V Int16 or Int64 Capability (OpSConvert)");
536 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000537
Nicolas Capens112faf42019-12-13 17:32:26 -0500538 case spv::OpUConvert:
539 UNSUPPORTED("SPIR-V Int16 or Int64 Capability (OpUConvert)");
540 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000541
Nicolas Capens112faf42019-12-13 17:32:26 -0500542 case spv::OpLoad:
543 case spv::OpAccessChain:
544 case spv::OpInBoundsAccessChain:
545 case spv::OpSampledImage:
546 case spv::OpImage:
Nicolas Capens157ba262019-12-10 17:49:14 -0500547 {
548 // Propagate the descriptor decorations to the result.
549 Object::ID resultId = insn.word(2);
550 Object::ID pointerId = insn.word(3);
551 const auto &d = descriptorDecorations.find(pointerId);
552
553 if(d != descriptorDecorations.end())
554 {
555 descriptorDecorations[resultId] = d->second;
556 }
557
558 DefineResult(insn);
559
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500560 if(opcode == spv::OpAccessChain || opcode == spv::OpInBoundsAccessChain)
Nicolas Capens157ba262019-12-10 17:49:14 -0500561 {
562 Decorations dd{};
563 ApplyDecorationsForAccessChain(&dd, &descriptorDecorations[resultId], pointerId, insn.wordCount() - 4, insn.wordPointer(4));
564 // Note: offset is the one thing that does *not* propagate, as the access chain accounts for it.
565 dd.HasOffset = false;
566 decorations[resultId].Apply(dd);
567 }
568 }
569 break;
Ben Clayton9b156612019-03-13 19:48:31 +0000570
Nicolas Capens112faf42019-12-13 17:32:26 -0500571 case spv::OpCompositeConstruct:
572 case spv::OpCompositeInsert:
573 case spv::OpCompositeExtract:
574 case spv::OpVectorShuffle:
575 case spv::OpVectorTimesScalar:
576 case spv::OpMatrixTimesScalar:
577 case spv::OpMatrixTimesVector:
578 case spv::OpVectorTimesMatrix:
579 case spv::OpMatrixTimesMatrix:
580 case spv::OpOuterProduct:
581 case spv::OpTranspose:
582 case spv::OpVectorExtractDynamic:
583 case spv::OpVectorInsertDynamic:
584 // Unary ops
585 case spv::OpNot:
586 case spv::OpBitFieldInsert:
587 case spv::OpBitFieldSExtract:
588 case spv::OpBitFieldUExtract:
589 case spv::OpBitReverse:
590 case spv::OpBitCount:
591 case spv::OpSNegate:
592 case spv::OpFNegate:
593 case spv::OpLogicalNot:
594 case spv::OpQuantizeToF16:
595 // Binary ops
596 case spv::OpIAdd:
597 case spv::OpISub:
598 case spv::OpIMul:
599 case spv::OpSDiv:
600 case spv::OpUDiv:
601 case spv::OpFAdd:
602 case spv::OpFSub:
603 case spv::OpFMul:
604 case spv::OpFDiv:
605 case spv::OpFMod:
606 case spv::OpFRem:
607 case spv::OpFOrdEqual:
608 case spv::OpFUnordEqual:
609 case spv::OpFOrdNotEqual:
610 case spv::OpFUnordNotEqual:
611 case spv::OpFOrdLessThan:
612 case spv::OpFUnordLessThan:
613 case spv::OpFOrdGreaterThan:
614 case spv::OpFUnordGreaterThan:
615 case spv::OpFOrdLessThanEqual:
616 case spv::OpFUnordLessThanEqual:
617 case spv::OpFOrdGreaterThanEqual:
618 case spv::OpFUnordGreaterThanEqual:
619 case spv::OpSMod:
620 case spv::OpSRem:
621 case spv::OpUMod:
622 case spv::OpIEqual:
623 case spv::OpINotEqual:
624 case spv::OpUGreaterThan:
625 case spv::OpSGreaterThan:
626 case spv::OpUGreaterThanEqual:
627 case spv::OpSGreaterThanEqual:
628 case spv::OpULessThan:
629 case spv::OpSLessThan:
630 case spv::OpULessThanEqual:
631 case spv::OpSLessThanEqual:
632 case spv::OpShiftRightLogical:
633 case spv::OpShiftRightArithmetic:
634 case spv::OpShiftLeftLogical:
635 case spv::OpBitwiseOr:
636 case spv::OpBitwiseXor:
637 case spv::OpBitwiseAnd:
638 case spv::OpLogicalOr:
639 case spv::OpLogicalAnd:
640 case spv::OpLogicalEqual:
641 case spv::OpLogicalNotEqual:
642 case spv::OpUMulExtended:
643 case spv::OpSMulExtended:
644 case spv::OpIAddCarry:
645 case spv::OpISubBorrow:
646 case spv::OpDot:
647 case spv::OpConvertFToU:
648 case spv::OpConvertFToS:
649 case spv::OpConvertSToF:
650 case spv::OpConvertUToF:
651 case spv::OpBitcast:
652 case spv::OpSelect:
653 case spv::OpIsInf:
654 case spv::OpIsNan:
655 case spv::OpAny:
656 case spv::OpAll:
657 case spv::OpDPdx:
658 case spv::OpDPdxCoarse:
659 case spv::OpDPdy:
660 case spv::OpDPdyCoarse:
661 case spv::OpFwidth:
662 case spv::OpFwidthCoarse:
663 case spv::OpDPdxFine:
664 case spv::OpDPdyFine:
665 case spv::OpFwidthFine:
666 case spv::OpAtomicLoad:
667 case spv::OpAtomicIAdd:
668 case spv::OpAtomicISub:
669 case spv::OpAtomicSMin:
670 case spv::OpAtomicSMax:
671 case spv::OpAtomicUMin:
672 case spv::OpAtomicUMax:
673 case spv::OpAtomicAnd:
674 case spv::OpAtomicOr:
675 case spv::OpAtomicXor:
676 case spv::OpAtomicIIncrement:
677 case spv::OpAtomicIDecrement:
678 case spv::OpAtomicExchange:
679 case spv::OpAtomicCompareExchange:
680 case spv::OpPhi:
681 case spv::OpImageSampleImplicitLod:
682 case spv::OpImageSampleExplicitLod:
683 case spv::OpImageSampleDrefImplicitLod:
684 case spv::OpImageSampleDrefExplicitLod:
685 case spv::OpImageSampleProjImplicitLod:
686 case spv::OpImageSampleProjExplicitLod:
687 case spv::OpImageSampleProjDrefImplicitLod:
688 case spv::OpImageSampleProjDrefExplicitLod:
689 case spv::OpImageGather:
690 case spv::OpImageDrefGather:
691 case spv::OpImageFetch:
692 case spv::OpImageQuerySizeLod:
693 case spv::OpImageQuerySize:
694 case spv::OpImageQueryLod:
695 case spv::OpImageQueryLevels:
696 case spv::OpImageQuerySamples:
697 case spv::OpImageRead:
698 case spv::OpImageTexelPointer:
699 case spv::OpGroupNonUniformElect:
700 case spv::OpGroupNonUniformAll:
701 case spv::OpGroupNonUniformAny:
702 case spv::OpGroupNonUniformAllEqual:
703 case spv::OpGroupNonUniformBroadcast:
704 case spv::OpGroupNonUniformBroadcastFirst:
705 case spv::OpGroupNonUniformBallot:
706 case spv::OpGroupNonUniformInverseBallot:
707 case spv::OpGroupNonUniformBallotBitExtract:
708 case spv::OpGroupNonUniformBallotBitCount:
709 case spv::OpGroupNonUniformBallotFindLSB:
710 case spv::OpGroupNonUniformBallotFindMSB:
711 case spv::OpGroupNonUniformShuffle:
712 case spv::OpGroupNonUniformShuffleXor:
713 case spv::OpGroupNonUniformShuffleUp:
714 case spv::OpGroupNonUniformShuffleDown:
715 case spv::OpGroupNonUniformIAdd:
716 case spv::OpGroupNonUniformFAdd:
717 case spv::OpGroupNonUniformIMul:
718 case spv::OpGroupNonUniformFMul:
719 case spv::OpGroupNonUniformSMin:
720 case spv::OpGroupNonUniformUMin:
721 case spv::OpGroupNonUniformFMin:
722 case spv::OpGroupNonUniformSMax:
723 case spv::OpGroupNonUniformUMax:
724 case spv::OpGroupNonUniformFMax:
725 case spv::OpGroupNonUniformBitwiseAnd:
726 case spv::OpGroupNonUniformBitwiseOr:
727 case spv::OpGroupNonUniformBitwiseXor:
728 case spv::OpGroupNonUniformLogicalAnd:
729 case spv::OpGroupNonUniformLogicalOr:
730 case spv::OpGroupNonUniformLogicalXor:
731 case spv::OpCopyObject:
732 case spv::OpCopyLogical:
733 case spv::OpArrayLength:
734 // Instructions that yield an intermediate value or divergent pointer
735 DefineResult(insn);
736 break;
737
738 case spv::OpExtInst:
739 switch(getExtension(insn.word(3)).name)
740 {
741 case Extension::GLSLstd450:
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000742 DefineResult(insn);
743 break;
Nicolas Capens112faf42019-12-13 17:32:26 -0500744 case Extension::OpenCLDebugInfo100:
745 DefineOpenCLDebugInfo100(insn);
Ben Claytonb36dbbe2020-01-08 12:18:43 +0000746 break;
Nicolas Capens112faf42019-12-13 17:32:26 -0500747 default:
748 UNREACHABLE("Unexpected Extension name %d", int(getExtension(insn.word(3)).name));
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000749 break;
Nicolas Capens112faf42019-12-13 17:32:26 -0500750 }
751 break;
Nicolas Capens157ba262019-12-10 17:49:14 -0500752
Nicolas Capens112faf42019-12-13 17:32:26 -0500753 case spv::OpStore:
754 case spv::OpAtomicStore:
755 case spv::OpImageWrite:
756 case spv::OpCopyMemory:
757 case spv::OpMemoryBarrier:
758 // Don't need to do anything during analysis pass
759 break;
Nicolas Capens157ba262019-12-10 17:49:14 -0500760
Nicolas Capens112faf42019-12-13 17:32:26 -0500761 case spv::OpControlBarrier:
Nicolas Capens15941842021-08-13 15:24:28 -0400762 analysis.ContainsControlBarriers = true;
Nicolas Capens112faf42019-12-13 17:32:26 -0500763 break;
764
765 case spv::OpExtension:
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000766 {
Nicolas Capens4c629802021-12-08 02:05:19 -0500767 const char *ext = insn.string(1);
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000768 // Part of core SPIR-V 1.3. Vulkan 1.1 implementations must also accept the pre-1.3
769 // extension per Appendix A, `Vulkan Environment for SPIR-V`.
770 if(!strcmp(ext, "SPV_KHR_storage_buffer_storage_class")) break;
771 if(!strcmp(ext, "SPV_KHR_shader_draw_parameters")) break;
772 if(!strcmp(ext, "SPV_KHR_16bit_storage")) break;
773 if(!strcmp(ext, "SPV_KHR_variable_pointers")) break;
774 if(!strcmp(ext, "SPV_KHR_device_group")) break;
775 if(!strcmp(ext, "SPV_KHR_multiview")) break;
Alexis Hetu1ee36c92020-02-20 14:07:26 -0500776 if(!strcmp(ext, "SPV_EXT_shader_stencil_export")) break;
Sean Risser0063eca2020-10-26 17:08:42 -0400777 if(!strcmp(ext, "SPV_KHR_float_controls")) break;
Nicolas Capens4c629802021-12-08 02:05:19 -0500778 if(!strcmp(ext, "SPV_KHR_vulkan_memory_model")) break;
Nicolas Capens4fd9ef92022-01-14 16:11:27 -0500779 if(!strcmp(ext, "SPV_GOOGLE_decorate_string")) break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000780 UNSUPPORTED("SPIR-V Extension: %s", ext);
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000781 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500782 break;
Ben Claytonc0cf68b2019-03-21 17:46:08 +0000783
Nicolas Capens112faf42019-12-13 17:32:26 -0500784 default:
785 UNSUPPORTED("%s", OpcodeName(opcode));
Nicolas Capens157ba262019-12-10 17:49:14 -0500786 }
Chris Forbesd5aed492019-02-02 15:18:52 -0800787 }
Chris Forbesc61271e2019-02-19 17:01:28 -0800788
Nicolas Capens157ba262019-12-10 17:49:14 -0500789 ASSERT_MSG(entryPoint != 0, "Entry point '%s' not found", entryPointName);
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500790 for(auto &it : functions)
Nicolas Capensfabdec52019-03-21 17:04:05 -0400791 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500792 it.second.AssignBlockFields();
Nicolas Capensfabdec52019-03-21 17:04:05 -0400793 }
Ben Claytonb0ca2a82020-01-08 13:00:57 +0000794
Ben Clayton0d6791c2020-04-22 21:55:27 +0100795#ifdef SPIRV_SHADER_CFG_GRAPHVIZ_DOT_FILEPATH
796 {
797 char path[1024];
798 snprintf(path, sizeof(path), SPIRV_SHADER_CFG_GRAPHVIZ_DOT_FILEPATH, codeSerialID);
799 WriteCFGGraphVizDotFile(path);
800 }
801#endif
802
Ben Claytonb0ca2a82020-01-08 13:00:57 +0000803 dbgCreateFile();
804}
805
806SpirvShader::~SpirvShader()
807{
808 dbgTerm();
Nicolas Capens157ba262019-12-10 17:49:14 -0500809}
Nicolas Capensfabdec52019-03-21 17:04:05 -0400810
Nicolas Capens157ba262019-12-10 17:49:14 -0500811void SpirvShader::DeclareType(InsnIterator insn)
812{
813 Type::ID resultId = insn.word(1);
814
815 auto &type = types[resultId];
816 type.definition = insn;
Nicolas Capensff9f9b52020-04-14 00:46:38 -0400817 type.componentCount = ComputeTypeSize(insn);
Nicolas Capens157ba262019-12-10 17:49:14 -0500818
819 // A structure is a builtin block if it has a builtin
820 // member. All members of such a structure are builtins.
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500821 switch(insn.opcode())
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000822 {
Nicolas Capens112faf42019-12-13 17:32:26 -0500823 case spv::OpTypeStruct:
Nicolas Capens157ba262019-12-10 17:49:14 -0500824 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000825 auto d = memberDecorations.find(resultId);
826 if(d != memberDecorations.end())
Nicolas Capens157ba262019-12-10 17:49:14 -0500827 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000828 for(auto &m : d->second)
Nicolas Capens157ba262019-12-10 17:49:14 -0500829 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000830 if(m.HasBuiltIn)
831 {
832 type.isBuiltInBlock = true;
833 break;
834 }
Nicolas Capens157ba262019-12-10 17:49:14 -0500835 }
836 }
837 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500838 break;
839 case spv::OpTypePointer:
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000840 {
841 Type::ID elementTypeId = insn.word(3);
842 type.element = elementTypeId;
843 type.isBuiltInBlock = getType(elementTypeId).isBuiltInBlock;
844 type.storageClass = static_cast<spv::StorageClass>(insn.word(2));
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000845 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500846 break;
847 case spv::OpTypeVector:
848 case spv::OpTypeMatrix:
849 case spv::OpTypeArray:
850 case spv::OpTypeRuntimeArray:
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000851 {
852 Type::ID elementTypeId = insn.word(2);
853 type.element = elementTypeId;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000854 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500855 break;
856 default:
857 break;
Nicolas Capens157ba262019-12-10 17:49:14 -0500858 }
859}
860
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000861SpirvShader::Object &SpirvShader::CreateConstant(InsnIterator insn)
Nicolas Capens157ba262019-12-10 17:49:14 -0500862{
863 Type::ID typeId = insn.word(1);
864 Object::ID resultId = insn.word(2);
865 auto &object = defs[resultId];
866 auto &objectTy = getType(typeId);
Nicolas Capens157ba262019-12-10 17:49:14 -0500867 object.kind = Object::Kind::Constant;
868 object.definition = insn;
Nicolas Capens2f4b6032020-04-09 02:01:50 -0400869 object.constantValue.resize(objectTy.componentCount);
Nicolas Capens72f089c2020-04-08 23:37:08 -0400870
Nicolas Capens157ba262019-12-10 17:49:14 -0500871 return object;
872}
873
874void SpirvShader::ProcessInterfaceVariable(Object &object)
875{
Nicolas Capens72f089c2020-04-08 23:37:08 -0400876 auto &objectTy = getType(object);
Nicolas Capens157ba262019-12-10 17:49:14 -0500877 ASSERT(objectTy.storageClass == spv::StorageClassInput || objectTy.storageClass == spv::StorageClassOutput);
878
879 ASSERT(objectTy.opcode() == spv::OpTypePointer);
880 auto pointeeTy = getType(objectTy.element);
881
882 auto &builtinInterface = (objectTy.storageClass == spv::StorageClassInput) ? inputBuiltins : outputBuiltins;
883 auto &userDefinedInterface = (objectTy.storageClass == spv::StorageClassInput) ? inputs : outputs;
884
885 ASSERT(object.opcode() == spv::OpVariable);
886 Object::ID resultId = object.definition.word(2);
887
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500888 if(objectTy.isBuiltInBlock)
Nicolas Capens157ba262019-12-10 17:49:14 -0500889 {
Nicolas Capens71186752020-04-09 01:05:31 -0400890 // Walk the builtin block, registering each of its members separately.
Nicolas Capens157ba262019-12-10 17:49:14 -0500891 auto m = memberDecorations.find(objectTy.element);
Nicolas Capens71186752020-04-09 01:05:31 -0400892 ASSERT(m != memberDecorations.end()); // Otherwise we wouldn't have marked the type chain
Nicolas Capens157ba262019-12-10 17:49:14 -0500893 auto &structType = pointeeTy.definition;
Nicolas Capens71186752020-04-09 01:05:31 -0400894 auto memberIndex = 0u;
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000895 auto offset = 0u;
Nicolas Capens71186752020-04-09 01:05:31 -0400896
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500897 for(auto &member : m->second)
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000898 {
Nicolas Capens71186752020-04-09 01:05:31 -0400899 auto &memberType = getType(structType.word(2 + memberIndex));
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000900
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500901 if(member.HasBuiltIn)
Ben Clayton9b62c5e2019-03-08 09:32:34 +0000902 {
Nicolas Capensff9f9b52020-04-14 00:46:38 -0400903 builtinInterface[member.BuiltIn] = { resultId, offset, memberType.componentCount };
Ben Clayton9b62c5e2019-03-08 09:32:34 +0000904 }
Ben Claytonc0cf68b2019-03-21 17:46:08 +0000905
Nicolas Capensff9f9b52020-04-14 00:46:38 -0400906 offset += memberType.componentCount;
Nicolas Capens71186752020-04-09 01:05:31 -0400907 ++memberIndex;
Nicolas Capens157ba262019-12-10 17:49:14 -0500908 }
Nicolas Capens71186752020-04-09 01:05:31 -0400909
Nicolas Capens157ba262019-12-10 17:49:14 -0500910 return;
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000911 }
912
Nicolas Capens157ba262019-12-10 17:49:14 -0500913 auto d = decorations.find(resultId);
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500914 if(d != decorations.end() && d->second.HasBuiltIn)
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000915 {
Nicolas Capensff9f9b52020-04-14 00:46:38 -0400916 builtinInterface[d->second.BuiltIn] = { resultId, 0, pointeeTy.componentCount };
Nicolas Capens157ba262019-12-10 17:49:14 -0500917 }
918 else
919 {
920 object.kind = Object::Kind::InterfaceVariable;
921 VisitInterface(resultId,
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000922 [&userDefinedInterface](Decorations const &d, AttribType type) {
923 // Populate a single scalar slot in the interface from a collection of decorations and the intended component type.
924 auto scalarSlot = (d.Location << 2) | d.Component;
925 ASSERT(scalarSlot >= 0 &&
926 scalarSlot < static_cast<int32_t>(userDefinedInterface.size()));
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000927
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000928 auto &slot = userDefinedInterface[scalarSlot];
929 slot.Type = type;
930 slot.Flat = d.Flat;
931 slot.NoPerspective = d.NoPerspective;
932 slot.Centroid = d.Centroid;
933 });
Nicolas Capens157ba262019-12-10 17:49:14 -0500934 }
935}
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000936
Alexis Hetu945f1442021-01-14 11:39:56 -0500937uint32_t SpirvShader::GetNumInputComponents(int32_t location) const
938{
939 ASSERT(location >= 0);
940
941 // Verify how many component(s) per input
942 // 1 to 4, for float, vec2, vec3, vec4.
943 // Note that matrices are divided over multiple inputs
944 uint32_t num_components_per_input = 0;
945 for(; num_components_per_input < 4; ++num_components_per_input)
946 {
947 if(inputs[(location << 2) | num_components_per_input].Type == ATTRIBTYPE_UNUSED)
948 {
949 break;
950 }
951 }
952
953 return num_components_per_input;
954}
955
Alexis Hetu73a69402021-11-08 16:03:51 -0500956uint32_t SpirvShader::GetPackedInterpolant(int32_t location) const
957{
958 ASSERT(location >= 0);
959 const uint32_t maxInterpolant = (location << 2);
960
961 // Return the number of used components only at location
962 uint32_t packedInterpolant = 0;
963 for(uint32_t i = 0; i < maxInterpolant; ++i)
964 {
Nicolas Capens8dccb372021-11-11 14:24:34 -0500965 if(inputs[i].Type != ATTRIBTYPE_UNUSED)
Alexis Hetu73a69402021-11-08 16:03:51 -0500966 {
967 ++packedInterpolant;
968 }
969 }
970
971 return packedInterpolant;
972}
973
Nicolas Capens157ba262019-12-10 17:49:14 -0500974void SpirvShader::ProcessExecutionMode(InsnIterator insn)
975{
Nicolas Capens57eb48a2020-05-15 17:07:07 -0400976 Function::ID function = insn.word(1);
977 if(function != entryPoint)
978 {
979 return;
980 }
981
Nicolas Capens157ba262019-12-10 17:49:14 -0500982 auto mode = static_cast<spv::ExecutionMode>(insn.word(2));
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500983 switch(mode)
Nicolas Capens157ba262019-12-10 17:49:14 -0500984 {
Nicolas Capens112faf42019-12-13 17:32:26 -0500985 case spv::ExecutionModeEarlyFragmentTests:
Nicolas Capens15941842021-08-13 15:24:28 -0400986 executionModes.EarlyFragmentTests = true;
Nicolas Capens112faf42019-12-13 17:32:26 -0500987 break;
988 case spv::ExecutionModeDepthReplacing:
Nicolas Capens15941842021-08-13 15:24:28 -0400989 executionModes.DepthReplacing = true;
Nicolas Capens112faf42019-12-13 17:32:26 -0500990 break;
991 case spv::ExecutionModeDepthGreater:
992 // TODO(b/177915067): Can be used to optimize depth test, currently unused.
Nicolas Capens15941842021-08-13 15:24:28 -0400993 executionModes.DepthGreater = true;
Nicolas Capens112faf42019-12-13 17:32:26 -0500994 break;
995 case spv::ExecutionModeDepthLess:
996 // TODO(b/177915067): Can be used to optimize depth test, currently unused.
Nicolas Capens15941842021-08-13 15:24:28 -0400997 executionModes.DepthLess = true;
Nicolas Capens112faf42019-12-13 17:32:26 -0500998 break;
999 case spv::ExecutionModeDepthUnchanged:
1000 // TODO(b/177915067): Can be used to optimize depth test, currently unused.
Nicolas Capens15941842021-08-13 15:24:28 -04001001 executionModes.DepthUnchanged = true;
Nicolas Capens112faf42019-12-13 17:32:26 -05001002 break;
1003 case spv::ExecutionModeLocalSize:
Nicolas Capens15941842021-08-13 15:24:28 -04001004 executionModes.WorkgroupSizeX = insn.word(3);
1005 executionModes.WorkgroupSizeY = insn.word(4);
1006 executionModes.WorkgroupSizeZ = insn.word(5);
Nicolas Capens112faf42019-12-13 17:32:26 -05001007 break;
1008 case spv::ExecutionModeOriginUpperLeft:
1009 // This is always the case for a Vulkan shader. Do nothing.
1010 break;
1011 default:
1012 UNREACHABLE("Execution mode: %d", int(mode));
Nicolas Capens157ba262019-12-10 17:49:14 -05001013 }
1014}
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001015
Nicolas Capens157ba262019-12-10 17:49:14 -05001016uint32_t SpirvShader::ComputeTypeSize(InsnIterator insn)
1017{
1018 // Types are always built from the bottom up (with the exception of forward ptrs, which
1019 // don't appear in Vulkan shaders. Therefore, we can always assume our component parts have
1020 // already been described (and so their sizes determined)
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001021 switch(insn.opcode())
Nicolas Capens157ba262019-12-10 17:49:14 -05001022 {
Nicolas Capens112faf42019-12-13 17:32:26 -05001023 case spv::OpTypeVoid:
1024 case spv::OpTypeSampler:
1025 case spv::OpTypeImage:
1026 case spv::OpTypeSampledImage:
1027 case spv::OpTypeFunction:
1028 case spv::OpTypeRuntimeArray:
1029 // Objects that don't consume any space.
1030 // Descriptor-backed objects currently only need exist at compile-time.
1031 // Runtime arrays don't appear in places where their size would be interesting
1032 return 0;
Nicolas Capens157ba262019-12-10 17:49:14 -05001033
Nicolas Capens112faf42019-12-13 17:32:26 -05001034 case spv::OpTypeBool:
1035 case spv::OpTypeFloat:
1036 case spv::OpTypeInt:
1037 // All the fundamental types are 1 component. If we ever add support for 8/16/64-bit components,
1038 // we might need to change this, but only 32 bit components are required for Vulkan 1.1.
1039 return 1;
Nicolas Capens157ba262019-12-10 17:49:14 -05001040
Nicolas Capens112faf42019-12-13 17:32:26 -05001041 case spv::OpTypeVector:
1042 case spv::OpTypeMatrix:
1043 // Vectors and matrices both consume element count * element size.
1044 return getType(insn.word(2)).componentCount * insn.word(3);
Nicolas Capens157ba262019-12-10 17:49:14 -05001045
Nicolas Capens112faf42019-12-13 17:32:26 -05001046 case spv::OpTypeArray:
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001047 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001048 // Element count * element size. Array sizes come from constant ids.
1049 auto arraySize = GetConstScalarInt(insn.word(3));
Nicolas Capensff9f9b52020-04-14 00:46:38 -04001050 return getType(insn.word(2)).componentCount * arraySize;
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001051 }
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001052
Nicolas Capens112faf42019-12-13 17:32:26 -05001053 case spv::OpTypeStruct:
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001054 {
1055 uint32_t size = 0;
1056 for(uint32_t i = 2u; i < insn.wordCount(); i++)
1057 {
Nicolas Capensff9f9b52020-04-14 00:46:38 -04001058 size += getType(insn.word(i)).componentCount;
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001059 }
1060 return size;
1061 }
Nicolas Capens157ba262019-12-10 17:49:14 -05001062
Nicolas Capens112faf42019-12-13 17:32:26 -05001063 case spv::OpTypePointer:
1064 // Runtime representation of a pointer is a per-lane index.
1065 // Note: clients are expected to look through the pointer if they want the pointee size instead.
1066 return 1;
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001067
Nicolas Capens112faf42019-12-13 17:32:26 -05001068 default:
1069 UNREACHABLE("%s", OpcodeName(insn.opcode()));
1070 return 0;
Nicolas Capens157ba262019-12-10 17:49:14 -05001071 }
1072}
1073
1074int SpirvShader::VisitInterfaceInner(Type::ID id, Decorations d, const InterfaceVisitor &f) const
1075{
1076 // Recursively walks variable definition and its type tree, taking into account
1077 // any explicit Location or Component decorations encountered; where explicit
1078 // Locations or Components are not specified, assigns them sequentially.
1079 // Collected decorations are carried down toward the leaves and across
1080 // siblings; Effect of decorations intentionally does not flow back up the tree.
1081 //
1082 // F is a functor to be called with the effective decoration set for every component.
1083 //
1084 // Returns the next available location, and calls f().
1085
1086 // This covers the rules in Vulkan 1.1 spec, 14.1.4 Location Assignment.
1087
1088 ApplyDecorationsForId(&d, id);
1089
1090 auto const &obj = getType(id);
1091 switch(obj.opcode())
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001092 {
Nicolas Capens112faf42019-12-13 17:32:26 -05001093 case spv::OpTypePointer:
1094 return VisitInterfaceInner(obj.definition.word(3), d, f);
1095 case spv::OpTypeMatrix:
1096 for(auto i = 0u; i < obj.definition.word(3); i++, d.Location++)
1097 {
1098 // consumes same components of N consecutive locations
1099 VisitInterfaceInner(obj.definition.word(2), d, f);
1100 }
1101 return d.Location;
1102 case spv::OpTypeVector:
1103 for(auto i = 0u; i < obj.definition.word(3); i++, d.Component++)
1104 {
1105 // consumes N consecutive components in the same location
1106 VisitInterfaceInner(obj.definition.word(2), d, f);
1107 }
1108 return d.Location + 1;
1109 case spv::OpTypeFloat:
1110 f(d, ATTRIBTYPE_FLOAT);
1111 return d.Location + 1;
1112 case spv::OpTypeInt:
1113 f(d, obj.definition.word(3) ? ATTRIBTYPE_INT : ATTRIBTYPE_UINT);
1114 return d.Location + 1;
1115 case spv::OpTypeBool:
1116 f(d, ATTRIBTYPE_UINT);
1117 return d.Location + 1;
1118 case spv::OpTypeStruct:
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001119 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001120 // iterate over members, which may themselves have Location/Component decorations
1121 for(auto i = 0u; i < obj.definition.wordCount() - 2; i++)
1122 {
Alexis Hetub6540802020-08-11 18:12:03 -04001123 Decorations dMember = d;
1124 ApplyDecorationsForIdMember(&dMember, id, i);
1125 d.Location = VisitInterfaceInner(obj.definition.word(i + 2), dMember, f);
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001126 d.Component = 0; // Implicit locations always have component=0
1127 }
1128 return d.Location;
Nicolas Capens157ba262019-12-10 17:49:14 -05001129 }
Nicolas Capens112faf42019-12-13 17:32:26 -05001130 case spv::OpTypeArray:
Nicolas Capens157ba262019-12-10 17:49:14 -05001131 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001132 auto arraySize = GetConstScalarInt(obj.definition.word(3));
1133 for(auto i = 0u; i < arraySize; i++)
1134 {
1135 d.Location = VisitInterfaceInner(obj.definition.word(2), d, f);
1136 }
1137 return d.Location;
Nicolas Capens157ba262019-12-10 17:49:14 -05001138 }
Nicolas Capens112faf42019-12-13 17:32:26 -05001139 default:
1140 // Intentionally partial; most opcodes do not participate in type hierarchies
1141 return 0;
Nicolas Capens157ba262019-12-10 17:49:14 -05001142 }
1143}
1144
1145void SpirvShader::VisitInterface(Object::ID id, const InterfaceVisitor &f) const
1146{
1147 // Walk a variable definition and call f for each component in it.
1148 Decorations d{};
1149 ApplyDecorationsForId(&d, id);
1150
1151 auto def = getObject(id).definition;
1152 ASSERT(def.opcode() == spv::OpVariable);
1153 VisitInterfaceInner(def.word(1), d, f);
1154}
1155
1156void SpirvShader::ApplyDecorationsForAccessChain(Decorations *d, DescriptorDecorations *dd, Object::ID baseId, uint32_t numIndexes, uint32_t const *indexIds) const
1157{
1158 ApplyDecorationsForId(d, baseId);
1159 auto &baseObject = getObject(baseId);
Nicolas Capens72f089c2020-04-08 23:37:08 -04001160 ApplyDecorationsForId(d, baseObject.typeId());
1161 auto typeId = getType(baseObject).element;
Nicolas Capens157ba262019-12-10 17:49:14 -05001162
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001163 for(auto i = 0u; i < numIndexes; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05001164 {
1165 ApplyDecorationsForId(d, typeId);
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001166 auto &type = getType(typeId);
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001167 switch(type.opcode())
Nicolas Capens157ba262019-12-10 17:49:14 -05001168 {
Nicolas Capens112faf42019-12-13 17:32:26 -05001169 case spv::OpTypeStruct:
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001170 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001171 int memberIndex = GetConstScalarInt(indexIds[i]);
1172 ApplyDecorationsForIdMember(d, typeId, memberIndex);
1173 typeId = type.definition.word(2u + memberIndex);
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001174 }
Nicolas Capens112faf42019-12-13 17:32:26 -05001175 break;
1176 case spv::OpTypeArray:
1177 case spv::OpTypeRuntimeArray:
1178 if(dd->InputAttachmentIndex >= 0)
1179 {
1180 dd->InputAttachmentIndex += GetConstScalarInt(indexIds[i]);
1181 }
1182 typeId = type.element;
1183 break;
1184 case spv::OpTypeVector:
1185 typeId = type.element;
1186 break;
1187 case spv::OpTypeMatrix:
1188 typeId = type.element;
1189 d->InsideMatrix = true;
1190 break;
1191 default:
1192 UNREACHABLE("%s", OpcodeName(type.definition.opcode()));
Nicolas Capens157ba262019-12-10 17:49:14 -05001193 }
1194 }
1195}
1196
1197SIMD::Pointer SpirvShader::WalkExplicitLayoutAccessChain(Object::ID baseId, uint32_t numIndexes, uint32_t const *indexIds, EmitState const *state) const
1198{
1199 // Produce a offset into external memory in sizeof(float) units
1200
1201 auto &baseObject = getObject(baseId);
Nicolas Capens72f089c2020-04-08 23:37:08 -04001202 Type::ID typeId = getType(baseObject).element;
Nicolas Capens157ba262019-12-10 17:49:14 -05001203 Decorations d = {};
Nicolas Capens72f089c2020-04-08 23:37:08 -04001204 ApplyDecorationsForId(&d, baseObject.typeId());
Nicolas Capens157ba262019-12-10 17:49:14 -05001205
Nicolas Capens479d1432020-01-31 11:19:21 -05001206 Int arrayIndex = 0;
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001207 if(baseObject.kind == Object::Kind::DescriptorSet)
Nicolas Capens157ba262019-12-10 17:49:14 -05001208 {
1209 auto type = getType(typeId).definition.opcode();
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001210 if(type == spv::OpTypeArray || type == spv::OpTypeRuntimeArray)
Nicolas Capens157ba262019-12-10 17:49:14 -05001211 {
Nicolas Capens479d1432020-01-31 11:19:21 -05001212 auto &obj = getObject(indexIds[0]);
1213 ASSERT(obj.kind == Object::Kind::Constant || obj.kind == Object::Kind::Intermediate);
1214 if(obj.kind == Object::Kind::Constant)
1215 {
1216 arrayIndex = GetConstScalarInt(indexIds[0]);
1217 }
1218 else
1219 {
1220 // Note: the value of indexIds[0] must be dynamically uniform.
1221 arrayIndex = Extract(state->getIntermediate(indexIds[0]).Int(0), 0);
1222 }
Nicolas Capens157ba262019-12-10 17:49:14 -05001223
1224 numIndexes--;
1225 indexIds++;
1226 typeId = getType(typeId).element;
1227 }
1228 }
1229
1230 auto ptr = GetPointerToData(baseId, arrayIndex, state);
1231
1232 int constantOffset = 0;
1233
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001234 for(auto i = 0u; i < numIndexes; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05001235 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001236 auto &type = getType(typeId);
Nicolas Capens157ba262019-12-10 17:49:14 -05001237 ApplyDecorationsForId(&d, typeId);
1238
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001239 switch(type.definition.opcode())
Nicolas Capens157ba262019-12-10 17:49:14 -05001240 {
Nicolas Capens112faf42019-12-13 17:32:26 -05001241 case spv::OpTypeStruct:
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001242 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001243 int memberIndex = GetConstScalarInt(indexIds[i]);
1244 ApplyDecorationsForIdMember(&d, typeId, memberIndex);
1245 ASSERT(d.HasOffset);
1246 constantOffset += d.Offset;
1247 typeId = type.definition.word(2u + memberIndex);
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001248 }
Nicolas Capens112faf42019-12-13 17:32:26 -05001249 break;
1250 case spv::OpTypeArray:
1251 case spv::OpTypeRuntimeArray:
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001252 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001253 // TODO: b/127950082: Check bounds.
1254 ASSERT(d.HasArrayStride);
1255 auto &obj = getObject(indexIds[i]);
1256 if(obj.kind == Object::Kind::Constant)
1257 {
1258 constantOffset += d.ArrayStride * GetConstScalarInt(indexIds[i]);
1259 }
1260 else
1261 {
1262 ptr += SIMD::Int(d.ArrayStride) * state->getIntermediate(indexIds[i]).Int(0);
1263 }
1264 typeId = type.element;
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001265 }
Nicolas Capens112faf42019-12-13 17:32:26 -05001266 break;
1267 case spv::OpTypeMatrix:
Chris Forbes17813932019-04-18 11:45:54 -07001268 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001269 // TODO: b/127950082: Check bounds.
1270 ASSERT(d.HasMatrixStride);
1271 d.InsideMatrix = true;
1272 auto columnStride = (d.HasRowMajor && d.RowMajor) ? static_cast<int32_t>(sizeof(float)) : d.MatrixStride;
1273 auto &obj = getObject(indexIds[i]);
1274 if(obj.kind == Object::Kind::Constant)
1275 {
1276 constantOffset += columnStride * GetConstScalarInt(indexIds[i]);
1277 }
1278 else
1279 {
1280 ptr += SIMD::Int(columnStride) * state->getIntermediate(indexIds[i]).Int(0);
1281 }
1282 typeId = type.element;
Chris Forbes17813932019-04-18 11:45:54 -07001283 }
Nicolas Capens112faf42019-12-13 17:32:26 -05001284 break;
1285 case spv::OpTypeVector:
Chris Forbesa16238d2019-04-18 16:31:54 -07001286 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001287 auto elemStride = (d.InsideMatrix && d.HasRowMajor && d.RowMajor) ? d.MatrixStride : static_cast<int32_t>(sizeof(float));
1288 auto &obj = getObject(indexIds[i]);
1289 if(obj.kind == Object::Kind::Constant)
1290 {
1291 constantOffset += elemStride * GetConstScalarInt(indexIds[i]);
1292 }
1293 else
1294 {
1295 ptr += SIMD::Int(elemStride) * state->getIntermediate(indexIds[i]).Int(0);
1296 }
1297 typeId = type.element;
Chris Forbesa16238d2019-04-18 16:31:54 -07001298 }
Nicolas Capens112faf42019-12-13 17:32:26 -05001299 break;
1300 default:
1301 UNREACHABLE("%s", OpcodeName(type.definition.opcode()));
Ben Clayton60f15ec2019-05-09 17:50:01 +01001302 }
1303 }
1304
Nicolas Capens157ba262019-12-10 17:49:14 -05001305 ptr += constantOffset;
1306 return ptr;
1307}
Ben Clayton59cd59b2019-06-25 19:07:48 +01001308
Nicolas Capens157ba262019-12-10 17:49:14 -05001309SIMD::Pointer SpirvShader::WalkAccessChain(Object::ID baseId, uint32_t numIndexes, uint32_t const *indexIds, EmitState const *state) const
1310{
1311 // TODO: avoid doing per-lane work in some cases if we can?
1312 auto routine = state->routine;
1313 auto &baseObject = getObject(baseId);
Nicolas Capens72f089c2020-04-08 23:37:08 -04001314 Type::ID typeId = getType(baseObject).element;
Nicolas Capens157ba262019-12-10 17:49:14 -05001315
1316 auto ptr = state->getPointer(baseId);
1317
1318 int constantOffset = 0;
1319
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001320 for(auto i = 0u; i < numIndexes; i++)
Ben Clayton76e9bc02019-02-26 15:02:18 +00001321 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001322 auto &type = getType(typeId);
Nicolas Capens157ba262019-12-10 17:49:14 -05001323 switch(type.opcode())
1324 {
Nicolas Capens112faf42019-12-13 17:32:26 -05001325 case spv::OpTypeStruct:
Nicolas Capens157ba262019-12-10 17:49:14 -05001326 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001327 int memberIndex = GetConstScalarInt(indexIds[i]);
1328 int offsetIntoStruct = 0;
1329 for(auto j = 0; j < memberIndex; j++)
Nicolas Capens157ba262019-12-10 17:49:14 -05001330 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001331 auto memberType = type.definition.word(2u + j);
Nicolas Capensff9f9b52020-04-14 00:46:38 -04001332 offsetIntoStruct += getType(memberType).componentCount * sizeof(float);
Nicolas Capens157ba262019-12-10 17:49:14 -05001333 }
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001334 constantOffset += offsetIntoStruct;
1335 typeId = type.definition.word(2u + memberIndex);
Nicolas Capens157ba262019-12-10 17:49:14 -05001336 }
Nicolas Capens112faf42019-12-13 17:32:26 -05001337 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001338
Nicolas Capens112faf42019-12-13 17:32:26 -05001339 case spv::OpTypeVector:
1340 case spv::OpTypeMatrix:
1341 case spv::OpTypeArray:
1342 case spv::OpTypeRuntimeArray:
Nicolas Capens157ba262019-12-10 17:49:14 -05001343 {
Nicolas Capens479d1432020-01-31 11:19:21 -05001344 // TODO(b/127950082): Check bounds.
Nicolas Capens72f089c2020-04-08 23:37:08 -04001345 if(getType(baseObject).storageClass == spv::StorageClassUniformConstant)
Nicolas Capens157ba262019-12-10 17:49:14 -05001346 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001347 // indexing into an array of descriptors.
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001348 auto d = descriptorDecorations.at(baseId);
1349 ASSERT(d.DescriptorSet >= 0);
1350 ASSERT(d.Binding >= 0);
Nicolas Capensc7d5ec32020-04-22 01:11:37 -04001351 uint32_t descriptorSize = routine->pipelineLayout->getDescriptorSize(d.DescriptorSet, d.Binding);
Nicolas Capens479d1432020-01-31 11:19:21 -05001352
1353 auto &obj = getObject(indexIds[i]);
1354 if(obj.kind == Object::Kind::Constant)
1355 {
1356 ptr.base += descriptorSize * GetConstScalarInt(indexIds[i]);
1357 }
1358 else
1359 {
1360 // Note: the value of indexIds[i] must be dynamically uniform.
1361 ptr.base += descriptorSize * Extract(state->getIntermediate(indexIds[i]).Int(0), 0);
1362 }
Nicolas Capens157ba262019-12-10 17:49:14 -05001363 }
1364 else
1365 {
Nicolas Capensff9f9b52020-04-14 00:46:38 -04001366 auto stride = getType(type.element).componentCount * static_cast<uint32_t>(sizeof(float));
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001367 auto &obj = getObject(indexIds[i]);
1368 if(obj.kind == Object::Kind::Constant)
1369 {
1370 ptr += stride * GetConstScalarInt(indexIds[i]);
1371 }
1372 else
1373 {
1374 ptr += SIMD::Int(stride) * state->getIntermediate(indexIds[i]).Int(0);
1375 }
Nicolas Capens157ba262019-12-10 17:49:14 -05001376 }
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001377 typeId = type.element;
Nicolas Capens157ba262019-12-10 17:49:14 -05001378 }
Nicolas Capens112faf42019-12-13 17:32:26 -05001379 break;
Nicolas Capens157ba262019-12-10 17:49:14 -05001380
Nicolas Capens112faf42019-12-13 17:32:26 -05001381 default:
1382 UNREACHABLE("%s", OpcodeName(type.opcode()));
Nicolas Capens157ba262019-12-10 17:49:14 -05001383 }
Ben Clayton76e9bc02019-02-26 15:02:18 +00001384 }
1385
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001386 if(constantOffset != 0)
Ben Clayton30ee92e2019-08-13 14:21:44 +01001387 {
Nicolas Capens157ba262019-12-10 17:49:14 -05001388 ptr += constantOffset;
1389 }
1390 return ptr;
1391}
Ben Clayton30ee92e2019-08-13 14:21:44 +01001392
Nicolas Capens157ba262019-12-10 17:49:14 -05001393uint32_t SpirvShader::WalkLiteralAccessChain(Type::ID typeId, uint32_t numIndexes, uint32_t const *indexes) const
1394{
1395 uint32_t componentOffset = 0;
Ben Clayton30ee92e2019-08-13 14:21:44 +01001396
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001397 for(auto i = 0u; i < numIndexes; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05001398 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001399 auto &type = getType(typeId);
Nicolas Capens157ba262019-12-10 17:49:14 -05001400 switch(type.opcode())
Ben Clayton30ee92e2019-08-13 14:21:44 +01001401 {
Nicolas Capens112faf42019-12-13 17:32:26 -05001402 case spv::OpTypeStruct:
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001403 {
1404 int memberIndex = indexes[i];
1405 int offsetIntoStruct = 0;
1406 for(auto j = 0; j < memberIndex; j++)
1407 {
1408 auto memberType = type.definition.word(2u + j);
Nicolas Capensff9f9b52020-04-14 00:46:38 -04001409 offsetIntoStruct += getType(memberType).componentCount;
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001410 }
1411 componentOffset += offsetIntoStruct;
1412 typeId = type.definition.word(2u + memberIndex);
Nicolas Capens157ba262019-12-10 17:49:14 -05001413 }
Nicolas Capens112faf42019-12-13 17:32:26 -05001414 break;
Ben Clayton30ee92e2019-08-13 14:21:44 +01001415
Nicolas Capens112faf42019-12-13 17:32:26 -05001416 case spv::OpTypeVector:
1417 case spv::OpTypeMatrix:
1418 case spv::OpTypeArray:
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001419 {
1420 auto elementType = type.definition.word(2);
Nicolas Capensff9f9b52020-04-14 00:46:38 -04001421 auto stride = getType(elementType).componentCount;
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001422 componentOffset += stride * indexes[i];
1423 typeId = elementType;
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001424 }
Nicolas Capens112faf42019-12-13 17:32:26 -05001425 break;
Ben Clayton30ee92e2019-08-13 14:21:44 +01001426
Nicolas Capens112faf42019-12-13 17:32:26 -05001427 default:
1428 UNREACHABLE("%s", OpcodeName(type.opcode()));
Nicolas Capens157ba262019-12-10 17:49:14 -05001429 }
1430 }
Ben Clayton30ee92e2019-08-13 14:21:44 +01001431
Nicolas Capens157ba262019-12-10 17:49:14 -05001432 return componentOffset;
1433}
Ben Clayton30ee92e2019-08-13 14:21:44 +01001434
Nicolas Capens157ba262019-12-10 17:49:14 -05001435void SpirvShader::Decorations::Apply(spv::Decoration decoration, uint32_t arg)
1436{
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001437 switch(decoration)
Nicolas Capens157ba262019-12-10 17:49:14 -05001438 {
Nicolas Capens112faf42019-12-13 17:32:26 -05001439 case spv::DecorationLocation:
1440 HasLocation = true;
1441 Location = static_cast<int32_t>(arg);
1442 break;
1443 case spv::DecorationComponent:
1444 HasComponent = true;
1445 Component = arg;
1446 break;
1447 case spv::DecorationBuiltIn:
1448 HasBuiltIn = true;
1449 BuiltIn = static_cast<spv::BuiltIn>(arg);
1450 break;
1451 case spv::DecorationFlat:
1452 Flat = true;
1453 break;
1454 case spv::DecorationNoPerspective:
1455 NoPerspective = true;
1456 break;
1457 case spv::DecorationCentroid:
1458 Centroid = true;
1459 break;
1460 case spv::DecorationBlock:
1461 Block = true;
1462 break;
1463 case spv::DecorationBufferBlock:
1464 BufferBlock = true;
1465 break;
1466 case spv::DecorationOffset:
1467 HasOffset = true;
1468 Offset = static_cast<int32_t>(arg);
1469 break;
1470 case spv::DecorationArrayStride:
1471 HasArrayStride = true;
1472 ArrayStride = static_cast<int32_t>(arg);
1473 break;
1474 case spv::DecorationMatrixStride:
1475 HasMatrixStride = true;
1476 MatrixStride = static_cast<int32_t>(arg);
1477 break;
1478 case spv::DecorationRelaxedPrecision:
1479 RelaxedPrecision = true;
1480 break;
1481 case spv::DecorationRowMajor:
1482 HasRowMajor = true;
1483 RowMajor = true;
1484 break;
1485 case spv::DecorationColMajor:
1486 HasRowMajor = true;
1487 RowMajor = false;
1488 default:
1489 // Intentionally partial, there are many decorations we just don't care about.
1490 break;
Ben Clayton30ee92e2019-08-13 14:21:44 +01001491 }
Chris Forbesc25b8072018-12-10 15:10:39 -08001492}
Nicolas Capens157ba262019-12-10 17:49:14 -05001493
1494void SpirvShader::Decorations::Apply(const sw::SpirvShader::Decorations &src)
1495{
1496 // Apply a decoration group to this set of decorations
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001497 if(src.HasBuiltIn)
Nicolas Capens157ba262019-12-10 17:49:14 -05001498 {
1499 HasBuiltIn = true;
1500 BuiltIn = src.BuiltIn;
1501 }
1502
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001503 if(src.HasLocation)
Nicolas Capens157ba262019-12-10 17:49:14 -05001504 {
1505 HasLocation = true;
1506 Location = src.Location;
1507 }
1508
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001509 if(src.HasComponent)
Nicolas Capens157ba262019-12-10 17:49:14 -05001510 {
1511 HasComponent = true;
1512 Component = src.Component;
1513 }
1514
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001515 if(src.HasOffset)
Nicolas Capens157ba262019-12-10 17:49:14 -05001516 {
1517 HasOffset = true;
1518 Offset = src.Offset;
1519 }
1520
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001521 if(src.HasArrayStride)
Nicolas Capens157ba262019-12-10 17:49:14 -05001522 {
1523 HasArrayStride = true;
1524 ArrayStride = src.ArrayStride;
1525 }
1526
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001527 if(src.HasMatrixStride)
Nicolas Capens157ba262019-12-10 17:49:14 -05001528 {
1529 HasMatrixStride = true;
1530 MatrixStride = src.MatrixStride;
1531 }
1532
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001533 if(src.HasRowMajor)
Nicolas Capens157ba262019-12-10 17:49:14 -05001534 {
1535 HasRowMajor = true;
1536 RowMajor = src.RowMajor;
1537 }
1538
1539 Flat |= src.Flat;
1540 NoPerspective |= src.NoPerspective;
1541 Centroid |= src.Centroid;
1542 Block |= src.Block;
1543 BufferBlock |= src.BufferBlock;
1544 RelaxedPrecision |= src.RelaxedPrecision;
1545 InsideMatrix |= src.InsideMatrix;
1546}
1547
1548void SpirvShader::DescriptorDecorations::Apply(const sw::SpirvShader::DescriptorDecorations &src)
1549{
1550 if(src.DescriptorSet >= 0)
1551 {
1552 DescriptorSet = src.DescriptorSet;
1553 }
1554
1555 if(src.Binding >= 0)
1556 {
1557 Binding = src.Binding;
1558 }
1559
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001560 if(src.InputAttachmentIndex >= 0)
Nicolas Capens157ba262019-12-10 17:49:14 -05001561 {
1562 InputAttachmentIndex = src.InputAttachmentIndex;
1563 }
1564}
1565
1566void SpirvShader::ApplyDecorationsForId(Decorations *d, TypeOrObjectID id) const
1567{
1568 auto it = decorations.find(id);
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001569 if(it != decorations.end())
Nicolas Capens157ba262019-12-10 17:49:14 -05001570 d->Apply(it->second);
1571}
1572
1573void SpirvShader::ApplyDecorationsForIdMember(Decorations *d, Type::ID id, uint32_t member) const
1574{
1575 auto it = memberDecorations.find(id);
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001576 if(it != memberDecorations.end() && member < it->second.size())
Nicolas Capens157ba262019-12-10 17:49:14 -05001577 {
1578 d->Apply(it->second[member]);
1579 }
1580}
1581
1582void SpirvShader::DefineResult(const InsnIterator &insn)
1583{
1584 Type::ID typeId = insn.word(1);
1585 Object::ID resultId = insn.word(2);
1586 auto &object = defs[resultId];
Nicolas Capens157ba262019-12-10 17:49:14 -05001587
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001588 switch(getType(typeId).opcode())
Nicolas Capens157ba262019-12-10 17:49:14 -05001589 {
Nicolas Capens112faf42019-12-13 17:32:26 -05001590 case spv::OpTypePointer:
1591 case spv::OpTypeImage:
1592 case spv::OpTypeSampledImage:
1593 case spv::OpTypeSampler:
1594 object.kind = Object::Kind::Pointer;
1595 break;
Nicolas Capens157ba262019-12-10 17:49:14 -05001596
Nicolas Capens112faf42019-12-13 17:32:26 -05001597 default:
1598 object.kind = Object::Kind::Intermediate;
Nicolas Capens157ba262019-12-10 17:49:14 -05001599 }
1600
1601 object.definition = insn;
Ben Claytonb0ca2a82020-01-08 13:00:57 +00001602 dbgDeclareResult(insn, resultId);
Nicolas Capens157ba262019-12-10 17:49:14 -05001603}
1604
1605OutOfBoundsBehavior SpirvShader::EmitState::getOutOfBoundsBehavior(spv::StorageClass storageClass) const
1606{
1607 switch(storageClass)
1608 {
Nicolas Capens112faf42019-12-13 17:32:26 -05001609 case spv::StorageClassUniform:
1610 case spv::StorageClassStorageBuffer:
1611 // Buffer resource access. robustBufferAccess feature applies.
1612 return robustBufferAccess ? OutOfBoundsBehavior::RobustBufferAccess
1613 : OutOfBoundsBehavior::UndefinedBehavior;
1614
1615 case spv::StorageClassImage:
1616 // VK_EXT_image_robustness requires nullifying out-of-bounds accesses.
1617 // TODO(b/162327166): Only perform bounds checks when VK_EXT_image_robustness is enabled.
1618 return OutOfBoundsBehavior::Nullify;
1619
1620 case spv::StorageClassInput:
1621 if(executionModel == spv::ExecutionModelVertex)
1622 {
1623 // Vertex attributes follow robustBufferAccess rules.
Nicolas Capens157ba262019-12-10 17:49:14 -05001624 return robustBufferAccess ? OutOfBoundsBehavior::RobustBufferAccess
1625 : OutOfBoundsBehavior::UndefinedBehavior;
Nicolas Capens112faf42019-12-13 17:32:26 -05001626 }
1627 // Fall through to default case.
1628 default:
Nicolas Capense4b77942021-08-03 17:09:41 -04001629 // TODO(b/192310780): StorageClassFunction out-of-bounds accesses are undefined behavior.
Nicolas Capens112faf42019-12-13 17:32:26 -05001630 // TODO(b/137183137): Optimize if the pointer resulted from OpInBoundsAccessChain.
1631 // TODO(b/131224163): Optimize cases statically known to be within bounds.
1632 return OutOfBoundsBehavior::UndefinedValue;
Nicolas Capens157ba262019-12-10 17:49:14 -05001633 }
1634
1635 return OutOfBoundsBehavior::Nullify;
1636}
1637
1638// emit-time
1639
1640void SpirvShader::emitProlog(SpirvRoutine *routine) const
1641{
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001642 for(auto insn : *this)
Nicolas Capens157ba262019-12-10 17:49:14 -05001643 {
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001644 switch(insn.opcode())
Nicolas Capens157ba262019-12-10 17:49:14 -05001645 {
Nicolas Capens112faf42019-12-13 17:32:26 -05001646 case spv::OpVariable:
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001647 {
Nicolas Capens71186752020-04-09 01:05:31 -04001648 auto resultPointerType = getType(insn.resultTypeId());
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001649 auto pointeeType = getType(resultPointerType.element);
Nicolas Capens157ba262019-12-10 17:49:14 -05001650
Nicolas Capensff9f9b52020-04-14 00:46:38 -04001651 if(pointeeType.componentCount > 0) // TODO: what to do about zero-slot objects?
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001652 {
Nicolas Capensff9f9b52020-04-14 00:46:38 -04001653 routine->createVariable(insn.resultId(), pointeeType.componentCount);
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001654 }
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001655 }
Nicolas Capens112faf42019-12-13 17:32:26 -05001656 break;
1657
1658 case spv::OpPhi:
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001659 {
Nicolas Capens71186752020-04-09 01:05:31 -04001660 auto type = getType(insn.resultTypeId());
Nicolas Capensff9f9b52020-04-14 00:46:38 -04001661 routine->phis.emplace(insn.resultId(), SpirvRoutine::Variable(type.componentCount));
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001662 }
Nicolas Capens112faf42019-12-13 17:32:26 -05001663 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001664
Nicolas Capensf0e8ec22021-11-12 13:57:14 -05001665 case spv::OpImageSampleImplicitLod:
1666 case spv::OpImageSampleExplicitLod:
1667 case spv::OpImageSampleDrefImplicitLod:
1668 case spv::OpImageSampleDrefExplicitLod:
1669 case spv::OpImageSampleProjImplicitLod:
1670 case spv::OpImageSampleProjExplicitLod:
1671 case spv::OpImageSampleProjDrefImplicitLod:
1672 case spv::OpImageSampleProjDrefExplicitLod:
Nicolas Capens112faf42019-12-13 17:32:26 -05001673 case spv::OpImageFetch:
1674 case spv::OpImageGather:
Nicolas Capensf0e8ec22021-11-12 13:57:14 -05001675 case spv::OpImageDrefGather:
1676 case spv::OpImageWrite:
Nicolas Capens112faf42019-12-13 17:32:26 -05001677 case spv::OpImageQueryLod:
Nicolas Capens96b34f72021-11-09 00:41:40 -05001678 {
1679 // The 'inline' sampler caches must be created in the prolog to initialize the tags.
1680 uint32_t instructionPosition = insn.distanceFrom(this->begin());
1681 routine->samplerCache.emplace(instructionPosition, SpirvRoutine::SamplerCache{});
1682 }
Nicolas Capens112faf42019-12-13 17:32:26 -05001683 break;
Nicolas Capens157ba262019-12-10 17:49:14 -05001684
Nicolas Capens112faf42019-12-13 17:32:26 -05001685 default:
1686 // Nothing else produces interface variables, so can all be safely ignored.
1687 break;
Nicolas Capens157ba262019-12-10 17:49:14 -05001688 }
1689 }
1690}
1691
Alexis Hetu0bcb71f2021-01-14 12:05:12 -05001692void 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 -05001693{
Alexis Hetu0bcb71f2021-01-14 12:05:12 -05001694 EmitState state(routine, entryPoint, activeLaneMask, storesAndAtomicsMask, descriptorSets, robustBufferAccess, multiSampleCount, executionModel);
Nicolas Capens157ba262019-12-10 17:49:14 -05001695
Ben Claytonb0ca2a82020-01-08 13:00:57 +00001696 dbgBeginEmit(&state);
1697 defer(dbgEndEmit(&state));
1698
Nicolas Capens157ba262019-12-10 17:49:14 -05001699 // Emit everything up to the first label
1700 // TODO: Separate out dispatch of block from non-block instructions?
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001701 for(auto insn : *this)
Nicolas Capens157ba262019-12-10 17:49:14 -05001702 {
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001703 if(insn.opcode() == spv::OpLabel)
Nicolas Capens157ba262019-12-10 17:49:14 -05001704 {
1705 break;
1706 }
1707 EmitInstruction(insn, &state);
1708 }
1709
1710 // Emit all the blocks starting from entryPoint.
1711 EmitBlocks(getFunction(entryPoint).entry, &state);
1712}
1713
1714void SpirvShader::EmitInstructions(InsnIterator begin, InsnIterator end, EmitState *state) const
1715{
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001716 for(auto insn = begin; insn != end; insn++)
Nicolas Capens157ba262019-12-10 17:49:14 -05001717 {
1718 auto res = EmitInstruction(insn, state);
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001719 switch(res)
Nicolas Capens157ba262019-12-10 17:49:14 -05001720 {
Nicolas Capens112faf42019-12-13 17:32:26 -05001721 case EmitResult::Continue:
1722 continue;
1723 case EmitResult::Terminator:
1724 break;
1725 default:
1726 UNREACHABLE("Unexpected EmitResult %d", int(res));
1727 break;
Nicolas Capens157ba262019-12-10 17:49:14 -05001728 }
1729 }
1730}
1731
1732SpirvShader::EmitResult SpirvShader::EmitInstruction(InsnIterator insn, EmitState *state) const
1733{
Ben Claytonb0ca2a82020-01-08 13:00:57 +00001734 dbgBeginEmitInstruction(insn, state);
1735 defer(dbgEndEmitInstruction(insn, state));
1736
Nicolas Capens157ba262019-12-10 17:49:14 -05001737 auto opcode = insn.opcode();
1738
Ben Claytonfc951cd2019-05-15 17:16:56 +01001739#if SPIRV_SHADER_ENABLE_DBG
1740 {
1741 auto text = spvtools::spvInstructionBinaryToText(
Sean Risser019feda2020-11-09 14:19:27 -05001742 vk::SPIRV_VERSION,
Ben Claytonfc951cd2019-05-15 17:16:56 +01001743 insn.wordPointer(0),
1744 insn.wordCount(),
1745 insns.data(),
1746 insns.size(),
1747 SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
1748 SPIRV_SHADER_DBG("{0}", text);
1749 }
1750#endif // ENABLE_DBG_MSGS
1751
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001752 switch(opcode)
Nicolas Capens157ba262019-12-10 17:49:14 -05001753 {
Nicolas Capens112faf42019-12-13 17:32:26 -05001754 case spv::OpTypeVoid:
1755 case spv::OpTypeInt:
1756 case spv::OpTypeFloat:
1757 case spv::OpTypeBool:
1758 case spv::OpTypeVector:
1759 case spv::OpTypeArray:
1760 case spv::OpTypeRuntimeArray:
1761 case spv::OpTypeMatrix:
1762 case spv::OpTypeStruct:
1763 case spv::OpTypePointer:
1764 case spv::OpTypeFunction:
1765 case spv::OpTypeImage:
1766 case spv::OpTypeSampledImage:
1767 case spv::OpTypeSampler:
1768 case spv::OpExecutionMode:
1769 case spv::OpMemoryModel:
1770 case spv::OpFunction:
1771 case spv::OpFunctionEnd:
1772 case spv::OpConstant:
1773 case spv::OpConstantNull:
1774 case spv::OpConstantTrue:
1775 case spv::OpConstantFalse:
1776 case spv::OpConstantComposite:
1777 case spv::OpSpecConstant:
1778 case spv::OpSpecConstantTrue:
1779 case spv::OpSpecConstantFalse:
1780 case spv::OpSpecConstantComposite:
1781 case spv::OpSpecConstantOp:
1782 case spv::OpUndef:
1783 case spv::OpExtension:
1784 case spv::OpCapability:
1785 case spv::OpEntryPoint:
1786 case spv::OpExtInstImport:
1787 case spv::OpDecorate:
1788 case spv::OpMemberDecorate:
1789 case spv::OpGroupDecorate:
1790 case spv::OpGroupMemberDecorate:
1791 case spv::OpDecorationGroup:
1792 case spv::OpDecorateId:
1793 case spv::OpDecorateString:
1794 case spv::OpMemberDecorateString:
1795 case spv::OpName:
1796 case spv::OpMemberName:
1797 case spv::OpSource:
1798 case spv::OpSourceContinued:
1799 case spv::OpSourceExtension:
1800 case spv::OpNoLine:
1801 case spv::OpModuleProcessed:
1802 case spv::OpString:
1803 // Nothing to do at emit time. These are either fully handled at analysis time,
1804 // or don't require any work at all.
1805 return EmitResult::Continue;
Nicolas Capens157ba262019-12-10 17:49:14 -05001806
Nicolas Capens112faf42019-12-13 17:32:26 -05001807 case spv::OpLine:
1808 return EmitLine(insn, state);
Ben Claytonb0ca2a82020-01-08 13:00:57 +00001809
Nicolas Capens112faf42019-12-13 17:32:26 -05001810 case spv::OpLabel:
1811 return EmitResult::Continue;
Nicolas Capens157ba262019-12-10 17:49:14 -05001812
Nicolas Capens112faf42019-12-13 17:32:26 -05001813 case spv::OpVariable:
1814 return EmitVariable(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001815
Nicolas Capens112faf42019-12-13 17:32:26 -05001816 case spv::OpLoad:
1817 case spv::OpAtomicLoad:
1818 return EmitLoad(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001819
Nicolas Capens112faf42019-12-13 17:32:26 -05001820 case spv::OpStore:
1821 case spv::OpAtomicStore:
1822 return EmitStore(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001823
Nicolas Capens112faf42019-12-13 17:32:26 -05001824 case spv::OpAtomicIAdd:
1825 case spv::OpAtomicISub:
1826 case spv::OpAtomicSMin:
1827 case spv::OpAtomicSMax:
1828 case spv::OpAtomicUMin:
1829 case spv::OpAtomicUMax:
1830 case spv::OpAtomicAnd:
1831 case spv::OpAtomicOr:
1832 case spv::OpAtomicXor:
1833 case spv::OpAtomicIIncrement:
1834 case spv::OpAtomicIDecrement:
1835 case spv::OpAtomicExchange:
1836 return EmitAtomicOp(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001837
Nicolas Capens112faf42019-12-13 17:32:26 -05001838 case spv::OpAtomicCompareExchange:
1839 return EmitAtomicCompareExchange(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001840
Nicolas Capens112faf42019-12-13 17:32:26 -05001841 case spv::OpAccessChain:
1842 case spv::OpInBoundsAccessChain:
1843 return EmitAccessChain(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001844
Nicolas Capens112faf42019-12-13 17:32:26 -05001845 case spv::OpCompositeConstruct:
1846 return EmitCompositeConstruct(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001847
Nicolas Capens112faf42019-12-13 17:32:26 -05001848 case spv::OpCompositeInsert:
1849 return EmitCompositeInsert(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001850
Nicolas Capens112faf42019-12-13 17:32:26 -05001851 case spv::OpCompositeExtract:
1852 return EmitCompositeExtract(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001853
Nicolas Capens112faf42019-12-13 17:32:26 -05001854 case spv::OpVectorShuffle:
1855 return EmitVectorShuffle(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001856
Nicolas Capens112faf42019-12-13 17:32:26 -05001857 case spv::OpVectorExtractDynamic:
1858 return EmitVectorExtractDynamic(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001859
Nicolas Capens112faf42019-12-13 17:32:26 -05001860 case spv::OpVectorInsertDynamic:
1861 return EmitVectorInsertDynamic(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001862
Nicolas Capens112faf42019-12-13 17:32:26 -05001863 case spv::OpVectorTimesScalar:
1864 case spv::OpMatrixTimesScalar:
1865 return EmitVectorTimesScalar(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001866
Nicolas Capens112faf42019-12-13 17:32:26 -05001867 case spv::OpMatrixTimesVector:
1868 return EmitMatrixTimesVector(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001869
Nicolas Capens112faf42019-12-13 17:32:26 -05001870 case spv::OpVectorTimesMatrix:
1871 return EmitVectorTimesMatrix(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001872
Nicolas Capens112faf42019-12-13 17:32:26 -05001873 case spv::OpMatrixTimesMatrix:
1874 return EmitMatrixTimesMatrix(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001875
Nicolas Capens112faf42019-12-13 17:32:26 -05001876 case spv::OpOuterProduct:
1877 return EmitOuterProduct(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001878
Nicolas Capens112faf42019-12-13 17:32:26 -05001879 case spv::OpTranspose:
1880 return EmitTranspose(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001881
Nicolas Capens112faf42019-12-13 17:32:26 -05001882 case spv::OpNot:
1883 case spv::OpBitFieldInsert:
1884 case spv::OpBitFieldSExtract:
1885 case spv::OpBitFieldUExtract:
1886 case spv::OpBitReverse:
1887 case spv::OpBitCount:
1888 case spv::OpSNegate:
1889 case spv::OpFNegate:
1890 case spv::OpLogicalNot:
1891 case spv::OpConvertFToU:
1892 case spv::OpConvertFToS:
1893 case spv::OpConvertSToF:
1894 case spv::OpConvertUToF:
1895 case spv::OpBitcast:
1896 case spv::OpIsInf:
1897 case spv::OpIsNan:
1898 case spv::OpDPdx:
1899 case spv::OpDPdxCoarse:
1900 case spv::OpDPdy:
1901 case spv::OpDPdyCoarse:
1902 case spv::OpFwidth:
1903 case spv::OpFwidthCoarse:
1904 case spv::OpDPdxFine:
1905 case spv::OpDPdyFine:
1906 case spv::OpFwidthFine:
1907 case spv::OpQuantizeToF16:
1908 return EmitUnaryOp(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001909
Nicolas Capens112faf42019-12-13 17:32:26 -05001910 case spv::OpIAdd:
1911 case spv::OpISub:
1912 case spv::OpIMul:
1913 case spv::OpSDiv:
1914 case spv::OpUDiv:
1915 case spv::OpFAdd:
1916 case spv::OpFSub:
1917 case spv::OpFMul:
1918 case spv::OpFDiv:
1919 case spv::OpFMod:
1920 case spv::OpFRem:
1921 case spv::OpFOrdEqual:
1922 case spv::OpFUnordEqual:
1923 case spv::OpFOrdNotEqual:
1924 case spv::OpFUnordNotEqual:
1925 case spv::OpFOrdLessThan:
1926 case spv::OpFUnordLessThan:
1927 case spv::OpFOrdGreaterThan:
1928 case spv::OpFUnordGreaterThan:
1929 case spv::OpFOrdLessThanEqual:
1930 case spv::OpFUnordLessThanEqual:
1931 case spv::OpFOrdGreaterThanEqual:
1932 case spv::OpFUnordGreaterThanEqual:
1933 case spv::OpSMod:
1934 case spv::OpSRem:
1935 case spv::OpUMod:
1936 case spv::OpIEqual:
1937 case spv::OpINotEqual:
1938 case spv::OpUGreaterThan:
1939 case spv::OpSGreaterThan:
1940 case spv::OpUGreaterThanEqual:
1941 case spv::OpSGreaterThanEqual:
1942 case spv::OpULessThan:
1943 case spv::OpSLessThan:
1944 case spv::OpULessThanEqual:
1945 case spv::OpSLessThanEqual:
1946 case spv::OpShiftRightLogical:
1947 case spv::OpShiftRightArithmetic:
1948 case spv::OpShiftLeftLogical:
1949 case spv::OpBitwiseOr:
1950 case spv::OpBitwiseXor:
1951 case spv::OpBitwiseAnd:
1952 case spv::OpLogicalOr:
1953 case spv::OpLogicalAnd:
1954 case spv::OpLogicalEqual:
1955 case spv::OpLogicalNotEqual:
1956 case spv::OpUMulExtended:
1957 case spv::OpSMulExtended:
1958 case spv::OpIAddCarry:
1959 case spv::OpISubBorrow:
1960 return EmitBinaryOp(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001961
Nicolas Capens112faf42019-12-13 17:32:26 -05001962 case spv::OpDot:
1963 return EmitDot(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001964
Nicolas Capens112faf42019-12-13 17:32:26 -05001965 case spv::OpSelect:
1966 return EmitSelect(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001967
Nicolas Capens112faf42019-12-13 17:32:26 -05001968 case spv::OpExtInst:
1969 return EmitExtendedInstruction(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001970
Nicolas Capens112faf42019-12-13 17:32:26 -05001971 case spv::OpAny:
1972 return EmitAny(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001973
Nicolas Capens112faf42019-12-13 17:32:26 -05001974 case spv::OpAll:
1975 return EmitAll(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001976
Nicolas Capens112faf42019-12-13 17:32:26 -05001977 case spv::OpBranch:
1978 return EmitBranch(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001979
Nicolas Capens112faf42019-12-13 17:32:26 -05001980 case spv::OpPhi:
1981 return EmitPhi(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001982
Nicolas Capens112faf42019-12-13 17:32:26 -05001983 case spv::OpSelectionMerge:
1984 case spv::OpLoopMerge:
1985 return EmitResult::Continue;
Nicolas Capens157ba262019-12-10 17:49:14 -05001986
Nicolas Capens112faf42019-12-13 17:32:26 -05001987 case spv::OpBranchConditional:
1988 return EmitBranchConditional(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001989
Nicolas Capens112faf42019-12-13 17:32:26 -05001990 case spv::OpSwitch:
1991 return EmitSwitch(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001992
Nicolas Capens112faf42019-12-13 17:32:26 -05001993 case spv::OpUnreachable:
1994 return EmitUnreachable(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001995
Nicolas Capens112faf42019-12-13 17:32:26 -05001996 case spv::OpReturn:
1997 return EmitReturn(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001998
Nicolas Capens112faf42019-12-13 17:32:26 -05001999 case spv::OpFunctionCall:
2000 return EmitFunctionCall(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002001
Nicolas Capens112faf42019-12-13 17:32:26 -05002002 case spv::OpKill:
2003 return EmitKill(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002004
Nicolas Capens112faf42019-12-13 17:32:26 -05002005 case spv::OpImageSampleImplicitLod:
Nicolas Capens112faf42019-12-13 17:32:26 -05002006 case spv::OpImageSampleExplicitLod:
Nicolas Capens112faf42019-12-13 17:32:26 -05002007 case spv::OpImageSampleDrefImplicitLod:
Nicolas Capens112faf42019-12-13 17:32:26 -05002008 case spv::OpImageSampleDrefExplicitLod:
Nicolas Capens112faf42019-12-13 17:32:26 -05002009 case spv::OpImageSampleProjImplicitLod:
Nicolas Capens112faf42019-12-13 17:32:26 -05002010 case spv::OpImageSampleProjExplicitLod:
Nicolas Capens112faf42019-12-13 17:32:26 -05002011 case spv::OpImageSampleProjDrefImplicitLod:
Nicolas Capens112faf42019-12-13 17:32:26 -05002012 case spv::OpImageSampleProjDrefExplicitLod:
Nicolas Capens112faf42019-12-13 17:32:26 -05002013 case spv::OpImageGather:
Nicolas Capens112faf42019-12-13 17:32:26 -05002014 case spv::OpImageDrefGather:
Nicolas Capens112faf42019-12-13 17:32:26 -05002015 case spv::OpImageFetch:
Nicolas Capens05963ef2021-11-08 20:27:35 -05002016 case spv::OpImageQueryLod:
Nicolas Capens6745fce2021-11-04 16:01:31 -04002017 return EmitImageSample(ImageInstruction(insn, *this), state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002018
Nicolas Capens112faf42019-12-13 17:32:26 -05002019 case spv::OpImageQuerySizeLod:
2020 return EmitImageQuerySizeLod(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002021
Nicolas Capens112faf42019-12-13 17:32:26 -05002022 case spv::OpImageQuerySize:
2023 return EmitImageQuerySize(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002024
Nicolas Capens112faf42019-12-13 17:32:26 -05002025 case spv::OpImageQueryLevels:
2026 return EmitImageQueryLevels(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002027
Nicolas Capens112faf42019-12-13 17:32:26 -05002028 case spv::OpImageQuerySamples:
2029 return EmitImageQuerySamples(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002030
Nicolas Capens112faf42019-12-13 17:32:26 -05002031 case spv::OpImageRead:
Nicolas Capens6745fce2021-11-04 16:01:31 -04002032 return EmitImageRead(ImageInstruction(insn, *this), state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002033
Nicolas Capens112faf42019-12-13 17:32:26 -05002034 case spv::OpImageWrite:
Nicolas Capens6745fce2021-11-04 16:01:31 -04002035 return EmitImageWrite(ImageInstruction(insn, *this), state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002036
Nicolas Capens112faf42019-12-13 17:32:26 -05002037 case spv::OpImageTexelPointer:
Nicolas Capens0b241e72021-11-11 01:49:50 -05002038 return EmitImageTexelPointer(ImageInstruction(insn, *this), state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002039
Nicolas Capens112faf42019-12-13 17:32:26 -05002040 case spv::OpSampledImage:
2041 case spv::OpImage:
2042 return EmitSampledImageCombineOrSplit(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002043
Nicolas Capens112faf42019-12-13 17:32:26 -05002044 case spv::OpCopyObject:
2045 case spv::OpCopyLogical:
2046 return EmitCopyObject(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002047
Nicolas Capens112faf42019-12-13 17:32:26 -05002048 case spv::OpCopyMemory:
2049 return EmitCopyMemory(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002050
Nicolas Capens112faf42019-12-13 17:32:26 -05002051 case spv::OpControlBarrier:
2052 return EmitControlBarrier(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002053
Nicolas Capens112faf42019-12-13 17:32:26 -05002054 case spv::OpMemoryBarrier:
2055 return EmitMemoryBarrier(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002056
Nicolas Capens112faf42019-12-13 17:32:26 -05002057 case spv::OpGroupNonUniformElect:
2058 case spv::OpGroupNonUniformAll:
2059 case spv::OpGroupNonUniformAny:
2060 case spv::OpGroupNonUniformAllEqual:
2061 case spv::OpGroupNonUniformBroadcast:
2062 case spv::OpGroupNonUniformBroadcastFirst:
2063 case spv::OpGroupNonUniformBallot:
2064 case spv::OpGroupNonUniformInverseBallot:
2065 case spv::OpGroupNonUniformBallotBitExtract:
2066 case spv::OpGroupNonUniformBallotBitCount:
2067 case spv::OpGroupNonUniformBallotFindLSB:
2068 case spv::OpGroupNonUniformBallotFindMSB:
2069 case spv::OpGroupNonUniformShuffle:
2070 case spv::OpGroupNonUniformShuffleXor:
2071 case spv::OpGroupNonUniformShuffleUp:
2072 case spv::OpGroupNonUniformShuffleDown:
2073 case spv::OpGroupNonUniformIAdd:
2074 case spv::OpGroupNonUniformFAdd:
2075 case spv::OpGroupNonUniformIMul:
2076 case spv::OpGroupNonUniformFMul:
2077 case spv::OpGroupNonUniformSMin:
2078 case spv::OpGroupNonUniformUMin:
2079 case spv::OpGroupNonUniformFMin:
2080 case spv::OpGroupNonUniformSMax:
2081 case spv::OpGroupNonUniformUMax:
2082 case spv::OpGroupNonUniformFMax:
2083 case spv::OpGroupNonUniformBitwiseAnd:
2084 case spv::OpGroupNonUniformBitwiseOr:
2085 case spv::OpGroupNonUniformBitwiseXor:
2086 case spv::OpGroupNonUniformLogicalAnd:
2087 case spv::OpGroupNonUniformLogicalOr:
2088 case spv::OpGroupNonUniformLogicalXor:
2089 return EmitGroupNonUniform(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002090
Nicolas Capens112faf42019-12-13 17:32:26 -05002091 case spv::OpArrayLength:
2092 return EmitArrayLength(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002093
Nicolas Capens112faf42019-12-13 17:32:26 -05002094 default:
2095 UNREACHABLE("%s", OpcodeName(opcode));
2096 break;
Nicolas Capens157ba262019-12-10 17:49:14 -05002097 }
2098
2099 return EmitResult::Continue;
2100}
2101
2102SpirvShader::EmitResult SpirvShader::EmitAccessChain(InsnIterator insn, EmitState *state) const
2103{
2104 Type::ID typeId = insn.word(1);
2105 Object::ID resultId = insn.word(2);
2106 Object::ID baseId = insn.word(3);
2107 uint32_t numIndexes = insn.wordCount() - 4;
2108 const uint32_t *indexes = insn.wordPointer(4);
2109 auto &type = getType(typeId);
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002110 ASSERT(type.componentCount == 1);
Nicolas Capens157ba262019-12-10 17:49:14 -05002111 ASSERT(getObject(resultId).kind == Object::Kind::Pointer);
2112
2113 if(type.storageClass == spv::StorageClassPushConstant ||
2114 type.storageClass == spv::StorageClassUniform ||
2115 type.storageClass == spv::StorageClassStorageBuffer)
2116 {
2117 auto ptr = WalkExplicitLayoutAccessChain(baseId, numIndexes, indexes, state);
2118 state->createPointer(resultId, ptr);
2119 }
2120 else
2121 {
2122 auto ptr = WalkAccessChain(baseId, numIndexes, indexes, state);
2123 state->createPointer(resultId, ptr);
2124 }
2125
2126 return EmitResult::Continue;
2127}
2128
2129SpirvShader::EmitResult SpirvShader::EmitCompositeConstruct(InsnIterator insn, EmitState *state) const
2130{
Nicolas Capens71186752020-04-09 01:05:31 -04002131 auto &type = getType(insn.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 offset = 0u;
2134
Nicolas Capens81bc9d92019-12-16 15:05:57 -05002135 for(auto i = 0u; i < insn.wordCount() - 3; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002136 {
2137 Object::ID srcObjectId = insn.word(3u + i);
Ben Claytonbc1c067be2019-12-17 20:37:37 +00002138 auto &srcObject = getObject(srcObjectId);
Nicolas Capens72f089c2020-04-08 23:37:08 -04002139 auto &srcObjectTy = getType(srcObject);
Nicolas Capense6f65d92020-04-08 21:55:43 -04002140 Operand srcObjectAccess(this, state, srcObjectId);
Nicolas Capens157ba262019-12-10 17:49:14 -05002141
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002142 for(auto j = 0u; j < srcObjectTy.componentCount; j++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002143 {
2144 dst.move(offset++, srcObjectAccess.Float(j));
2145 }
2146 }
2147
2148 return EmitResult::Continue;
2149}
2150
2151SpirvShader::EmitResult SpirvShader::EmitCompositeInsert(InsnIterator insn, EmitState *state) const
2152{
2153 Type::ID resultTypeId = insn.word(1);
2154 auto &type = getType(resultTypeId);
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002155 auto &dst = state->createIntermediate(insn.resultId(), type.componentCount);
Nicolas Capens157ba262019-12-10 17:49:14 -05002156 auto &newPartObject = getObject(insn.word(3));
Nicolas Capens72f089c2020-04-08 23:37:08 -04002157 auto &newPartObjectTy = getType(newPartObject);
Nicolas Capens157ba262019-12-10 17:49:14 -05002158 auto firstNewComponent = WalkLiteralAccessChain(resultTypeId, insn.wordCount() - 5, insn.wordPointer(5));
2159
Nicolas Capense6f65d92020-04-08 21:55:43 -04002160 Operand srcObjectAccess(this, state, insn.word(4));
2161 Operand newPartObjectAccess(this, state, insn.word(3));
Nicolas Capens157ba262019-12-10 17:49:14 -05002162
2163 // old components before
Nicolas Capens81bc9d92019-12-16 15:05:57 -05002164 for(auto i = 0u; i < firstNewComponent; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002165 {
2166 dst.move(i, srcObjectAccess.Float(i));
2167 }
2168 // new part
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002169 for(auto i = 0u; i < newPartObjectTy.componentCount; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002170 {
2171 dst.move(firstNewComponent + i, newPartObjectAccess.Float(i));
2172 }
2173 // old components after
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002174 for(auto i = firstNewComponent + newPartObjectTy.componentCount; i < type.componentCount; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002175 {
2176 dst.move(i, srcObjectAccess.Float(i));
2177 }
2178
2179 return EmitResult::Continue;
2180}
2181
2182SpirvShader::EmitResult SpirvShader::EmitCompositeExtract(InsnIterator insn, EmitState *state) const
2183{
Nicolas Capens71186752020-04-09 01:05:31 -04002184 auto &type = getType(insn.resultTypeId());
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002185 auto &dst = state->createIntermediate(insn.resultId(), type.componentCount);
Nicolas Capens157ba262019-12-10 17:49:14 -05002186 auto &compositeObject = getObject(insn.word(3));
2187 Type::ID compositeTypeId = compositeObject.definition.word(1);
2188 auto firstComponent = WalkLiteralAccessChain(compositeTypeId, insn.wordCount() - 4, insn.wordPointer(4));
2189
Nicolas Capense6f65d92020-04-08 21:55:43 -04002190 Operand compositeObjectAccess(this, state, insn.word(3));
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002191 for(auto i = 0u; i < type.componentCount; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002192 {
2193 dst.move(i, compositeObjectAccess.Float(firstComponent + i));
2194 }
2195
2196 return EmitResult::Continue;
2197}
2198
2199SpirvShader::EmitResult SpirvShader::EmitVectorShuffle(InsnIterator insn, EmitState *state) const
2200{
Nicolas Capens71186752020-04-09 01:05:31 -04002201 auto &type = getType(insn.resultTypeId());
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002202 auto &dst = state->createIntermediate(insn.resultId(), type.componentCount);
Nicolas Capens157ba262019-12-10 17:49:14 -05002203
2204 // Note: number of components in result type, first half type, and second
2205 // half type are all independent.
Nicolas Capense7355b92021-11-08 22:48:34 -05002206 auto &firstHalfType = getObjectType(insn.word(3));
Nicolas Capens157ba262019-12-10 17:49:14 -05002207
Nicolas Capense6f65d92020-04-08 21:55:43 -04002208 Operand firstHalfAccess(this, state, insn.word(3));
2209 Operand secondHalfAccess(this, state, insn.word(4));
Nicolas Capens157ba262019-12-10 17:49:14 -05002210
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002211 for(auto i = 0u; i < type.componentCount; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002212 {
2213 auto selector = insn.word(5 + i);
Nicolas Capens81bc9d92019-12-16 15:05:57 -05002214 if(selector == static_cast<uint32_t>(-1))
Nicolas Capens157ba262019-12-10 17:49:14 -05002215 {
2216 // Undefined value. Until we decide to do real undef values, zero is as good
2217 // a value as any
2218 dst.move(i, RValue<SIMD::Float>(0.0f));
2219 }
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002220 else if(selector < firstHalfType.componentCount)
Nicolas Capens157ba262019-12-10 17:49:14 -05002221 {
2222 dst.move(i, firstHalfAccess.Float(selector));
2223 }
2224 else
2225 {
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002226 dst.move(i, secondHalfAccess.Float(selector - firstHalfType.componentCount));
Nicolas Capens157ba262019-12-10 17:49:14 -05002227 }
2228 }
2229
2230 return EmitResult::Continue;
2231}
2232
2233SpirvShader::EmitResult SpirvShader::EmitVectorExtractDynamic(InsnIterator insn, EmitState *state) const
2234{
Nicolas Capens71186752020-04-09 01:05:31 -04002235 auto &type = getType(insn.resultTypeId());
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002236 auto &dst = state->createIntermediate(insn.resultId(), type.componentCount);
Nicolas Capense7355b92021-11-08 22:48:34 -05002237 auto &srcType = getObjectType(insn.word(3));
Nicolas Capens157ba262019-12-10 17:49:14 -05002238
Nicolas Capense6f65d92020-04-08 21:55:43 -04002239 Operand src(this, state, insn.word(3));
2240 Operand index(this, state, insn.word(4));
Nicolas Capens157ba262019-12-10 17:49:14 -05002241
2242 SIMD::UInt v = SIMD::UInt(0);
2243
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002244 for(auto i = 0u; i < srcType.componentCount; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002245 {
2246 v |= CmpEQ(index.UInt(0), SIMD::UInt(i)) & src.UInt(i);
2247 }
2248
2249 dst.move(0, v);
2250 return EmitResult::Continue;
2251}
2252
2253SpirvShader::EmitResult SpirvShader::EmitVectorInsertDynamic(InsnIterator insn, EmitState *state) const
2254{
Nicolas Capens71186752020-04-09 01:05:31 -04002255 auto &type = getType(insn.resultTypeId());
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002256 auto &dst = state->createIntermediate(insn.resultId(), type.componentCount);
Nicolas Capens157ba262019-12-10 17:49:14 -05002257
Nicolas Capense6f65d92020-04-08 21:55:43 -04002258 Operand src(this, state, insn.word(3));
2259 Operand component(this, state, insn.word(4));
2260 Operand index(this, state, insn.word(5));
Nicolas Capens157ba262019-12-10 17:49:14 -05002261
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002262 for(auto i = 0u; i < type.componentCount; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002263 {
2264 SIMD::UInt mask = CmpEQ(SIMD::UInt(i), index.UInt(0));
2265 dst.move(i, (src.UInt(i) & ~mask) | (component.UInt(0) & mask));
2266 }
2267 return EmitResult::Continue;
2268}
2269
2270SpirvShader::EmitResult SpirvShader::EmitSelect(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 auto &dst = state->createIntermediate(insn.resultId(), type.componentCount);
Nicolas Capense6f65d92020-04-08 21:55:43 -04002274 auto cond = Operand(this, state, insn.word(3));
Nicolas Capens2f4b6032020-04-09 02:01:50 -04002275 auto condIsScalar = (cond.componentCount == 1);
Nicolas Capense6f65d92020-04-08 21:55:43 -04002276 auto lhs = Operand(this, state, insn.word(4));
2277 auto rhs = Operand(this, state, insn.word(5));
Nicolas Capens157ba262019-12-10 17:49:14 -05002278
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002279 for(auto i = 0u; i < type.componentCount; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002280 {
2281 auto sel = cond.Int(condIsScalar ? 0 : i);
Ben Claytonbc1c067be2019-12-17 20:37:37 +00002282 dst.move(i, (sel & lhs.Int(i)) | (~sel & rhs.Int(i))); // TODO: IfThenElse()
Nicolas Capens157ba262019-12-10 17:49:14 -05002283 }
2284
Ben Claytonfc951cd2019-05-15 17:16:56 +01002285 SPIRV_SHADER_DBG("{0}: {1}", insn.word(2), dst);
2286 SPIRV_SHADER_DBG("{0}: {1}", insn.word(3), cond);
2287 SPIRV_SHADER_DBG("{0}: {1}", insn.word(4), lhs);
2288 SPIRV_SHADER_DBG("{0}: {1}", insn.word(5), rhs);
2289
Nicolas Capens157ba262019-12-10 17:49:14 -05002290 return EmitResult::Continue;
2291}
2292
2293SpirvShader::EmitResult SpirvShader::EmitAny(InsnIterator insn, EmitState *state) const
2294{
Nicolas Capens71186752020-04-09 01:05:31 -04002295 auto &type = getType(insn.resultTypeId());
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002296 ASSERT(type.componentCount == 1);
2297 auto &dst = state->createIntermediate(insn.resultId(), type.componentCount);
Nicolas Capense7355b92021-11-08 22:48:34 -05002298 auto &srcType = getObjectType(insn.word(3));
Nicolas Capense6f65d92020-04-08 21:55:43 -04002299 auto src = Operand(this, state, insn.word(3));
Nicolas Capens157ba262019-12-10 17:49:14 -05002300
2301 SIMD::UInt result = src.UInt(0);
2302
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002303 for(auto i = 1u; i < srcType.componentCount; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002304 {
2305 result |= src.UInt(i);
2306 }
2307
2308 dst.move(0, result);
2309 return EmitResult::Continue;
2310}
2311
2312SpirvShader::EmitResult SpirvShader::EmitAll(InsnIterator insn, EmitState *state) const
2313{
Nicolas Capens71186752020-04-09 01:05:31 -04002314 auto &type = getType(insn.resultTypeId());
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002315 ASSERT(type.componentCount == 1);
2316 auto &dst = state->createIntermediate(insn.resultId(), type.componentCount);
Nicolas Capense7355b92021-11-08 22:48:34 -05002317 auto &srcType = getObjectType(insn.word(3));
Nicolas Capense6f65d92020-04-08 21:55:43 -04002318 auto src = Operand(this, state, insn.word(3));
Nicolas Capens157ba262019-12-10 17:49:14 -05002319
2320 SIMD::UInt result = src.UInt(0);
2321
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002322 for(auto i = 1u; i < srcType.componentCount; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002323 {
2324 result &= src.UInt(i);
2325 }
2326
2327 dst.move(0, result);
2328 return EmitResult::Continue;
2329}
2330
2331SpirvShader::EmitResult SpirvShader::EmitAtomicOp(InsnIterator insn, EmitState *state) const
2332{
2333 auto &resultType = getType(Type::ID(insn.word(1)));
2334 Object::ID resultId = insn.word(2);
Nicolas Capens7c84c9e2020-07-24 22:13:44 -04002335 Object::ID pointerId = insn.word(3);
Nicolas Capens157ba262019-12-10 17:49:14 -05002336 Object::ID semanticsId = insn.word(5);
2337 auto memorySemantics = static_cast<spv::MemorySemanticsMask>(getObject(semanticsId).constantValue[0]);
2338 auto memoryOrder = MemoryOrder(memorySemantics);
2339 // Where no value is provided (increment/decrement) use an implicit value of 1.
Nicolas Capense6f65d92020-04-08 21:55:43 -04002340 auto value = (insn.wordCount() == 7) ? Operand(this, state, insn.word(6)).UInt(0) : RValue<SIMD::UInt>(1);
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002341 auto &dst = state->createIntermediate(resultId, resultType.componentCount);
Nicolas Capens7c84c9e2020-07-24 22:13:44 -04002342 auto ptr = state->getPointer(pointerId);
Nicolas Capens157ba262019-12-10 17:49:14 -05002343 auto ptrOffsets = ptr.offsets();
2344
Nicolas Capens7c84c9e2020-07-24 22:13:44 -04002345 SIMD::Int mask = state->activeLaneMask() & state->storesAndAtomicsMask();
2346
2347 if(getObject(pointerId).opcode() == spv::OpImageTexelPointer)
2348 {
2349 mask &= ptr.isInBounds(sizeof(int32_t), OutOfBoundsBehavior::Nullify);
2350 }
2351
2352 SIMD::UInt result(0);
Nicolas Capens81bc9d92019-12-16 15:05:57 -05002353 for(int j = 0; j < SIMD::Width; j++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002354 {
2355 If(Extract(mask, j) != 0)
2356 {
2357 auto offset = Extract(ptrOffsets, j);
2358 auto laneValue = Extract(value, j);
2359 UInt v;
Nicolas Capens81bc9d92019-12-16 15:05:57 -05002360 switch(insn.opcode())
Nicolas Capens157ba262019-12-10 17:49:14 -05002361 {
Nicolas Capens112faf42019-12-13 17:32:26 -05002362 case spv::OpAtomicIAdd:
2363 case spv::OpAtomicIIncrement:
2364 v = AddAtomic(Pointer<UInt>(&ptr.base[offset]), laneValue, memoryOrder);
2365 break;
2366 case spv::OpAtomicISub:
2367 case spv::OpAtomicIDecrement:
2368 v = SubAtomic(Pointer<UInt>(&ptr.base[offset]), laneValue, memoryOrder);
2369 break;
2370 case spv::OpAtomicAnd:
2371 v = AndAtomic(Pointer<UInt>(&ptr.base[offset]), laneValue, memoryOrder);
2372 break;
2373 case spv::OpAtomicOr:
2374 v = OrAtomic(Pointer<UInt>(&ptr.base[offset]), laneValue, memoryOrder);
2375 break;
2376 case spv::OpAtomicXor:
2377 v = XorAtomic(Pointer<UInt>(&ptr.base[offset]), laneValue, memoryOrder);
2378 break;
2379 case spv::OpAtomicSMin:
2380 v = As<UInt>(MinAtomic(Pointer<Int>(&ptr.base[offset]), As<Int>(laneValue), memoryOrder));
2381 break;
2382 case spv::OpAtomicSMax:
2383 v = As<UInt>(MaxAtomic(Pointer<Int>(&ptr.base[offset]), As<Int>(laneValue), memoryOrder));
2384 break;
2385 case spv::OpAtomicUMin:
2386 v = MinAtomic(Pointer<UInt>(&ptr.base[offset]), laneValue, memoryOrder);
2387 break;
2388 case spv::OpAtomicUMax:
2389 v = MaxAtomic(Pointer<UInt>(&ptr.base[offset]), laneValue, memoryOrder);
2390 break;
2391 case spv::OpAtomicExchange:
2392 v = ExchangeAtomic(Pointer<UInt>(&ptr.base[offset]), laneValue, memoryOrder);
2393 break;
2394 default:
2395 UNREACHABLE("%s", OpcodeName(insn.opcode()));
2396 break;
Nicolas Capens157ba262019-12-10 17:49:14 -05002397 }
Nicolas Capens7c84c9e2020-07-24 22:13:44 -04002398 result = Insert(result, v, j);
Nicolas Capens157ba262019-12-10 17:49:14 -05002399 }
2400 }
2401
Nicolas Capens7c84c9e2020-07-24 22:13:44 -04002402 dst.move(0, result);
Nicolas Capens157ba262019-12-10 17:49:14 -05002403 return EmitResult::Continue;
2404}
2405
2406SpirvShader::EmitResult SpirvShader::EmitAtomicCompareExchange(InsnIterator insn, EmitState *state) const
2407{
2408 // Separate from EmitAtomicOp due to different instruction encoding
2409 auto &resultType = getType(Type::ID(insn.word(1)));
2410 Object::ID resultId = insn.word(2);
2411
2412 auto memorySemanticsEqual = static_cast<spv::MemorySemanticsMask>(getObject(insn.word(5)).constantValue[0]);
2413 auto memoryOrderEqual = MemoryOrder(memorySemanticsEqual);
2414 auto memorySemanticsUnequal = static_cast<spv::MemorySemanticsMask>(getObject(insn.word(6)).constantValue[0]);
2415 auto memoryOrderUnequal = MemoryOrder(memorySemanticsUnequal);
2416
Nicolas Capense6f65d92020-04-08 21:55:43 -04002417 auto value = Operand(this, state, insn.word(7));
2418 auto comparator = Operand(this, state, insn.word(8));
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002419 auto &dst = state->createIntermediate(resultId, resultType.componentCount);
Nicolas Capens157ba262019-12-10 17:49:14 -05002420 auto ptr = state->getPointer(insn.word(3));
2421 auto ptrOffsets = ptr.offsets();
2422
2423 SIMD::UInt x(0);
2424 auto mask = state->activeLaneMask() & state->storesAndAtomicsMask();
Nicolas Capens81bc9d92019-12-16 15:05:57 -05002425 for(int j = 0; j < SIMD::Width; j++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002426 {
2427 If(Extract(mask, j) != 0)
2428 {
2429 auto offset = Extract(ptrOffsets, j);
2430 auto laneValue = Extract(value.UInt(0), j);
2431 auto laneComparator = Extract(comparator.UInt(0), j);
2432 UInt v = CompareExchangeAtomic(Pointer<UInt>(&ptr.base[offset]), laneValue, laneComparator, memoryOrderEqual, memoryOrderUnequal);
2433 x = Insert(x, v, j);
2434 }
2435 }
2436
2437 dst.move(0, x);
2438 return EmitResult::Continue;
2439}
2440
2441SpirvShader::EmitResult SpirvShader::EmitCopyObject(InsnIterator insn, EmitState *state) const
2442{
Nicolas Capens71186752020-04-09 01:05:31 -04002443 auto type = getType(insn.resultTypeId());
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002444 auto &dst = state->createIntermediate(insn.resultId(), type.componentCount);
Nicolas Capense6f65d92020-04-08 21:55:43 -04002445 auto src = Operand(this, state, insn.word(3));
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002446 for(uint32_t i = 0; i < type.componentCount; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002447 {
2448 dst.move(i, src.Int(i));
2449 }
2450 return EmitResult::Continue;
2451}
2452
2453SpirvShader::EmitResult SpirvShader::EmitArrayLength(InsnIterator insn, EmitState *state) const
2454{
Nicolas Capens157ba262019-12-10 17:49:14 -05002455 auto structPtrId = Object::ID(insn.word(3));
2456 auto arrayFieldIdx = insn.word(4);
2457
Nicolas Capens71186752020-04-09 01:05:31 -04002458 auto &resultType = getType(insn.resultTypeId());
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002459 ASSERT(resultType.componentCount == 1);
Nicolas Capens157ba262019-12-10 17:49:14 -05002460 ASSERT(resultType.definition.opcode() == spv::OpTypeInt);
2461
Nicolas Capense7355b92021-11-08 22:48:34 -05002462 auto &structPtrTy = getObjectType(structPtrId);
Nicolas Capens157ba262019-12-10 17:49:14 -05002463 auto &structTy = getType(structPtrTy.element);
Alexis Hetu74d3f372020-02-14 15:32:37 -05002464 auto arrayId = Type::ID(structTy.definition.word(2 + arrayFieldIdx));
Nicolas Capens157ba262019-12-10 17:49:14 -05002465
Nicolas Capens71186752020-04-09 01:05:31 -04002466 auto &result = state->createIntermediate(insn.resultId(), 1);
Nicolas Capens157ba262019-12-10 17:49:14 -05002467 auto structBase = GetPointerToData(structPtrId, 0, state);
2468
Alexis Hetu74d3f372020-02-14 15:32:37 -05002469 Decorations structDecorations = {};
2470 ApplyDecorationsForIdMember(&structDecorations, structPtrTy.element, arrayFieldIdx);
2471 ASSERT(structDecorations.HasOffset);
Nicolas Capens157ba262019-12-10 17:49:14 -05002472
Alexis Hetu74d3f372020-02-14 15:32:37 -05002473 auto arrayBase = structBase + structDecorations.Offset;
Nicolas Capens157ba262019-12-10 17:49:14 -05002474 auto arraySizeInBytes = SIMD::Int(arrayBase.limit()) - arrayBase.offsets();
Alexis Hetu74d3f372020-02-14 15:32:37 -05002475
2476 Decorations arrayDecorations = {};
2477 ApplyDecorationsForId(&arrayDecorations, arrayId);
2478 ASSERT(arrayDecorations.HasArrayStride);
2479 auto arrayLength = arraySizeInBytes / SIMD::Int(arrayDecorations.ArrayStride);
Nicolas Capens157ba262019-12-10 17:49:14 -05002480
2481 result.move(0, SIMD::Int(arrayLength));
2482
2483 return EmitResult::Continue;
2484}
2485
Ben Claytonb36dbbe2020-01-08 12:18:43 +00002486SpirvShader::EmitResult SpirvShader::EmitExtendedInstruction(InsnIterator insn, EmitState *state) const
2487{
2488 auto ext = getExtension(insn.word(3));
2489 switch(ext.name)
2490 {
Nicolas Capens112faf42019-12-13 17:32:26 -05002491 case Extension::GLSLstd450:
2492 return EmitExtGLSLstd450(insn, state);
2493 case Extension::OpenCLDebugInfo100:
2494 return EmitOpenCLDebugInfo100(insn, state);
2495 default:
2496 UNREACHABLE("Unknown Extension::Name<%d>", int(ext.name));
Ben Claytonb36dbbe2020-01-08 12:18:43 +00002497 }
2498 return EmitResult::Continue;
2499}
2500
Nicolas Capens157ba262019-12-10 17:49:14 -05002501uint32_t SpirvShader::GetConstScalarInt(Object::ID id) const
2502{
2503 auto &scopeObj = getObject(id);
2504 ASSERT(scopeObj.kind == Object::Kind::Constant);
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002505 ASSERT(getType(scopeObj).componentCount == 1);
Nicolas Capens157ba262019-12-10 17:49:14 -05002506 return scopeObj.constantValue[0];
2507}
2508
2509void SpirvShader::emitEpilog(SpirvRoutine *routine) const
2510{
Nicolas Capens81bc9d92019-12-16 15:05:57 -05002511 for(auto insn : *this)
Nicolas Capens157ba262019-12-10 17:49:14 -05002512 {
Nicolas Capens81bc9d92019-12-16 15:05:57 -05002513 switch(insn.opcode())
Nicolas Capens157ba262019-12-10 17:49:14 -05002514 {
Nicolas Capens112faf42019-12-13 17:32:26 -05002515 case spv::OpVariable:
Nicolas Capens157ba262019-12-10 17:49:14 -05002516 {
Nicolas Capens71186752020-04-09 01:05:31 -04002517 auto &object = getObject(insn.resultId());
Nicolas Capens72f089c2020-04-08 23:37:08 -04002518 auto &objectTy = getType(object);
Ben Claytonbc1c067be2019-12-17 20:37:37 +00002519 if(object.kind == Object::Kind::InterfaceVariable && objectTy.storageClass == spv::StorageClassOutput)
2520 {
Nicolas Capens71186752020-04-09 01:05:31 -04002521 auto &dst = routine->getVariable(insn.resultId());
Ben Claytonbc1c067be2019-12-17 20:37:37 +00002522 int offset = 0;
Nicolas Capens71186752020-04-09 01:05:31 -04002523 VisitInterface(insn.resultId(),
Ben Claytonbc1c067be2019-12-17 20:37:37 +00002524 [&](Decorations const &d, AttribType type) {
2525 auto scalarSlot = d.Location << 2 | d.Component;
2526 routine->outputs[scalarSlot] = dst[offset++];
2527 });
2528 }
Nicolas Capens157ba262019-12-10 17:49:14 -05002529 }
Nicolas Capens112faf42019-12-13 17:32:26 -05002530 break;
2531 default:
2532 break;
Nicolas Capens157ba262019-12-10 17:49:14 -05002533 }
2534 }
Alexis Hetu09df3eb2021-01-14 10:46:33 -05002535}
Nicolas Capens157ba262019-12-10 17:49:14 -05002536
Alexis Hetu09df3eb2021-01-14 10:46:33 -05002537void SpirvShader::clearPhis(SpirvRoutine *routine) const
2538{
Nicolas Capens157ba262019-12-10 17:49:14 -05002539 // Clear phis that are no longer used. This serves two purposes:
2540 // (1) The phi rr::Variables are destructed, preventing pointless
2541 // materialization.
2542 // (2) Frees memory that will never be used again.
2543 routine->phis.clear();
2544}
2545
2546VkShaderStageFlagBits SpirvShader::executionModelToStage(spv::ExecutionModel model)
2547{
Nicolas Capens81bc9d92019-12-16 15:05:57 -05002548 switch(model)
Nicolas Capens157ba262019-12-10 17:49:14 -05002549 {
Nicolas Capens112faf42019-12-13 17:32:26 -05002550 case spv::ExecutionModelVertex: return VK_SHADER_STAGE_VERTEX_BIT;
2551 // case spv::ExecutionModelTessellationControl: return VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
2552 // case spv::ExecutionModelTessellationEvaluation: return VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
2553 // case spv::ExecutionModelGeometry: return VK_SHADER_STAGE_GEOMETRY_BIT;
2554 case spv::ExecutionModelFragment: return VK_SHADER_STAGE_FRAGMENT_BIT;
2555 case spv::ExecutionModelGLCompute: return VK_SHADER_STAGE_COMPUTE_BIT;
2556 // case spv::ExecutionModelKernel: return VkShaderStageFlagBits(0); // Not supported by vulkan.
2557 // case spv::ExecutionModelTaskNV: return VK_SHADER_STAGE_TASK_BIT_NV;
2558 // case spv::ExecutionModelMeshNV: return VK_SHADER_STAGE_MESH_BIT_NV;
2559 // case spv::ExecutionModelRayGenerationNV: return VK_SHADER_STAGE_RAYGEN_BIT_NV;
2560 // case spv::ExecutionModelIntersectionNV: return VK_SHADER_STAGE_INTERSECTION_BIT_NV;
2561 // case spv::ExecutionModelAnyHitNV: return VK_SHADER_STAGE_ANY_HIT_BIT_NV;
2562 // case spv::ExecutionModelClosestHitNV: return VK_SHADER_STAGE_CLOSEST_HIT_BIT_NV;
2563 // case spv::ExecutionModelMissNV: return VK_SHADER_STAGE_MISS_BIT_NV;
2564 // case spv::ExecutionModelCallableNV: return VK_SHADER_STAGE_CALLABLE_BIT_NV;
2565 default:
2566 UNSUPPORTED("ExecutionModel: %d", int(model));
2567 return VkShaderStageFlagBits(0);
Nicolas Capens157ba262019-12-10 17:49:14 -05002568 }
2569}
2570
Nicolas Capens2f4b6032020-04-09 02:01:50 -04002571SpirvShader::Operand::Operand(const SpirvShader *shader, const EmitState *state, SpirvShader::Object::ID objectId)
2572 : Operand(state, shader->getObject(objectId))
Ben Claytonbc1c067be2019-12-17 20:37:37 +00002573{}
Nicolas Capens157ba262019-12-10 17:49:14 -05002574
Nicolas Capens2f4b6032020-04-09 02:01:50 -04002575SpirvShader::Operand::Operand(const EmitState *state, const Object &object)
Nicolas Capens3c0e0582020-08-26 11:04:37 -04002576 : constant(object.kind == SpirvShader::Object::Kind::Constant ? object.constantValue.data() : nullptr)
Nicolas Capens2f4b6032020-04-09 02:01:50 -04002577 , intermediate(object.kind == SpirvShader::Object::Kind::Intermediate ? &state->getIntermediate(object.id()) : nullptr)
2578 , componentCount(intermediate ? intermediate->componentCount : object.constantValue.size())
2579{
Nicolas Capens3c0e0582020-08-26 11:04:37 -04002580 ASSERT(intermediate || constant);
Nicolas Capens2f4b6032020-04-09 02:01:50 -04002581}
2582
Nicolas Capens20220a02020-04-09 02:48:16 -04002583SpirvShader::Operand::Operand(const Intermediate &value)
2584 : constant(nullptr)
2585 , intermediate(&value)
2586 , componentCount(value.componentCount)
2587{
2588}
2589
Nicolas Capens8dccb372021-11-11 14:24:34 -05002590bool SpirvShader::Object::isConstantZero() const
Nicolas Capens3c0e0582020-08-26 11:04:37 -04002591{
Nicolas Capens8dccb372021-11-11 14:24:34 -05002592 if(kind != Kind::Constant)
Nicolas Capens3c0e0582020-08-26 11:04:37 -04002593 {
2594 return false;
2595 }
2596
Nicolas Capens8dccb372021-11-11 14:24:34 -05002597 for(uint32_t i = 0; i < constantValue.size(); i++)
Nicolas Capens3c0e0582020-08-26 11:04:37 -04002598 {
Nicolas Capens8dccb372021-11-11 14:24:34 -05002599 if(constantValue[i] != 0)
Nicolas Capens3c0e0582020-08-26 11:04:37 -04002600 {
2601 return false;
2602 }
2603 }
2604
2605 return true;
2606}
2607
Ben Claytonbc1c067be2019-12-17 20:37:37 +00002608SpirvRoutine::SpirvRoutine(vk::PipelineLayout const *pipelineLayout)
2609 : pipelineLayout(pipelineLayout)
Nicolas Capens157ba262019-12-10 17:49:14 -05002610{
2611}
2612
2613void SpirvRoutine::setImmutableInputBuiltins(SpirvShader const *shader)
2614{
Ben Claytonbc1c067be2019-12-17 20:37:37 +00002615 setInputBuiltin(shader, spv::BuiltInSubgroupLocalInvocationId, [&](const SpirvShader::BuiltinMapping &builtin, Array<SIMD::Float> &value) {
Nicolas Capens157ba262019-12-10 17:49:14 -05002616 ASSERT(builtin.SizeInComponents == 1);
2617 value[builtin.FirstComponent] = As<SIMD::Float>(SIMD::Int(0, 1, 2, 3));
2618 });
2619
Ben Claytonbc1c067be2019-12-17 20:37:37 +00002620 setInputBuiltin(shader, spv::BuiltInSubgroupEqMask, [&](const SpirvShader::BuiltinMapping &builtin, Array<SIMD::Float> &value) {
Nicolas Capens157ba262019-12-10 17:49:14 -05002621 ASSERT(builtin.SizeInComponents == 4);
2622 value[builtin.FirstComponent + 0] = As<SIMD::Float>(SIMD::Int(1, 2, 4, 8));
2623 value[builtin.FirstComponent + 1] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2624 value[builtin.FirstComponent + 2] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2625 value[builtin.FirstComponent + 3] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2626 });
2627
Ben Claytonbc1c067be2019-12-17 20:37:37 +00002628 setInputBuiltin(shader, spv::BuiltInSubgroupGeMask, [&](const SpirvShader::BuiltinMapping &builtin, Array<SIMD::Float> &value) {
Nicolas Capens157ba262019-12-10 17:49:14 -05002629 ASSERT(builtin.SizeInComponents == 4);
2630 value[builtin.FirstComponent + 0] = As<SIMD::Float>(SIMD::Int(15, 14, 12, 8));
2631 value[builtin.FirstComponent + 1] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2632 value[builtin.FirstComponent + 2] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2633 value[builtin.FirstComponent + 3] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2634 });
2635
Ben Claytonbc1c067be2019-12-17 20:37:37 +00002636 setInputBuiltin(shader, spv::BuiltInSubgroupGtMask, [&](const SpirvShader::BuiltinMapping &builtin, Array<SIMD::Float> &value) {
Nicolas Capens157ba262019-12-10 17:49:14 -05002637 ASSERT(builtin.SizeInComponents == 4);
2638 value[builtin.FirstComponent + 0] = As<SIMD::Float>(SIMD::Int(14, 12, 8, 0));
2639 value[builtin.FirstComponent + 1] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2640 value[builtin.FirstComponent + 2] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2641 value[builtin.FirstComponent + 3] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2642 });
2643
Ben Claytonbc1c067be2019-12-17 20:37:37 +00002644 setInputBuiltin(shader, spv::BuiltInSubgroupLeMask, [&](const SpirvShader::BuiltinMapping &builtin, Array<SIMD::Float> &value) {
Nicolas Capens157ba262019-12-10 17:49:14 -05002645 ASSERT(builtin.SizeInComponents == 4);
2646 value[builtin.FirstComponent + 0] = As<SIMD::Float>(SIMD::Int(1, 3, 7, 15));
2647 value[builtin.FirstComponent + 1] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2648 value[builtin.FirstComponent + 2] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2649 value[builtin.FirstComponent + 3] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2650 });
2651
Ben Claytonbc1c067be2019-12-17 20:37:37 +00002652 setInputBuiltin(shader, spv::BuiltInSubgroupLtMask, [&](const SpirvShader::BuiltinMapping &builtin, Array<SIMD::Float> &value) {
Nicolas Capens157ba262019-12-10 17:49:14 -05002653 ASSERT(builtin.SizeInComponents == 4);
2654 value[builtin.FirstComponent + 0] = As<SIMD::Float>(SIMD::Int(0, 1, 3, 7));
2655 value[builtin.FirstComponent + 1] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2656 value[builtin.FirstComponent + 2] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2657 value[builtin.FirstComponent + 3] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2658 });
2659
Ben Claytonbc1c067be2019-12-17 20:37:37 +00002660 setInputBuiltin(shader, spv::BuiltInDeviceIndex, [&](const SpirvShader::BuiltinMapping &builtin, Array<SIMD::Float> &value) {
Nicolas Capens157ba262019-12-10 17:49:14 -05002661 ASSERT(builtin.SizeInComponents == 1);
2662 // Only a single physical device is supported.
2663 value[builtin.FirstComponent] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2664 });
2665}
2666
2667} // namespace sw