blob: 28516ed19025e5309a698166edde4e6a32388462 [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"
Daniele Vettorelf908b182022-02-09 17:38:08 +000016
17#include "SpirvProfiler.hpp"
Ben Claytonfc951cd2019-05-15 17:16:56 +010018#include "SpirvShaderDebug.hpp"
Ben Claytonecfeede2019-05-08 08:51:01 +010019
Ben Clayton25e06e02020-02-07 11:19:08 +000020#include "System/Debug.hpp"
Ben Clayton76e9bc02019-02-26 15:02:18 +000021#include "Vulkan/VkPipelineLayout.hpp"
Chris Forbes24466042019-04-22 10:54:23 -070022#include "Vulkan/VkRenderPass.hpp"
Chris Forbesaf4ed532018-12-06 18:33:27 -080023
Ben Claytonb0ca2a82020-01-08 13:00:57 +000024#include "marl/defer.h"
25
Nicolas Capens82eb22e2019-04-10 01:15:43 -040026#include <spirv/unified1/spirv.hpp>
Ben Clayton62bb5ed2019-06-18 13:12:20 +010027
Nicolas Capens157ba262019-12-10 17:49:14 -050028namespace sw {
29
30SpirvShader::SpirvShader(
Ben Claytonbc1c067be2019-12-17 20:37:37 +000031 VkShaderStageFlagBits pipelineStage,
32 const char *entryPointName,
Nicolas Capens0c227672021-09-15 10:34:14 -040033 SpirvBinary const &insns,
Ben Claytonbc1c067be2019-12-17 20:37:37 +000034 const vk::RenderPass *renderPass,
35 uint32_t subpassIndex,
Ben Clayton7d0ce412019-12-03 13:26:31 +000036 bool robustBufferAccess,
Daniele Vettorelf908b182022-02-09 17:38:08 +000037 const std::shared_ptr<vk::dbg::Context> &dbgctx,
38 std::shared_ptr<SpirvProfiler> profiler)
Ben Claytonbc1c067be2019-12-17 20:37:37 +000039 : insns{ insns }
40 , inputs{ MAX_INTERFACE_COMPONENTS }
41 , outputs{ MAX_INTERFACE_COMPONENTS }
Ben Claytonbc1c067be2019-12-17 20:37:37 +000042 , robustBufferAccess(robustBufferAccess)
Daniele Vettorelf908b182022-02-09 17:38:08 +000043 , profiler(profiler)
Chris Forbesaf4ed532018-12-06 18:33:27 -080044{
Nicolas Capens157ba262019-12-10 17:49:14 -050045 ASSERT(insns.size() > 0);
Ben Clayton9e4bc1b2019-04-16 16:52:02 -040046
Ben Claytonb0ca2a82020-01-08 13:00:57 +000047 if(dbgctx)
48 {
49 dbgInit(dbgctx);
50 }
51
Nicolas Capens81bc9d92019-12-16 15:05:57 -050052 if(renderPass)
Chris Forbesaf4ed532018-12-06 18:33:27 -080053 {
Nicolas Capens157ba262019-12-10 17:49:14 -050054 // capture formats of any input attachments present
55 auto subpass = renderPass->getSubpass(subpassIndex);
56 inputAttachmentFormats.reserve(subpass.inputAttachmentCount);
Nicolas Capens81bc9d92019-12-16 15:05:57 -050057 for(auto i = 0u; i < subpass.inputAttachmentCount; i++)
Chris Forbes24466042019-04-22 10:54:23 -070058 {
Nicolas Capens157ba262019-12-10 17:49:14 -050059 auto attachmentIndex = subpass.pInputAttachments[i].attachment;
60 inputAttachmentFormats.push_back(attachmentIndex != VK_ATTACHMENT_UNUSED
Ben Claytonbc1c067be2019-12-17 20:37:37 +000061 ? renderPass->getAttachment(attachmentIndex).format
62 : VK_FORMAT_UNDEFINED);
Ben Clayton64f78f52019-03-21 17:21:06 +000063 }
Chris Forbesaf4ed532018-12-06 18:33:27 -080064 }
65
Ben Clayton964b9e32021-06-25 09:00:22 +010066 // The identifiers of all OpVariables that define the entry point's IO variables.
67 std::unordered_set<Object::ID> interfaceIds;
Nicolas Capens157ba262019-12-10 17:49:14 -050068
69 Function::ID currentFunction;
70 Block::ID currentBlock;
71 InsnIterator blockStart;
72
Nicolas Capens81bc9d92019-12-16 15:05:57 -050073 for(auto insn : *this)
Ben Clayton0bb83b82019-02-26 11:41:07 +000074 {
Nicolas Capens157ba262019-12-10 17:49:14 -050075 spv::Op opcode = insn.opcode();
Nicolas Capens82eb22e2019-04-10 01:15:43 -040076
Nicolas Capens81bc9d92019-12-16 15:05:57 -050077 switch(opcode)
Ben Clayton9b156612019-03-13 19:48:31 +000078 {
Nicolas Capens112faf42019-12-13 17:32:26 -050079 case spv::OpEntryPoint:
Nicolas Capens157ba262019-12-10 17:49:14 -050080 {
Nicolas Capens5806db92021-09-27 07:07:27 +000081 spv::ExecutionModel executionModel = spv::ExecutionModel(insn.word(1));
82 Function::ID entryPoint = Function::ID(insn.word(2));
83 const char *name = insn.string(3);
84 VkShaderStageFlagBits stage = executionModelToStage(executionModel);
85
Ben Claytonbc1c067be2019-12-17 20:37:37 +000086 if(stage == pipelineStage && strcmp(name, entryPointName) == 0)
87 {
Nicolas Capens5806db92021-09-27 07:07:27 +000088 ASSERT_MSG(this->entryPoint == 0, "Duplicate entry point with name '%s' and stage %d", name, int(stage));
89 this->entryPoint = entryPoint;
90 this->executionModel = executionModel;
Ben Clayton964b9e32021-06-25 09:00:22 +010091
92 auto interfaceIdsOffset = 3 + insn.stringSizeInWords(3);
93 for(uint32_t i = interfaceIdsOffset; i < insn.wordCount(); i++)
94 {
95 interfaceIds.emplace(insn.word(i));
96 }
Ben Claytonbc1c067be2019-12-17 20:37:37 +000097 }
Nicolas Capens157ba262019-12-10 17:49:14 -050098 }
Nicolas Capens112faf42019-12-13 17:32:26 -050099 break;
Nicolas Capens157ba262019-12-10 17:49:14 -0500100
Nicolas Capens112faf42019-12-13 17:32:26 -0500101 case spv::OpExecutionMode:
Alexis Hetu09ed4582022-02-23 14:24:50 -0500102 case spv::OpExecutionModeId:
Nicolas Capens112faf42019-12-13 17:32:26 -0500103 ProcessExecutionMode(insn);
104 break;
Nicolas Capens157ba262019-12-10 17:49:14 -0500105
Nicolas Capens112faf42019-12-13 17:32:26 -0500106 case spv::OpDecorate:
Nicolas Capens157ba262019-12-10 17:49:14 -0500107 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000108 TypeOrObjectID targetId = insn.word(1);
109 auto decoration = static_cast<spv::Decoration>(insn.word(2));
110 uint32_t value = insn.wordCount() > 3 ? insn.word(3) : 0;
111
112 decorations[targetId].Apply(decoration, value);
113
114 switch(decoration)
115 {
Nicolas Capens112faf42019-12-13 17:32:26 -0500116 case spv::DecorationDescriptorSet:
117 descriptorDecorations[targetId].DescriptorSet = value;
118 break;
119 case spv::DecorationBinding:
120 descriptorDecorations[targetId].Binding = value;
121 break;
122 case spv::DecorationInputAttachmentIndex:
123 descriptorDecorations[targetId].InputAttachmentIndex = value;
124 break;
125 case spv::DecorationSample:
Nicolas Capens15941842021-08-13 15:24:28 -0400126 analysis.ContainsSampleQualifier = true;
Nicolas Capens112faf42019-12-13 17:32:26 -0500127 break;
128 default:
129 // Only handling descriptor decorations here.
130 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000131 }
132
133 if(decoration == spv::DecorationCentroid)
Nicolas Capens112faf42019-12-13 17:32:26 -0500134 {
Nicolas Capens15941842021-08-13 15:24:28 -0400135 analysis.NeedsCentroid = true;
Nicolas Capens112faf42019-12-13 17:32:26 -0500136 }
Nicolas Capens157ba262019-12-10 17:49:14 -0500137 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500138 break;
Nicolas Capens157ba262019-12-10 17:49:14 -0500139
Nicolas Capens112faf42019-12-13 17:32:26 -0500140 case spv::OpMemberDecorate:
Nicolas Capens157ba262019-12-10 17:49:14 -0500141 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000142 Type::ID targetId = insn.word(1);
143 auto memberIndex = insn.word(2);
144 auto decoration = static_cast<spv::Decoration>(insn.word(3));
145 uint32_t value = insn.wordCount() > 4 ? insn.word(4) : 0;
146
147 auto &d = memberDecorations[targetId];
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500148 if(memberIndex >= d.size())
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000149 d.resize(memberIndex + 1); // on demand; exact size would require another pass...
150
151 d[memberIndex].Apply(decoration, value);
152
153 if(decoration == spv::DecorationCentroid)
Nicolas Capens112faf42019-12-13 17:32:26 -0500154 {
Nicolas Capens15941842021-08-13 15:24:28 -0400155 analysis.NeedsCentroid = true;
Nicolas Capens112faf42019-12-13 17:32:26 -0500156 }
Nicolas Capens157ba262019-12-10 17:49:14 -0500157 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500158 break;
Nicolas Capens157ba262019-12-10 17:49:14 -0500159
Nicolas Capens112faf42019-12-13 17:32:26 -0500160 case spv::OpDecorateId:
Sean Risser79a271a2020-12-02 16:56:03 -0500161 {
162 auto decoration = static_cast<spv::Decoration>(insn.word(2));
163
164 // Currently OpDecorateId only supports UniformId, which provides information for
165 // potential optimizations that we don't perform, and CounterBuffer, which is used
166 // by HLSL to build the graphics pipeline with shader reflection. At the driver level,
167 // the CounterBuffer decoration does nothing, so we can safely ignore both decorations.
168 ASSERT(decoration == spv::DecorationUniformId || decoration == spv::DecorationCounterBuffer);
Sean Risser79a271a2020-12-02 16:56:03 -0500169 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500170 break;
Sean Risser79a271a2020-12-02 16:56:03 -0500171
Nicolas Capens112faf42019-12-13 17:32:26 -0500172 case spv::OpDecorateString:
Nicolas Capens4fd9ef92022-01-14 16:11:27 -0500173 {
174 auto decoration = static_cast<spv::Decoration>(insn.word(2));
175
176 // We assume these are for HLSL semantics, ignore them (b/214576937).
Nicolas Capens9b1a72a2022-01-14 16:34:01 -0500177 ASSERT(decoration == spv::DecorationUserSemantic || decoration == spv::DecorationUserTypeGOOGLE);
Nicolas Capens4fd9ef92022-01-14 16:11:27 -0500178 }
179 break;
180
Nicolas Capens112faf42019-12-13 17:32:26 -0500181 case spv::OpMemberDecorateString:
Nicolas Capens4fd9ef92022-01-14 16:11:27 -0500182 {
183 auto decoration = static_cast<spv::Decoration>(insn.word(3));
184
185 // We assume these are for HLSL semantics, ignore them (b/214576937).
Nicolas Capens9b1a72a2022-01-14 16:34:01 -0500186 ASSERT(decoration == spv::DecorationUserSemantic || decoration == spv::DecorationUserTypeGOOGLE);
Nicolas Capens4fd9ef92022-01-14 16:11:27 -0500187 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500188 break;
Sean Risser79a271a2020-12-02 16:56:03 -0500189
Nicolas Capens112faf42019-12-13 17:32:26 -0500190 case spv::OpDecorationGroup:
191 // Nothing to do here. We don't need to record the definition of the group; we'll just have
192 // the bundle of decorations float around. If we were to ever walk the decorations directly,
193 // we might think about introducing this as a real Object.
194 break;
Nicolas Capens157ba262019-12-10 17:49:14 -0500195
Nicolas Capens112faf42019-12-13 17:32:26 -0500196 case spv::OpGroupDecorate:
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000197 {
198 uint32_t group = insn.word(1);
199 auto const &groupDecorations = decorations[group];
200 auto const &descriptorGroupDecorations = descriptorDecorations[group];
201 for(auto i = 2u; i < insn.wordCount(); i++)
202 {
203 // Remaining operands are targets to apply the group to.
204 uint32_t target = insn.word(i);
205 decorations[target].Apply(groupDecorations);
206 descriptorDecorations[target].Apply(descriptorGroupDecorations);
207 }
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000208 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500209 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000210
Nicolas Capens112faf42019-12-13 17:32:26 -0500211 case spv::OpGroupMemberDecorate:
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000212 {
213 auto const &srcDecorations = decorations[insn.word(1)];
214 for(auto i = 2u; i < insn.wordCount(); i += 2)
215 {
216 // remaining operands are pairs of <id>, literal for members to apply to.
217 auto &d = memberDecorations[insn.word(i)];
218 auto memberIndex = insn.word(i + 1);
219 if(memberIndex >= d.size())
220 d.resize(memberIndex + 1); // on demand resize, see above...
221 d[memberIndex].Apply(srcDecorations);
222 }
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000223 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500224 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000225
Nicolas Capens112faf42019-12-13 17:32:26 -0500226 case spv::OpLabel:
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000227 {
Nicolas Capensff9bb522021-11-08 21:29:29 -0500228 ASSERT(currentBlock == 0);
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000229 currentBlock = Block::ID(insn.word(1));
230 blockStart = insn;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000231 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500232 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000233
Alexis Hetubbe92e92022-03-23 13:32:00 -0400234 // Termination instructions:
235 case spv::OpKill:
236 case spv::OpTerminateInvocation:
Nicolas Capens23ccff72022-04-05 13:00:22 -0400237 analysis.ContainsDiscard = true;
Alexis Hetubbe92e92022-03-23 13:32:00 -0400238 // [[fallthrough]]
239
240 case spv::OpUnreachable:
241
Nicolas Capens112faf42019-12-13 17:32:26 -0500242 // Branch Instructions (subset of Termination Instructions):
243 case spv::OpBranch:
244 case spv::OpBranchConditional:
245 case spv::OpSwitch:
246 case spv::OpReturn:
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000247 {
Nicolas Capensff9bb522021-11-08 21:29:29 -0500248 ASSERT(currentBlock != 0);
249 ASSERT(currentFunction != 0);
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000250
251 auto blockEnd = insn;
252 blockEnd++;
253 functions[currentFunction].blocks[currentBlock] = Block(blockStart, blockEnd);
254 currentBlock = Block::ID(0);
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000255 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500256 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000257
Alexis Hetu4d2f9f12022-02-22 17:16:13 -0500258 case spv::OpDemoteToHelperInvocation:
Nicolas Capens23ccff72022-04-05 13:00:22 -0400259 analysis.ContainsDiscard = true;
Alexis Hetu4d2f9f12022-02-22 17:16:13 -0500260 break;
261
Nicolas Capens112faf42019-12-13 17:32:26 -0500262 case spv::OpLoopMerge:
263 case spv::OpSelectionMerge:
264 break; // Nothing to do in analysis pass.
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000265
Nicolas Capens112faf42019-12-13 17:32:26 -0500266 case spv::OpTypeVoid:
267 case spv::OpTypeBool:
268 case spv::OpTypeInt:
269 case spv::OpTypeFloat:
270 case spv::OpTypeVector:
271 case spv::OpTypeMatrix:
272 case spv::OpTypeImage:
273 case spv::OpTypeSampler:
274 case spv::OpTypeSampledImage:
275 case spv::OpTypeArray:
276 case spv::OpTypeRuntimeArray:
277 case spv::OpTypeStruct:
278 case spv::OpTypePointer:
Alexis Hetuc582db22022-06-14 16:46:56 -0400279 case spv::OpTypeForwardPointer:
Nicolas Capens112faf42019-12-13 17:32:26 -0500280 case spv::OpTypeFunction:
281 DeclareType(insn);
282 break;
Nicolas Capens157ba262019-12-10 17:49:14 -0500283
Nicolas Capens112faf42019-12-13 17:32:26 -0500284 case spv::OpVariable:
Nicolas Capens157ba262019-12-10 17:49:14 -0500285 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000286 Type::ID typeId = insn.word(1);
287 Object::ID resultId = insn.word(2);
288 auto storageClass = static_cast<spv::StorageClass>(insn.word(3));
289
290 auto &object = defs[resultId];
Nicolas Capens157ba262019-12-10 17:49:14 -0500291 object.kind = Object::Kind::Pointer;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000292 object.definition = insn;
Nicolas Capens157ba262019-12-10 17:49:14 -0500293
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000294 ASSERT(getType(typeId).definition.opcode() == spv::OpTypePointer);
295 ASSERT(getType(typeId).storageClass == storageClass);
Nicolas Capens157ba262019-12-10 17:49:14 -0500296
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000297 switch(storageClass)
Nicolas Capens157ba262019-12-10 17:49:14 -0500298 {
Nicolas Capens112faf42019-12-13 17:32:26 -0500299 case spv::StorageClassInput:
300 case spv::StorageClassOutput:
Ben Clayton964b9e32021-06-25 09:00:22 +0100301 if(interfaceIds.count(resultId))
302 {
303 ProcessInterfaceVariable(object);
304 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500305 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000306
Nicolas Capens112faf42019-12-13 17:32:26 -0500307 case spv::StorageClassUniform:
308 case spv::StorageClassStorageBuffer:
Alexis Hetu71ec98e2022-06-14 16:58:44 -0400309 case spv::StorageClassPhysicalStorageBuffer:
Nicolas Capens112faf42019-12-13 17:32:26 -0500310 object.kind = Object::Kind::DescriptorSet;
311 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000312
Nicolas Capens112faf42019-12-13 17:32:26 -0500313 case spv::StorageClassPushConstant:
314 case spv::StorageClassPrivate:
315 case spv::StorageClassFunction:
316 case spv::StorageClassUniformConstant:
317 break; // Correctly handled.
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000318
Nicolas Capens112faf42019-12-13 17:32:26 -0500319 case spv::StorageClassWorkgroup:
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000320 {
321 auto &elTy = getType(getType(typeId).element);
Nicolas Capensff9f9b52020-04-14 00:46:38 -0400322 auto sizeInBytes = elTy.componentCount * static_cast<uint32_t>(sizeof(float));
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000323 workgroupMemory.allocate(resultId, sizeInBytes);
324 object.kind = Object::Kind::Pointer;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000325 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500326 break;
327 case spv::StorageClassAtomicCounter:
328 case spv::StorageClassImage:
329 UNSUPPORTED("StorageClass %d not yet supported", (int)storageClass);
330 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000331
Nicolas Capens112faf42019-12-13 17:32:26 -0500332 case spv::StorageClassCrossWorkgroup:
333 UNSUPPORTED("SPIR-V OpenCL Execution Model (StorageClassCrossWorkgroup)");
334 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000335
Nicolas Capens112faf42019-12-13 17:32:26 -0500336 case spv::StorageClassGeneric:
337 UNSUPPORTED("SPIR-V GenericPointer Capability (StorageClassGeneric)");
338 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000339
Nicolas Capens112faf42019-12-13 17:32:26 -0500340 default:
341 UNREACHABLE("Unexpected StorageClass %d", storageClass); // See Appendix A of the Vulkan spec.
342 break;
Nicolas Capens157ba262019-12-10 17:49:14 -0500343 }
344 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500345 break;
Nicolas Capens157ba262019-12-10 17:49:14 -0500346
Nicolas Capens112faf42019-12-13 17:32:26 -0500347 case spv::OpConstant:
348 case spv::OpSpecConstant:
349 CreateConstant(insn).constantValue[0] = insn.word(3);
350 break;
351 case spv::OpConstantFalse:
352 case spv::OpSpecConstantFalse:
353 CreateConstant(insn).constantValue[0] = 0; // Represent Boolean false as zero.
354 break;
355 case spv::OpConstantTrue:
356 case spv::OpSpecConstantTrue:
357 CreateConstant(insn).constantValue[0] = ~0u; // Represent Boolean true as all bits set.
358 break;
359 case spv::OpConstantNull:
360 case spv::OpUndef:
Nicolas Capens157ba262019-12-10 17:49:14 -0500361 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000362 // TODO: consider a real LLVM-level undef. For now, zero is a perfectly good value.
363 // OpConstantNull forms a constant of arbitrary type, all zeros.
364 auto &object = CreateConstant(insn);
Nicolas Capens72f089c2020-04-08 23:37:08 -0400365 auto &objectTy = getType(object);
Nicolas Capensff9f9b52020-04-14 00:46:38 -0400366 for(auto i = 0u; i < objectTy.componentCount; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -0500367 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000368 object.constantValue[i] = 0;
Nicolas Capens157ba262019-12-10 17:49:14 -0500369 }
370 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500371 break;
372 case spv::OpConstantComposite:
373 case spv::OpSpecConstantComposite:
Nicolas Capens157ba262019-12-10 17:49:14 -0500374 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000375 auto &object = CreateConstant(insn);
376 auto offset = 0u;
377 for(auto i = 0u; i < insn.wordCount() - 3; i++)
378 {
379 auto &constituent = getObject(insn.word(i + 3));
Nicolas Capens72f089c2020-04-08 23:37:08 -0400380 auto &constituentTy = getType(constituent);
Nicolas Capensff9f9b52020-04-14 00:46:38 -0400381 for(auto j = 0u; j < constituentTy.componentCount; j++)
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000382 {
383 object.constantValue[offset++] = constituent.constantValue[j];
384 }
385 }
386
387 auto objectId = Object::ID(insn.word(2));
388 auto decorationsIt = decorations.find(objectId);
389 if(decorationsIt != decorations.end() &&
390 decorationsIt->second.BuiltIn == spv::BuiltInWorkgroupSize)
391 {
392 // https://www.khronos.org/registry/vulkan/specs/1.1/html/vkspec.html#interfaces-builtin-variables :
393 // Decorating an object with the WorkgroupSize built-in
394 // decoration will make that object contain the dimensions
395 // of a local workgroup. If an object is decorated with the
396 // WorkgroupSize decoration, this must take precedence over
397 // any execution mode set for LocalSize.
398 // The object decorated with WorkgroupSize must be declared
399 // as a three-component vector of 32-bit integers.
Nicolas Capensff9f9b52020-04-14 00:46:38 -0400400 ASSERT(getType(object).componentCount == 3);
Nicolas Capens15941842021-08-13 15:24:28 -0400401 executionModes.WorkgroupSizeX = object.constantValue[0];
402 executionModes.WorkgroupSizeY = object.constantValue[1];
403 executionModes.WorkgroupSizeZ = object.constantValue[2];
Alexis Hetu09ed4582022-02-23 14:24:50 -0500404 executionModes.useWorkgroupSizeId = false;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000405 }
Nicolas Capens157ba262019-12-10 17:49:14 -0500406 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500407 break;
408 case spv::OpSpecConstantOp:
409 EvalSpecConstantOp(insn);
410 break;
Ben Clayton9b156612019-03-13 19:48:31 +0000411
Nicolas Capens112faf42019-12-13 17:32:26 -0500412 case spv::OpCapability:
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000413 {
414 auto capability = static_cast<spv::Capability>(insn.word(1));
415 switch(capability)
416 {
Nicolas Capens112faf42019-12-13 17:32:26 -0500417 case spv::CapabilityMatrix: capabilities.Matrix = true; break;
418 case spv::CapabilityShader: capabilities.Shader = true; break;
419 case spv::CapabilityStorageImageMultisample: capabilities.StorageImageMultisample = true; break;
420 case spv::CapabilityClipDistance: capabilities.ClipDistance = true; break;
421 case spv::CapabilityCullDistance: capabilities.CullDistance = true; break;
422 case spv::CapabilityImageCubeArray: capabilities.ImageCubeArray = true; break;
423 case spv::CapabilitySampleRateShading: capabilities.SampleRateShading = true; break;
424 case spv::CapabilityInputAttachment: capabilities.InputAttachment = true; break;
425 case spv::CapabilitySampled1D: capabilities.Sampled1D = true; break;
426 case spv::CapabilityImage1D: capabilities.Image1D = true; break;
427 case spv::CapabilitySampledBuffer: capabilities.SampledBuffer = true; break;
428 case spv::CapabilitySampledCubeArray: capabilities.SampledCubeArray = true; break;
429 case spv::CapabilityImageBuffer: capabilities.ImageBuffer = true; break;
430 case spv::CapabilityImageMSArray: capabilities.ImageMSArray = true; break;
431 case spv::CapabilityStorageImageExtendedFormats: capabilities.StorageImageExtendedFormats = true; break;
432 case spv::CapabilityImageQuery: capabilities.ImageQuery = true; break;
433 case spv::CapabilityDerivativeControl: capabilities.DerivativeControl = true; break;
sugoi1e3d910c2022-02-22 15:07:21 -0500434 case spv::CapabilityDotProductInputAll: capabilities.DotProductInputAll = true; break;
435 case spv::CapabilityDotProductInput4x8Bit: capabilities.DotProductInput4x8Bit = true; break;
436 case spv::CapabilityDotProductInput4x8BitPacked: capabilities.DotProductInput4x8BitPacked = true; break;
437 case spv::CapabilityDotProduct: capabilities.DotProduct = true; break;
Nicolas Capens112faf42019-12-13 17:32:26 -0500438 case spv::CapabilityInterpolationFunction: capabilities.InterpolationFunction = true; break;
Nicolas Capensf0e8ec22021-11-12 13:57:14 -0500439 case spv::CapabilityStorageImageWriteWithoutFormat: capabilities.StorageImageWriteWithoutFormat = true; break;
Nicolas Capens112faf42019-12-13 17:32:26 -0500440 case spv::CapabilityGroupNonUniform: capabilities.GroupNonUniform = true; break;
441 case spv::CapabilityGroupNonUniformVote: capabilities.GroupNonUniformVote = true; break;
442 case spv::CapabilityGroupNonUniformArithmetic: capabilities.GroupNonUniformArithmetic = true; break;
443 case spv::CapabilityGroupNonUniformBallot: capabilities.GroupNonUniformBallot = true; break;
444 case spv::CapabilityGroupNonUniformShuffle: capabilities.GroupNonUniformShuffle = true; break;
445 case spv::CapabilityGroupNonUniformShuffleRelative: capabilities.GroupNonUniformShuffleRelative = true; break;
Sean Risser1144d582022-06-23 13:53:11 -0400446 case spv::CapabilityGroupNonUniformQuad: capabilities.GroupNonUniformQuad = true; break;
Nicolas Capens112faf42019-12-13 17:32:26 -0500447 case spv::CapabilityDeviceGroup: capabilities.DeviceGroup = true; break;
448 case spv::CapabilityMultiView: capabilities.MultiView = true; break;
Sean Risserb6ddcf32022-07-06 15:30:41 -0400449 case spv::CapabilitySignedZeroInfNanPreserve: capabilities.SignedZeroInfNanPreserve = true; break;
Alexis Hetu4d2f9f12022-02-22 17:16:13 -0500450 case spv::CapabilityDemoteToHelperInvocation: capabilities.DemoteToHelperInvocation = true; break;
Nicolas Capens112faf42019-12-13 17:32:26 -0500451 case spv::CapabilityStencilExportEXT: capabilities.StencilExportEXT = true; break;
Nicolas Capens4c629802021-12-08 02:05:19 -0500452 case spv::CapabilityVulkanMemoryModel: capabilities.VulkanMemoryModel = true; break;
453 case spv::CapabilityVulkanMemoryModelDeviceScope: capabilities.VulkanMemoryModelDeviceScope = true; break;
Sean Risserda08cb22022-04-08 20:49:06 -0400454 case spv::CapabilityShaderNonUniform: capabilities.ShaderNonUniform = true; break;
455 case spv::CapabilityRuntimeDescriptorArray: capabilities.RuntimeDescriptorArray = true; break;
456 case spv::CapabilityStorageBufferArrayNonUniformIndexing: capabilities.StorageBufferArrayNonUniformIndexing = true; break;
Sean Rissera4c2e9b2022-05-03 14:47:41 -0400457 case spv::CapabilityStorageTexelBufferArrayNonUniformIndexing: capabilities.StorageTexelBufferArrayNonUniformIndexing = true; break;
Sean Rissere726b1e2022-07-13 15:26:50 -0400458 case spv::CapabilityUniformTexelBufferArrayNonUniformIndexing: capabilities.UniformTexelBufferArrayNonUniformIndexing = true; break;
459 case spv::CapabilityUniformTexelBufferArrayDynamicIndexing: capabilities.UniformTexelBufferArrayDynamicIndexing = true; break;
Sean Risser5cb6a632022-06-20 12:37:40 -0400460 case spv::CapabilityStorageTexelBufferArrayDynamicIndexing: capabilities.StorageTexelBufferArrayDynamicIndexing = true; break;
Sean Risser54bae6e2022-07-13 16:03:17 -0400461 case spv::CapabilityUniformBufferArrayNonUniformIndexing: capabilities.UniformBufferArrayNonUniformIndex = true; break;
Alexis Hetuf8335442022-03-09 13:53:37 -0500462 case spv::CapabilityPhysicalStorageBufferAddresses: capabilities.PhysicalStorageBufferAddresses = true; break;
Nicolas Capens112faf42019-12-13 17:32:26 -0500463 default:
464 UNSUPPORTED("Unsupported capability %u", insn.word(1));
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000465 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500466
467 // Various capabilities will be declared, but none affect our code generation at this point.
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000468 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500469 break;
Ben Clayton9b156612019-03-13 19:48:31 +0000470
Nicolas Capens112faf42019-12-13 17:32:26 -0500471 case spv::OpMemoryModel:
Nicolas Capens4c629802021-12-08 02:05:19 -0500472 {
473 addressingModel = static_cast<spv::AddressingModel>(insn.word(1));
474 memoryModel = static_cast<spv::MemoryModel>(insn.word(2));
475 }
476 break;
Nicolas Capens157ba262019-12-10 17:49:14 -0500477
Nicolas Capens112faf42019-12-13 17:32:26 -0500478 case spv::OpFunction:
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000479 {
480 auto functionId = Function::ID(insn.word(2));
481 ASSERT_MSG(currentFunction == 0, "Functions %d and %d overlap", currentFunction.value(), functionId.value());
482 currentFunction = functionId;
483 auto &function = functions[functionId];
484 function.result = Type::ID(insn.word(1));
485 function.type = Type::ID(insn.word(4));
486 // Scan forward to find the function's label.
Ben Clayton7d098242020-03-13 13:07:12 +0000487 for(auto it = insn; it != end(); it++)
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000488 {
Ben Clayton7d098242020-03-13 13:07:12 +0000489 if(it.opcode() == spv::OpLabel)
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000490 {
Ben Clayton7d098242020-03-13 13:07:12 +0000491 function.entry = Block::ID(it.word(1));
492 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000493 }
494 }
495 ASSERT_MSG(function.entry != 0, "Function<%d> has no label", currentFunction.value());
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000496 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500497 break;
Nicolas Capens157ba262019-12-10 17:49:14 -0500498
Nicolas Capens112faf42019-12-13 17:32:26 -0500499 case spv::OpFunctionEnd:
500 currentFunction = 0;
501 break;
Nicolas Capens157ba262019-12-10 17:49:14 -0500502
Nicolas Capens112faf42019-12-13 17:32:26 -0500503 case spv::OpExtInstImport:
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000504 {
Ben Clayton683bad82020-02-10 23:57:09 +0000505 static constexpr std::pair<const char *, Extension::Name> extensionsByName[] = {
Ben Claytonf6a6a412020-01-09 16:43:37 +0000506 { "GLSL.std.450", Extension::GLSLstd450 },
Ben Claytoncd55f052020-01-14 11:56:00 +0000507 { "OpenCL.DebugInfo.100", Extension::OpenCLDebugInfo100 },
sugoi1cd8e0282022-02-22 15:50:46 -0500508 { "NonSemantic.", Extension::NonSemanticInfo },
Ben Claytonf6a6a412020-01-09 16:43:37 +0000509 };
Ben Clayton683bad82020-02-10 23:57:09 +0000510 static constexpr auto extensionCount = sizeof(extensionsByName) / sizeof(extensionsByName[0]);
511
Ben Claytonb36dbbe2020-01-08 12:18:43 +0000512 auto id = Extension::ID(insn.word(1));
513 auto name = insn.string(2);
514 auto ext = Extension{ Extension::Unknown };
Ben Clayton683bad82020-02-10 23:57:09 +0000515 for(size_t i = 0; i < extensionCount; i++)
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000516 {
sugoi1cd8e0282022-02-22 15:50:46 -0500517 if(0 == strncmp(name, extensionsByName[i].first, strlen(extensionsByName[i].first)))
Ben Claytonb36dbbe2020-01-08 12:18:43 +0000518 {
Ben Clayton683bad82020-02-10 23:57:09 +0000519 ext = Extension{ extensionsByName[i].second };
Ben Claytonb36dbbe2020-01-08 12:18:43 +0000520 break;
521 }
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000522 }
Ben Claytonb36dbbe2020-01-08 12:18:43 +0000523 if(ext.name == Extension::Unknown)
524 {
525 UNSUPPORTED("SPIR-V Extension: %s", name);
526 break;
527 }
Ben Clayton8842c8f2020-01-13 16:57:48 +0000528 extensionsByID.emplace(id, ext);
529 extensionsImported.emplace(ext.name);
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000530 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500531 break;
532 case spv::OpName:
533 case spv::OpMemberName:
534 case spv::OpSource:
535 case spv::OpSourceContinued:
536 case spv::OpSourceExtension:
537 case spv::OpLine:
538 case spv::OpNoLine:
539 case spv::OpModuleProcessed:
540 // No semantic impact
541 break;
Ben Clayton9b156612019-03-13 19:48:31 +0000542
Nicolas Capens112faf42019-12-13 17:32:26 -0500543 case spv::OpString:
544 strings.emplace(insn.word(1), insn.string(2));
545 break;
Ben Clayton9c8823a2020-01-08 12:07:30 +0000546
Nicolas Capens112faf42019-12-13 17:32:26 -0500547 case spv::OpFunctionParameter:
548 // These should have all been removed by preprocessing passes. If we see them here,
549 // our assumptions are wrong and we will probably generate wrong code.
550 UNREACHABLE("%s should have already been lowered.", OpcodeName(opcode));
551 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000552
Nicolas Capens112faf42019-12-13 17:32:26 -0500553 case spv::OpFunctionCall:
554 // TODO(b/141246700): Add full support for spv::OpFunctionCall
555 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000556
Nicolas Capens112faf42019-12-13 17:32:26 -0500557 case spv::OpFConvert:
558 UNSUPPORTED("SPIR-V Float16 or Float64 Capability (OpFConvert)");
559 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000560
Nicolas Capens112faf42019-12-13 17:32:26 -0500561 case spv::OpSConvert:
562 UNSUPPORTED("SPIR-V Int16 or Int64 Capability (OpSConvert)");
563 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000564
Nicolas Capens112faf42019-12-13 17:32:26 -0500565 case spv::OpUConvert:
566 UNSUPPORTED("SPIR-V Int16 or Int64 Capability (OpUConvert)");
567 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000568
Nicolas Capens112faf42019-12-13 17:32:26 -0500569 case spv::OpLoad:
570 case spv::OpAccessChain:
571 case spv::OpInBoundsAccessChain:
Alexis Hetu47c22462022-06-06 18:00:16 -0400572 case spv::OpPtrAccessChain:
Nicolas Capens112faf42019-12-13 17:32:26 -0500573 case spv::OpSampledImage:
574 case spv::OpImage:
Alexis Hetu150bc8c2022-08-30 12:01:15 -0400575 case spv::OpCopyObject:
576 case spv::OpCopyLogical:
Nicolas Capens157ba262019-12-10 17:49:14 -0500577 {
578 // Propagate the descriptor decorations to the result.
579 Object::ID resultId = insn.word(2);
580 Object::ID pointerId = insn.word(3);
581 const auto &d = descriptorDecorations.find(pointerId);
582
583 if(d != descriptorDecorations.end())
584 {
585 descriptorDecorations[resultId] = d->second;
586 }
587
588 DefineResult(insn);
589
Alexis Hetu47c22462022-06-06 18:00:16 -0400590 if(opcode == spv::OpAccessChain || opcode == spv::OpInBoundsAccessChain || opcode == spv::OpPtrAccessChain)
Nicolas Capens157ba262019-12-10 17:49:14 -0500591 {
Alexis Hetu71ec98e2022-06-14 16:58:44 -0400592 int indexId = (insn.opcode() == spv::OpPtrAccessChain) ? 5 : 4;
Nicolas Capens157ba262019-12-10 17:49:14 -0500593 Decorations dd{};
Alexis Hetu71ec98e2022-06-14 16:58:44 -0400594 ApplyDecorationsForAccessChain(&dd, &descriptorDecorations[resultId], pointerId, Span(insn, indexId, insn.wordCount() - indexId));
Nicolas Capens157ba262019-12-10 17:49:14 -0500595 // Note: offset is the one thing that does *not* propagate, as the access chain accounts for it.
596 dd.HasOffset = false;
597 decorations[resultId].Apply(dd);
598 }
599 }
600 break;
Ben Clayton9b156612019-03-13 19:48:31 +0000601
Nicolas Capens112faf42019-12-13 17:32:26 -0500602 case spv::OpCompositeConstruct:
603 case spv::OpCompositeInsert:
604 case spv::OpCompositeExtract:
605 case spv::OpVectorShuffle:
606 case spv::OpVectorTimesScalar:
607 case spv::OpMatrixTimesScalar:
608 case spv::OpMatrixTimesVector:
609 case spv::OpVectorTimesMatrix:
610 case spv::OpMatrixTimesMatrix:
611 case spv::OpOuterProduct:
612 case spv::OpTranspose:
613 case spv::OpVectorExtractDynamic:
614 case spv::OpVectorInsertDynamic:
615 // Unary ops
616 case spv::OpNot:
617 case spv::OpBitFieldInsert:
618 case spv::OpBitFieldSExtract:
619 case spv::OpBitFieldUExtract:
620 case spv::OpBitReverse:
621 case spv::OpBitCount:
622 case spv::OpSNegate:
623 case spv::OpFNegate:
624 case spv::OpLogicalNot:
625 case spv::OpQuantizeToF16:
626 // Binary ops
627 case spv::OpIAdd:
628 case spv::OpISub:
629 case spv::OpIMul:
630 case spv::OpSDiv:
631 case spv::OpUDiv:
632 case spv::OpFAdd:
633 case spv::OpFSub:
634 case spv::OpFMul:
635 case spv::OpFDiv:
636 case spv::OpFMod:
637 case spv::OpFRem:
638 case spv::OpFOrdEqual:
639 case spv::OpFUnordEqual:
640 case spv::OpFOrdNotEqual:
641 case spv::OpFUnordNotEqual:
642 case spv::OpFOrdLessThan:
643 case spv::OpFUnordLessThan:
644 case spv::OpFOrdGreaterThan:
645 case spv::OpFUnordGreaterThan:
646 case spv::OpFOrdLessThanEqual:
647 case spv::OpFUnordLessThanEqual:
648 case spv::OpFOrdGreaterThanEqual:
649 case spv::OpFUnordGreaterThanEqual:
650 case spv::OpSMod:
651 case spv::OpSRem:
652 case spv::OpUMod:
653 case spv::OpIEqual:
654 case spv::OpINotEqual:
655 case spv::OpUGreaterThan:
656 case spv::OpSGreaterThan:
657 case spv::OpUGreaterThanEqual:
658 case spv::OpSGreaterThanEqual:
659 case spv::OpULessThan:
660 case spv::OpSLessThan:
661 case spv::OpULessThanEqual:
662 case spv::OpSLessThanEqual:
663 case spv::OpShiftRightLogical:
664 case spv::OpShiftRightArithmetic:
665 case spv::OpShiftLeftLogical:
666 case spv::OpBitwiseOr:
667 case spv::OpBitwiseXor:
668 case spv::OpBitwiseAnd:
669 case spv::OpLogicalOr:
670 case spv::OpLogicalAnd:
671 case spv::OpLogicalEqual:
672 case spv::OpLogicalNotEqual:
673 case spv::OpUMulExtended:
674 case spv::OpSMulExtended:
675 case spv::OpIAddCarry:
676 case spv::OpISubBorrow:
677 case spv::OpDot:
sugoi1e3d910c2022-02-22 15:07:21 -0500678 case spv::OpSDot:
679 case spv::OpUDot:
680 case spv::OpSUDot:
681 case spv::OpSDotAccSat:
682 case spv::OpUDotAccSat:
683 case spv::OpSUDotAccSat:
Nicolas Capens112faf42019-12-13 17:32:26 -0500684 case spv::OpConvertFToU:
685 case spv::OpConvertFToS:
686 case spv::OpConvertSToF:
687 case spv::OpConvertUToF:
688 case spv::OpBitcast:
689 case spv::OpSelect:
690 case spv::OpIsInf:
691 case spv::OpIsNan:
692 case spv::OpAny:
693 case spv::OpAll:
694 case spv::OpDPdx:
695 case spv::OpDPdxCoarse:
696 case spv::OpDPdy:
697 case spv::OpDPdyCoarse:
698 case spv::OpFwidth:
699 case spv::OpFwidthCoarse:
700 case spv::OpDPdxFine:
701 case spv::OpDPdyFine:
702 case spv::OpFwidthFine:
703 case spv::OpAtomicLoad:
704 case spv::OpAtomicIAdd:
705 case spv::OpAtomicISub:
706 case spv::OpAtomicSMin:
707 case spv::OpAtomicSMax:
708 case spv::OpAtomicUMin:
709 case spv::OpAtomicUMax:
710 case spv::OpAtomicAnd:
711 case spv::OpAtomicOr:
712 case spv::OpAtomicXor:
713 case spv::OpAtomicIIncrement:
714 case spv::OpAtomicIDecrement:
715 case spv::OpAtomicExchange:
716 case spv::OpAtomicCompareExchange:
717 case spv::OpPhi:
718 case spv::OpImageSampleImplicitLod:
719 case spv::OpImageSampleExplicitLod:
720 case spv::OpImageSampleDrefImplicitLod:
721 case spv::OpImageSampleDrefExplicitLod:
722 case spv::OpImageSampleProjImplicitLod:
723 case spv::OpImageSampleProjExplicitLod:
724 case spv::OpImageSampleProjDrefImplicitLod:
725 case spv::OpImageSampleProjDrefExplicitLod:
726 case spv::OpImageGather:
727 case spv::OpImageDrefGather:
728 case spv::OpImageFetch:
729 case spv::OpImageQuerySizeLod:
730 case spv::OpImageQuerySize:
731 case spv::OpImageQueryLod:
732 case spv::OpImageQueryLevels:
733 case spv::OpImageQuerySamples:
734 case spv::OpImageRead:
735 case spv::OpImageTexelPointer:
736 case spv::OpGroupNonUniformElect:
737 case spv::OpGroupNonUniformAll:
738 case spv::OpGroupNonUniformAny:
739 case spv::OpGroupNonUniformAllEqual:
740 case spv::OpGroupNonUniformBroadcast:
741 case spv::OpGroupNonUniformBroadcastFirst:
Sean Risser1144d582022-06-23 13:53:11 -0400742 case spv::OpGroupNonUniformQuadBroadcast:
743 case spv::OpGroupNonUniformQuadSwap:
Nicolas Capens112faf42019-12-13 17:32:26 -0500744 case spv::OpGroupNonUniformBallot:
745 case spv::OpGroupNonUniformInverseBallot:
746 case spv::OpGroupNonUniformBallotBitExtract:
747 case spv::OpGroupNonUniformBallotBitCount:
748 case spv::OpGroupNonUniformBallotFindLSB:
749 case spv::OpGroupNonUniformBallotFindMSB:
750 case spv::OpGroupNonUniformShuffle:
751 case spv::OpGroupNonUniformShuffleXor:
752 case spv::OpGroupNonUniformShuffleUp:
753 case spv::OpGroupNonUniformShuffleDown:
754 case spv::OpGroupNonUniformIAdd:
755 case spv::OpGroupNonUniformFAdd:
756 case spv::OpGroupNonUniformIMul:
757 case spv::OpGroupNonUniformFMul:
758 case spv::OpGroupNonUniformSMin:
759 case spv::OpGroupNonUniformUMin:
760 case spv::OpGroupNonUniformFMin:
761 case spv::OpGroupNonUniformSMax:
762 case spv::OpGroupNonUniformUMax:
763 case spv::OpGroupNonUniformFMax:
764 case spv::OpGroupNonUniformBitwiseAnd:
765 case spv::OpGroupNonUniformBitwiseOr:
766 case spv::OpGroupNonUniformBitwiseXor:
767 case spv::OpGroupNonUniformLogicalAnd:
768 case spv::OpGroupNonUniformLogicalOr:
769 case spv::OpGroupNonUniformLogicalXor:
Nicolas Capens112faf42019-12-13 17:32:26 -0500770 case spv::OpArrayLength:
Alexis Hetu4d2f9f12022-02-22 17:16:13 -0500771 case spv::OpIsHelperInvocationEXT:
Nicolas Capens112faf42019-12-13 17:32:26 -0500772 // Instructions that yield an intermediate value or divergent pointer
773 DefineResult(insn);
774 break;
775
776 case spv::OpExtInst:
777 switch(getExtension(insn.word(3)).name)
778 {
779 case Extension::GLSLstd450:
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000780 DefineResult(insn);
781 break;
Nicolas Capens112faf42019-12-13 17:32:26 -0500782 case Extension::OpenCLDebugInfo100:
783 DefineOpenCLDebugInfo100(insn);
Ben Claytonb36dbbe2020-01-08 12:18:43 +0000784 break;
sugoi1cd8e0282022-02-22 15:50:46 -0500785 case Extension::NonSemanticInfo:
786 // An extended set name which is prefixed with "NonSemantic." is
787 // guaranteed to contain only non-semantic instructions and all
788 // OpExtInst instructions referencing this set can be ignored.
789 break;
Nicolas Capens112faf42019-12-13 17:32:26 -0500790 default:
791 UNREACHABLE("Unexpected Extension name %d", int(getExtension(insn.word(3)).name));
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000792 break;
Nicolas Capens112faf42019-12-13 17:32:26 -0500793 }
794 break;
Nicolas Capens157ba262019-12-10 17:49:14 -0500795
Nicolas Capens112faf42019-12-13 17:32:26 -0500796 case spv::OpStore:
797 case spv::OpAtomicStore:
798 case spv::OpImageWrite:
799 case spv::OpCopyMemory:
800 case spv::OpMemoryBarrier:
801 // Don't need to do anything during analysis pass
802 break;
Nicolas Capens157ba262019-12-10 17:49:14 -0500803
Nicolas Capens112faf42019-12-13 17:32:26 -0500804 case spv::OpControlBarrier:
Nicolas Capens15941842021-08-13 15:24:28 -0400805 analysis.ContainsControlBarriers = true;
Nicolas Capens112faf42019-12-13 17:32:26 -0500806 break;
807
808 case spv::OpExtension:
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000809 {
Nicolas Capens4c629802021-12-08 02:05:19 -0500810 const char *ext = insn.string(1);
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000811 // Part of core SPIR-V 1.3. Vulkan 1.1 implementations must also accept the pre-1.3
812 // extension per Appendix A, `Vulkan Environment for SPIR-V`.
813 if(!strcmp(ext, "SPV_KHR_storage_buffer_storage_class")) break;
814 if(!strcmp(ext, "SPV_KHR_shader_draw_parameters")) break;
815 if(!strcmp(ext, "SPV_KHR_16bit_storage")) break;
816 if(!strcmp(ext, "SPV_KHR_variable_pointers")) break;
817 if(!strcmp(ext, "SPV_KHR_device_group")) break;
818 if(!strcmp(ext, "SPV_KHR_multiview")) break;
Alexis Hetu4d2f9f12022-02-22 17:16:13 -0500819 if(!strcmp(ext, "SPV_EXT_demote_to_helper_invocation")) break;
Alexis Hetubbe92e92022-03-23 13:32:00 -0400820 if(!strcmp(ext, "SPV_KHR_terminate_invocation")) break;
Alexis Hetu1ee36c92020-02-20 14:07:26 -0500821 if(!strcmp(ext, "SPV_EXT_shader_stencil_export")) break;
Sean Risser0063eca2020-10-26 17:08:42 -0400822 if(!strcmp(ext, "SPV_KHR_float_controls")) break;
sugoi1e3d910c2022-02-22 15:07:21 -0500823 if(!strcmp(ext, "SPV_KHR_integer_dot_product")) break;
sugoi1cd8e0282022-02-22 15:50:46 -0500824 if(!strcmp(ext, "SPV_KHR_non_semantic_info")) break;
Alexis Hetuf8335442022-03-09 13:53:37 -0500825 if(!strcmp(ext, "SPV_KHR_physical_storage_buffer")) break;
Nicolas Capens4c629802021-12-08 02:05:19 -0500826 if(!strcmp(ext, "SPV_KHR_vulkan_memory_model")) break;
Nicolas Capens4fd9ef92022-01-14 16:11:27 -0500827 if(!strcmp(ext, "SPV_GOOGLE_decorate_string")) break;
Nicolas Capens534f10f2022-01-14 16:21:06 -0500828 if(!strcmp(ext, "SPV_GOOGLE_hlsl_functionality1")) break;
Nicolas Capens9b1a72a2022-01-14 16:34:01 -0500829 if(!strcmp(ext, "SPV_GOOGLE_user_type")) break;
Sean Risserda08cb22022-04-08 20:49:06 -0400830 if(!strcmp(ext, "SPV_EXT_descriptor_indexing")) break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000831 UNSUPPORTED("SPIR-V Extension: %s", ext);
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000832 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500833 break;
Ben Claytonc0cf68b2019-03-21 17:46:08 +0000834
Nicolas Capens112faf42019-12-13 17:32:26 -0500835 default:
836 UNSUPPORTED("%s", OpcodeName(opcode));
Nicolas Capens157ba262019-12-10 17:49:14 -0500837 }
Chris Forbesd5aed492019-02-02 15:18:52 -0800838 }
Chris Forbesc61271e2019-02-19 17:01:28 -0800839
Nicolas Capens157ba262019-12-10 17:49:14 -0500840 ASSERT_MSG(entryPoint != 0, "Entry point '%s' not found", entryPointName);
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500841 for(auto &it : functions)
Nicolas Capensfabdec52019-03-21 17:04:05 -0400842 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500843 it.second.AssignBlockFields();
Nicolas Capensfabdec52019-03-21 17:04:05 -0400844 }
Ben Claytonb0ca2a82020-01-08 13:00:57 +0000845
Ben Clayton0d6791c2020-04-22 21:55:27 +0100846#ifdef SPIRV_SHADER_CFG_GRAPHVIZ_DOT_FILEPATH
847 {
848 char path[1024];
849 snprintf(path, sizeof(path), SPIRV_SHADER_CFG_GRAPHVIZ_DOT_FILEPATH, codeSerialID);
850 WriteCFGGraphVizDotFile(path);
851 }
852#endif
853
Ben Claytonb0ca2a82020-01-08 13:00:57 +0000854 dbgCreateFile();
855}
856
857SpirvShader::~SpirvShader()
858{
859 dbgTerm();
Nicolas Capens157ba262019-12-10 17:49:14 -0500860}
Nicolas Capensfabdec52019-03-21 17:04:05 -0400861
Nicolas Capens157ba262019-12-10 17:49:14 -0500862void SpirvShader::DeclareType(InsnIterator insn)
863{
864 Type::ID resultId = insn.word(1);
865
866 auto &type = types[resultId];
867 type.definition = insn;
Nicolas Capensff9f9b52020-04-14 00:46:38 -0400868 type.componentCount = ComputeTypeSize(insn);
Nicolas Capens157ba262019-12-10 17:49:14 -0500869
870 // A structure is a builtin block if it has a builtin
871 // member. All members of such a structure are builtins.
Alexis Hetuc582db22022-06-14 16:46:56 -0400872 spv::Op opcode = insn.opcode();
873 switch(opcode)
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000874 {
Nicolas Capens112faf42019-12-13 17:32:26 -0500875 case spv::OpTypeStruct:
Nicolas Capens157ba262019-12-10 17:49:14 -0500876 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000877 auto d = memberDecorations.find(resultId);
878 if(d != memberDecorations.end())
Nicolas Capens157ba262019-12-10 17:49:14 -0500879 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000880 for(auto &m : d->second)
Nicolas Capens157ba262019-12-10 17:49:14 -0500881 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000882 if(m.HasBuiltIn)
883 {
884 type.isBuiltInBlock = true;
885 break;
886 }
Nicolas Capens157ba262019-12-10 17:49:14 -0500887 }
888 }
889 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500890 break;
891 case spv::OpTypePointer:
Alexis Hetuc582db22022-06-14 16:46:56 -0400892 case spv::OpTypeForwardPointer:
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000893 {
Alexis Hetuc582db22022-06-14 16:46:56 -0400894 Type::ID elementTypeId = insn.word((opcode == spv::OpTypeForwardPointer) ? 1 : 3);
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000895 type.element = elementTypeId;
896 type.isBuiltInBlock = getType(elementTypeId).isBuiltInBlock;
897 type.storageClass = static_cast<spv::StorageClass>(insn.word(2));
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000898 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500899 break;
900 case spv::OpTypeVector:
901 case spv::OpTypeMatrix:
902 case spv::OpTypeArray:
903 case spv::OpTypeRuntimeArray:
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000904 {
905 Type::ID elementTypeId = insn.word(2);
906 type.element = elementTypeId;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000907 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500908 break;
909 default:
910 break;
Nicolas Capens157ba262019-12-10 17:49:14 -0500911 }
912}
913
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000914SpirvShader::Object &SpirvShader::CreateConstant(InsnIterator insn)
Nicolas Capens157ba262019-12-10 17:49:14 -0500915{
916 Type::ID typeId = insn.word(1);
917 Object::ID resultId = insn.word(2);
918 auto &object = defs[resultId];
919 auto &objectTy = getType(typeId);
Nicolas Capens157ba262019-12-10 17:49:14 -0500920 object.kind = Object::Kind::Constant;
921 object.definition = insn;
Nicolas Capens2f4b6032020-04-09 02:01:50 -0400922 object.constantValue.resize(objectTy.componentCount);
Nicolas Capens72f089c2020-04-08 23:37:08 -0400923
Nicolas Capens157ba262019-12-10 17:49:14 -0500924 return object;
925}
926
927void SpirvShader::ProcessInterfaceVariable(Object &object)
928{
Nicolas Capens72f089c2020-04-08 23:37:08 -0400929 auto &objectTy = getType(object);
Nicolas Capens157ba262019-12-10 17:49:14 -0500930 ASSERT(objectTy.storageClass == spv::StorageClassInput || objectTy.storageClass == spv::StorageClassOutput);
931
932 ASSERT(objectTy.opcode() == spv::OpTypePointer);
933 auto pointeeTy = getType(objectTy.element);
934
935 auto &builtinInterface = (objectTy.storageClass == spv::StorageClassInput) ? inputBuiltins : outputBuiltins;
936 auto &userDefinedInterface = (objectTy.storageClass == spv::StorageClassInput) ? inputs : outputs;
937
938 ASSERT(object.opcode() == spv::OpVariable);
939 Object::ID resultId = object.definition.word(2);
940
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500941 if(objectTy.isBuiltInBlock)
Nicolas Capens157ba262019-12-10 17:49:14 -0500942 {
Nicolas Capens71186752020-04-09 01:05:31 -0400943 // Walk the builtin block, registering each of its members separately.
Nicolas Capens157ba262019-12-10 17:49:14 -0500944 auto m = memberDecorations.find(objectTy.element);
Nicolas Capens71186752020-04-09 01:05:31 -0400945 ASSERT(m != memberDecorations.end()); // Otherwise we wouldn't have marked the type chain
Nicolas Capens157ba262019-12-10 17:49:14 -0500946 auto &structType = pointeeTy.definition;
Nicolas Capens71186752020-04-09 01:05:31 -0400947 auto memberIndex = 0u;
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000948 auto offset = 0u;
Nicolas Capens71186752020-04-09 01:05:31 -0400949
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500950 for(auto &member : m->second)
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000951 {
Nicolas Capens71186752020-04-09 01:05:31 -0400952 auto &memberType = getType(structType.word(2 + memberIndex));
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000953
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500954 if(member.HasBuiltIn)
Ben Clayton9b62c5e2019-03-08 09:32:34 +0000955 {
Nicolas Capensff9f9b52020-04-14 00:46:38 -0400956 builtinInterface[member.BuiltIn] = { resultId, offset, memberType.componentCount };
Ben Clayton9b62c5e2019-03-08 09:32:34 +0000957 }
Ben Claytonc0cf68b2019-03-21 17:46:08 +0000958
Nicolas Capensff9f9b52020-04-14 00:46:38 -0400959 offset += memberType.componentCount;
Nicolas Capens71186752020-04-09 01:05:31 -0400960 ++memberIndex;
Nicolas Capens157ba262019-12-10 17:49:14 -0500961 }
Nicolas Capens71186752020-04-09 01:05:31 -0400962
Nicolas Capens157ba262019-12-10 17:49:14 -0500963 return;
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000964 }
965
Nicolas Capens157ba262019-12-10 17:49:14 -0500966 auto d = decorations.find(resultId);
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500967 if(d != decorations.end() && d->second.HasBuiltIn)
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000968 {
Nicolas Capensff9f9b52020-04-14 00:46:38 -0400969 builtinInterface[d->second.BuiltIn] = { resultId, 0, pointeeTy.componentCount };
Nicolas Capens157ba262019-12-10 17:49:14 -0500970 }
971 else
972 {
973 object.kind = Object::Kind::InterfaceVariable;
974 VisitInterface(resultId,
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000975 [&userDefinedInterface](Decorations const &d, AttribType type) {
976 // Populate a single scalar slot in the interface from a collection of decorations and the intended component type.
Nicolas Capens25813472022-02-17 01:07:32 -0500977 int32_t scalarSlot = (d.Location << 2) | d.Component;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000978 ASSERT(scalarSlot >= 0 &&
979 scalarSlot < static_cast<int32_t>(userDefinedInterface.size()));
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000980
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000981 auto &slot = userDefinedInterface[scalarSlot];
982 slot.Type = type;
983 slot.Flat = d.Flat;
984 slot.NoPerspective = d.NoPerspective;
985 slot.Centroid = d.Centroid;
986 });
Nicolas Capens157ba262019-12-10 17:49:14 -0500987 }
988}
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000989
Alexis Hetu945f1442021-01-14 11:39:56 -0500990uint32_t SpirvShader::GetNumInputComponents(int32_t location) const
991{
992 ASSERT(location >= 0);
993
994 // Verify how many component(s) per input
995 // 1 to 4, for float, vec2, vec3, vec4.
996 // Note that matrices are divided over multiple inputs
997 uint32_t num_components_per_input = 0;
998 for(; num_components_per_input < 4; ++num_components_per_input)
999 {
1000 if(inputs[(location << 2) | num_components_per_input].Type == ATTRIBTYPE_UNUSED)
1001 {
1002 break;
1003 }
1004 }
1005
1006 return num_components_per_input;
1007}
1008
Alexis Hetu73a69402021-11-08 16:03:51 -05001009uint32_t SpirvShader::GetPackedInterpolant(int32_t location) const
1010{
1011 ASSERT(location >= 0);
1012 const uint32_t maxInterpolant = (location << 2);
1013
1014 // Return the number of used components only at location
1015 uint32_t packedInterpolant = 0;
1016 for(uint32_t i = 0; i < maxInterpolant; ++i)
1017 {
Nicolas Capens8dccb372021-11-11 14:24:34 -05001018 if(inputs[i].Type != ATTRIBTYPE_UNUSED)
Alexis Hetu73a69402021-11-08 16:03:51 -05001019 {
1020 ++packedInterpolant;
1021 }
1022 }
1023
1024 return packedInterpolant;
1025}
1026
Nicolas Capens157ba262019-12-10 17:49:14 -05001027void SpirvShader::ProcessExecutionMode(InsnIterator insn)
1028{
Nicolas Capens57eb48a2020-05-15 17:07:07 -04001029 Function::ID function = insn.word(1);
1030 if(function != entryPoint)
1031 {
1032 return;
1033 }
1034
Nicolas Capens157ba262019-12-10 17:49:14 -05001035 auto mode = static_cast<spv::ExecutionMode>(insn.word(2));
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001036 switch(mode)
Nicolas Capens157ba262019-12-10 17:49:14 -05001037 {
Nicolas Capens112faf42019-12-13 17:32:26 -05001038 case spv::ExecutionModeEarlyFragmentTests:
Nicolas Capens15941842021-08-13 15:24:28 -04001039 executionModes.EarlyFragmentTests = true;
Nicolas Capens112faf42019-12-13 17:32:26 -05001040 break;
1041 case spv::ExecutionModeDepthReplacing:
Nicolas Capens15941842021-08-13 15:24:28 -04001042 executionModes.DepthReplacing = true;
Nicolas Capens112faf42019-12-13 17:32:26 -05001043 break;
1044 case spv::ExecutionModeDepthGreater:
1045 // TODO(b/177915067): Can be used to optimize depth test, currently unused.
Nicolas Capens15941842021-08-13 15:24:28 -04001046 executionModes.DepthGreater = true;
Nicolas Capens112faf42019-12-13 17:32:26 -05001047 break;
1048 case spv::ExecutionModeDepthLess:
1049 // TODO(b/177915067): Can be used to optimize depth test, currently unused.
Nicolas Capens15941842021-08-13 15:24:28 -04001050 executionModes.DepthLess = true;
Nicolas Capens112faf42019-12-13 17:32:26 -05001051 break;
1052 case spv::ExecutionModeDepthUnchanged:
1053 // TODO(b/177915067): Can be used to optimize depth test, currently unused.
Nicolas Capens15941842021-08-13 15:24:28 -04001054 executionModes.DepthUnchanged = true;
Nicolas Capens112faf42019-12-13 17:32:26 -05001055 break;
1056 case spv::ExecutionModeLocalSize:
Alexis Hetu09ed4582022-02-23 14:24:50 -05001057 case spv::ExecutionModeLocalSizeId:
Nicolas Capens15941842021-08-13 15:24:28 -04001058 executionModes.WorkgroupSizeX = insn.word(3);
1059 executionModes.WorkgroupSizeY = insn.word(4);
1060 executionModes.WorkgroupSizeZ = insn.word(5);
Alexis Hetu09ed4582022-02-23 14:24:50 -05001061 executionModes.useWorkgroupSizeId = (mode == spv::ExecutionModeLocalSizeId);
Nicolas Capens112faf42019-12-13 17:32:26 -05001062 break;
1063 case spv::ExecutionModeOriginUpperLeft:
1064 // This is always the case for a Vulkan shader. Do nothing.
1065 break;
Sean Risserb6ddcf32022-07-06 15:30:41 -04001066 case spv::ExecutionModeSignedZeroInfNanPreserve:
1067 // We currently don't perform any aggressive fast-math optimizations.
1068 break;
Nicolas Capens112faf42019-12-13 17:32:26 -05001069 default:
1070 UNREACHABLE("Execution mode: %d", int(mode));
Nicolas Capens157ba262019-12-10 17:49:14 -05001071 }
1072}
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001073
Alexis Hetu09ed4582022-02-23 14:24:50 -05001074uint32_t SpirvShader::getWorkgroupSizeX() const
1075{
1076 return executionModes.useWorkgroupSizeId ? getObject(executionModes.WorkgroupSizeX).constantValue[0] : executionModes.WorkgroupSizeX.value();
1077}
1078
1079uint32_t SpirvShader::getWorkgroupSizeY() const
1080{
1081 return executionModes.useWorkgroupSizeId ? getObject(executionModes.WorkgroupSizeY).constantValue[0] : executionModes.WorkgroupSizeY.value();
1082}
1083
1084uint32_t SpirvShader::getWorkgroupSizeZ() const
1085{
1086 return executionModes.useWorkgroupSizeId ? getObject(executionModes.WorkgroupSizeZ).constantValue[0] : executionModes.WorkgroupSizeZ.value();
1087}
1088
Nicolas Capens157ba262019-12-10 17:49:14 -05001089uint32_t SpirvShader::ComputeTypeSize(InsnIterator insn)
1090{
1091 // Types are always built from the bottom up (with the exception of forward ptrs, which
1092 // don't appear in Vulkan shaders. Therefore, we can always assume our component parts have
1093 // already been described (and so their sizes determined)
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001094 switch(insn.opcode())
Nicolas Capens157ba262019-12-10 17:49:14 -05001095 {
Nicolas Capens112faf42019-12-13 17:32:26 -05001096 case spv::OpTypeVoid:
1097 case spv::OpTypeSampler:
1098 case spv::OpTypeImage:
1099 case spv::OpTypeSampledImage:
Alexis Hetuc582db22022-06-14 16:46:56 -04001100 case spv::OpTypeForwardPointer:
Nicolas Capens112faf42019-12-13 17:32:26 -05001101 case spv::OpTypeFunction:
1102 case spv::OpTypeRuntimeArray:
1103 // Objects that don't consume any space.
1104 // Descriptor-backed objects currently only need exist at compile-time.
1105 // Runtime arrays don't appear in places where their size would be interesting
1106 return 0;
Nicolas Capens157ba262019-12-10 17:49:14 -05001107
Nicolas Capens112faf42019-12-13 17:32:26 -05001108 case spv::OpTypeBool:
1109 case spv::OpTypeFloat:
1110 case spv::OpTypeInt:
1111 // All the fundamental types are 1 component. If we ever add support for 8/16/64-bit components,
1112 // we might need to change this, but only 32 bit components are required for Vulkan 1.1.
1113 return 1;
Nicolas Capens157ba262019-12-10 17:49:14 -05001114
Nicolas Capens112faf42019-12-13 17:32:26 -05001115 case spv::OpTypeVector:
1116 case spv::OpTypeMatrix:
1117 // Vectors and matrices both consume element count * element size.
1118 return getType(insn.word(2)).componentCount * insn.word(3);
Nicolas Capens157ba262019-12-10 17:49:14 -05001119
Nicolas Capens112faf42019-12-13 17:32:26 -05001120 case spv::OpTypeArray:
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001121 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001122 // Element count * element size. Array sizes come from constant ids.
1123 auto arraySize = GetConstScalarInt(insn.word(3));
Nicolas Capensff9f9b52020-04-14 00:46:38 -04001124 return getType(insn.word(2)).componentCount * arraySize;
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001125 }
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001126
Nicolas Capens112faf42019-12-13 17:32:26 -05001127 case spv::OpTypeStruct:
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001128 {
1129 uint32_t size = 0;
1130 for(uint32_t i = 2u; i < insn.wordCount(); i++)
1131 {
Nicolas Capensff9f9b52020-04-14 00:46:38 -04001132 size += getType(insn.word(i)).componentCount;
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001133 }
1134 return size;
1135 }
Nicolas Capens157ba262019-12-10 17:49:14 -05001136
Nicolas Capens112faf42019-12-13 17:32:26 -05001137 case spv::OpTypePointer:
1138 // Runtime representation of a pointer is a per-lane index.
1139 // Note: clients are expected to look through the pointer if they want the pointee size instead.
1140 return 1;
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001141
Nicolas Capens112faf42019-12-13 17:32:26 -05001142 default:
1143 UNREACHABLE("%s", OpcodeName(insn.opcode()));
1144 return 0;
Nicolas Capens157ba262019-12-10 17:49:14 -05001145 }
1146}
1147
1148int SpirvShader::VisitInterfaceInner(Type::ID id, Decorations d, const InterfaceVisitor &f) const
1149{
1150 // Recursively walks variable definition and its type tree, taking into account
1151 // any explicit Location or Component decorations encountered; where explicit
1152 // Locations or Components are not specified, assigns them sequentially.
1153 // Collected decorations are carried down toward the leaves and across
1154 // siblings; Effect of decorations intentionally does not flow back up the tree.
1155 //
1156 // F is a functor to be called with the effective decoration set for every component.
1157 //
1158 // Returns the next available location, and calls f().
1159
1160 // This covers the rules in Vulkan 1.1 spec, 14.1.4 Location Assignment.
1161
1162 ApplyDecorationsForId(&d, id);
1163
1164 auto const &obj = getType(id);
1165 switch(obj.opcode())
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001166 {
Nicolas Capens112faf42019-12-13 17:32:26 -05001167 case spv::OpTypePointer:
1168 return VisitInterfaceInner(obj.definition.word(3), d, f);
1169 case spv::OpTypeMatrix:
1170 for(auto i = 0u; i < obj.definition.word(3); i++, d.Location++)
1171 {
1172 // consumes same components of N consecutive locations
1173 VisitInterfaceInner(obj.definition.word(2), d, f);
1174 }
1175 return d.Location;
1176 case spv::OpTypeVector:
1177 for(auto i = 0u; i < obj.definition.word(3); i++, d.Component++)
1178 {
1179 // consumes N consecutive components in the same location
1180 VisitInterfaceInner(obj.definition.word(2), d, f);
1181 }
1182 return d.Location + 1;
1183 case spv::OpTypeFloat:
1184 f(d, ATTRIBTYPE_FLOAT);
1185 return d.Location + 1;
1186 case spv::OpTypeInt:
1187 f(d, obj.definition.word(3) ? ATTRIBTYPE_INT : ATTRIBTYPE_UINT);
1188 return d.Location + 1;
1189 case spv::OpTypeBool:
1190 f(d, ATTRIBTYPE_UINT);
1191 return d.Location + 1;
1192 case spv::OpTypeStruct:
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001193 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001194 // iterate over members, which may themselves have Location/Component decorations
1195 for(auto i = 0u; i < obj.definition.wordCount() - 2; i++)
1196 {
Alexis Hetub6540802020-08-11 18:12:03 -04001197 Decorations dMember = d;
1198 ApplyDecorationsForIdMember(&dMember, id, i);
1199 d.Location = VisitInterfaceInner(obj.definition.word(i + 2), dMember, f);
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001200 d.Component = 0; // Implicit locations always have component=0
1201 }
1202 return d.Location;
Nicolas Capens157ba262019-12-10 17:49:14 -05001203 }
Nicolas Capens112faf42019-12-13 17:32:26 -05001204 case spv::OpTypeArray:
Nicolas Capens157ba262019-12-10 17:49:14 -05001205 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001206 auto arraySize = GetConstScalarInt(obj.definition.word(3));
1207 for(auto i = 0u; i < arraySize; i++)
1208 {
1209 d.Location = VisitInterfaceInner(obj.definition.word(2), d, f);
1210 }
1211 return d.Location;
Nicolas Capens157ba262019-12-10 17:49:14 -05001212 }
Nicolas Capens112faf42019-12-13 17:32:26 -05001213 default:
1214 // Intentionally partial; most opcodes do not participate in type hierarchies
1215 return 0;
Nicolas Capens157ba262019-12-10 17:49:14 -05001216 }
1217}
1218
1219void SpirvShader::VisitInterface(Object::ID id, const InterfaceVisitor &f) const
1220{
1221 // Walk a variable definition and call f for each component in it.
Nicolas Capensd6806b32022-03-02 10:16:31 -05001222 Decorations d = GetDecorationsForId(id);
Nicolas Capens157ba262019-12-10 17:49:14 -05001223
1224 auto def = getObject(id).definition;
1225 ASSERT(def.opcode() == spv::OpVariable);
1226 VisitInterfaceInner(def.word(1), d, f);
1227}
1228
Nicolas Capens0b2a7682022-04-04 00:43:17 -04001229void SpirvShader::ApplyDecorationsForAccessChain(Decorations *d, DescriptorDecorations *dd, Object::ID baseId, const Span &indexIds) const
Nicolas Capens157ba262019-12-10 17:49:14 -05001230{
1231 ApplyDecorationsForId(d, baseId);
1232 auto &baseObject = getObject(baseId);
Nicolas Capens72f089c2020-04-08 23:37:08 -04001233 ApplyDecorationsForId(d, baseObject.typeId());
1234 auto typeId = getType(baseObject).element;
Nicolas Capens157ba262019-12-10 17:49:14 -05001235
Nicolas Capens0b2a7682022-04-04 00:43:17 -04001236 for(uint32_t i = 0; i < indexIds.size(); i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05001237 {
1238 ApplyDecorationsForId(d, typeId);
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001239 auto &type = getType(typeId);
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001240 switch(type.opcode())
Nicolas Capens157ba262019-12-10 17:49:14 -05001241 {
Nicolas Capens112faf42019-12-13 17:32:26 -05001242 case spv::OpTypeStruct:
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001243 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001244 int memberIndex = GetConstScalarInt(indexIds[i]);
1245 ApplyDecorationsForIdMember(d, typeId, memberIndex);
1246 typeId = type.definition.word(2u + memberIndex);
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001247 }
Nicolas Capens112faf42019-12-13 17:32:26 -05001248 break;
1249 case spv::OpTypeArray:
1250 case spv::OpTypeRuntimeArray:
1251 if(dd->InputAttachmentIndex >= 0)
1252 {
1253 dd->InputAttachmentIndex += GetConstScalarInt(indexIds[i]);
1254 }
1255 typeId = type.element;
1256 break;
1257 case spv::OpTypeVector:
1258 typeId = type.element;
1259 break;
1260 case spv::OpTypeMatrix:
1261 typeId = type.element;
1262 d->InsideMatrix = true;
1263 break;
1264 default:
1265 UNREACHABLE("%s", OpcodeName(type.definition.opcode()));
Nicolas Capens157ba262019-12-10 17:49:14 -05001266 }
1267 }
1268}
1269
Sean Risserda08cb22022-04-08 20:49:06 -04001270SIMD::Pointer SpirvShader::WalkExplicitLayoutAccessChain(Object::ID baseId, Object::ID elementId, const Span &indexIds, bool nonUniform, const EmitState *state) const
Nicolas Capens157ba262019-12-10 17:49:14 -05001271{
1272 // Produce a offset into external memory in sizeof(float) units
1273
1274 auto &baseObject = getObject(baseId);
Nicolas Capens72f089c2020-04-08 23:37:08 -04001275 Type::ID typeId = getType(baseObject).element;
Nicolas Capensd6806b32022-03-02 10:16:31 -05001276 Decorations d = GetDecorationsForId(baseObject.typeId());
Sean Risserda08cb22022-04-08 20:49:06 -04001277 SIMD::Int arrayIndex = 0;
Nicolas Capens157ba262019-12-10 17:49:14 -05001278
Nicolas Capens0b2a7682022-04-04 00:43:17 -04001279 uint32_t start = 0;
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001280 if(baseObject.kind == Object::Kind::DescriptorSet)
Nicolas Capens157ba262019-12-10 17:49:14 -05001281 {
1282 auto type = getType(typeId).definition.opcode();
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001283 if(type == spv::OpTypeArray || type == spv::OpTypeRuntimeArray)
Nicolas Capens157ba262019-12-10 17:49:14 -05001284 {
Nicolas Capens479d1432020-01-31 11:19:21 -05001285 auto &obj = getObject(indexIds[0]);
1286 ASSERT(obj.kind == Object::Kind::Constant || obj.kind == Object::Kind::Intermediate);
1287 if(obj.kind == Object::Kind::Constant)
1288 {
1289 arrayIndex = GetConstScalarInt(indexIds[0]);
1290 }
1291 else
1292 {
Sean Risserda08cb22022-04-08 20:49:06 -04001293 nonUniform |= GetDecorationsForId(indexIds[0]).NonUniform;
1294 arrayIndex = state->getIntermediate(indexIds[0]).Int(0);
Nicolas Capens479d1432020-01-31 11:19:21 -05001295 }
Nicolas Capens157ba262019-12-10 17:49:14 -05001296
Nicolas Capens0b2a7682022-04-04 00:43:17 -04001297 start = 1;
Nicolas Capens157ba262019-12-10 17:49:14 -05001298 typeId = getType(typeId).element;
1299 }
1300 }
1301
Sean Risserda08cb22022-04-08 20:49:06 -04001302 auto ptr = GetPointerToData(baseId, arrayIndex, nonUniform, state);
Alexis Hetu47c22462022-06-06 18:00:16 -04001303 OffsetToElement(ptr, elementId, d.ArrayStride, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001304
1305 int constantOffset = 0;
1306
Nicolas Capens0b2a7682022-04-04 00:43:17 -04001307 for(uint32_t i = start; i < indexIds.size(); i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05001308 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001309 auto &type = getType(typeId);
Nicolas Capens157ba262019-12-10 17:49:14 -05001310 ApplyDecorationsForId(&d, typeId);
1311
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001312 switch(type.definition.opcode())
Nicolas Capens157ba262019-12-10 17:49:14 -05001313 {
Nicolas Capens112faf42019-12-13 17:32:26 -05001314 case spv::OpTypeStruct:
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001315 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001316 int memberIndex = GetConstScalarInt(indexIds[i]);
1317 ApplyDecorationsForIdMember(&d, typeId, memberIndex);
1318 ASSERT(d.HasOffset);
1319 constantOffset += d.Offset;
1320 typeId = type.definition.word(2u + memberIndex);
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001321 }
Nicolas Capens112faf42019-12-13 17:32:26 -05001322 break;
1323 case spv::OpTypeArray:
1324 case spv::OpTypeRuntimeArray:
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001325 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001326 // TODO: b/127950082: Check bounds.
1327 ASSERT(d.HasArrayStride);
1328 auto &obj = getObject(indexIds[i]);
1329 if(obj.kind == Object::Kind::Constant)
1330 {
1331 constantOffset += d.ArrayStride * GetConstScalarInt(indexIds[i]);
1332 }
1333 else
1334 {
1335 ptr += SIMD::Int(d.ArrayStride) * state->getIntermediate(indexIds[i]).Int(0);
1336 }
1337 typeId = type.element;
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001338 }
Nicolas Capens112faf42019-12-13 17:32:26 -05001339 break;
1340 case spv::OpTypeMatrix:
Chris Forbes17813932019-04-18 11:45:54 -07001341 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001342 // TODO: b/127950082: Check bounds.
1343 ASSERT(d.HasMatrixStride);
1344 d.InsideMatrix = true;
1345 auto columnStride = (d.HasRowMajor && d.RowMajor) ? static_cast<int32_t>(sizeof(float)) : d.MatrixStride;
1346 auto &obj = getObject(indexIds[i]);
1347 if(obj.kind == Object::Kind::Constant)
1348 {
1349 constantOffset += columnStride * GetConstScalarInt(indexIds[i]);
1350 }
1351 else
1352 {
1353 ptr += SIMD::Int(columnStride) * state->getIntermediate(indexIds[i]).Int(0);
1354 }
1355 typeId = type.element;
Chris Forbes17813932019-04-18 11:45:54 -07001356 }
Nicolas Capens112faf42019-12-13 17:32:26 -05001357 break;
1358 case spv::OpTypeVector:
Chris Forbesa16238d2019-04-18 16:31:54 -07001359 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001360 auto elemStride = (d.InsideMatrix && d.HasRowMajor && d.RowMajor) ? d.MatrixStride : static_cast<int32_t>(sizeof(float));
1361 auto &obj = getObject(indexIds[i]);
1362 if(obj.kind == Object::Kind::Constant)
1363 {
1364 constantOffset += elemStride * GetConstScalarInt(indexIds[i]);
1365 }
1366 else
1367 {
1368 ptr += SIMD::Int(elemStride) * state->getIntermediate(indexIds[i]).Int(0);
1369 }
1370 typeId = type.element;
Chris Forbesa16238d2019-04-18 16:31:54 -07001371 }
Nicolas Capens112faf42019-12-13 17:32:26 -05001372 break;
1373 default:
1374 UNREACHABLE("%s", OpcodeName(type.definition.opcode()));
Ben Clayton60f15ec2019-05-09 17:50:01 +01001375 }
1376 }
1377
Nicolas Capens157ba262019-12-10 17:49:14 -05001378 ptr += constantOffset;
1379 return ptr;
1380}
Ben Clayton59cd59b2019-06-25 19:07:48 +01001381
Sean Rissera4c2e9b2022-05-03 14:47:41 -04001382SIMD::Pointer SpirvShader::WalkAccessChain(Object::ID baseId, Object::ID elementId, const Span &indexIds, bool nonUniform, EmitState const *state) const
Nicolas Capens157ba262019-12-10 17:49:14 -05001383{
1384 // TODO: avoid doing per-lane work in some cases if we can?
1385 auto routine = state->routine;
1386 auto &baseObject = getObject(baseId);
Nicolas Capens72f089c2020-04-08 23:37:08 -04001387 Type::ID typeId = getType(baseObject).element;
Alexis Hetu47c22462022-06-06 18:00:16 -04001388 Decorations d = GetDecorationsForId(baseObject.typeId());
Nicolas Capens94c73622022-06-06 13:05:38 -04001389 auto storageClass = getType(baseObject).storageClass;
1390 bool interleavedByLane = IsStorageInterleavedByLane(storageClass);
Nicolas Capens157ba262019-12-10 17:49:14 -05001391
1392 auto ptr = state->getPointer(baseId);
Alexis Hetu47c22462022-06-06 18:00:16 -04001393 OffsetToElement(ptr, elementId, d.ArrayStride, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001394
1395 int constantOffset = 0;
1396
Nicolas Capens0b2a7682022-04-04 00:43:17 -04001397 for(uint32_t i = 0; i < indexIds.size(); i++)
Ben Clayton76e9bc02019-02-26 15:02:18 +00001398 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001399 auto &type = getType(typeId);
Nicolas Capens157ba262019-12-10 17:49:14 -05001400 switch(type.opcode())
1401 {
Nicolas Capens112faf42019-12-13 17:32:26 -05001402 case spv::OpTypeStruct:
Nicolas Capens157ba262019-12-10 17:49:14 -05001403 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001404 int memberIndex = GetConstScalarInt(indexIds[i]);
1405 int offsetIntoStruct = 0;
1406 for(auto j = 0; j < memberIndex; j++)
Nicolas Capens157ba262019-12-10 17:49:14 -05001407 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001408 auto memberType = type.definition.word(2u + j);
Nicolas Capensff9f9b52020-04-14 00:46:38 -04001409 offsetIntoStruct += getType(memberType).componentCount * sizeof(float);
Nicolas Capens157ba262019-12-10 17:49:14 -05001410 }
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001411 constantOffset += 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 Claytonbc1c067be2019-12-17 20:37:37 +00001415
Nicolas Capens112faf42019-12-13 17:32:26 -05001416 case spv::OpTypeVector:
1417 case spv::OpTypeMatrix:
1418 case spv::OpTypeArray:
1419 case spv::OpTypeRuntimeArray:
Nicolas Capens157ba262019-12-10 17:49:14 -05001420 {
Nicolas Capens479d1432020-01-31 11:19:21 -05001421 // TODO(b/127950082): Check bounds.
Nicolas Capens94c73622022-06-06 13:05:38 -04001422 if(storageClass == spv::StorageClassUniformConstant)
Nicolas Capens157ba262019-12-10 17:49:14 -05001423 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001424 // indexing into an array of descriptors.
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001425 auto d = descriptorDecorations.at(baseId);
1426 ASSERT(d.DescriptorSet >= 0);
1427 ASSERT(d.Binding >= 0);
Nicolas Capensc7d5ec32020-04-22 01:11:37 -04001428 uint32_t descriptorSize = routine->pipelineLayout->getDescriptorSize(d.DescriptorSet, d.Binding);
Nicolas Capens479d1432020-01-31 11:19:21 -05001429
1430 auto &obj = getObject(indexIds[i]);
1431 if(obj.kind == Object::Kind::Constant)
1432 {
Sean Risseree0d0b42022-04-20 16:27:26 -04001433 ptr += descriptorSize * GetConstScalarInt(indexIds[i]);
Nicolas Capens479d1432020-01-31 11:19:21 -05001434 }
1435 else
1436 {
Sean Rissera4c2e9b2022-05-03 14:47:41 -04001437 nonUniform |= GetDecorationsForId(indexIds[i]).NonUniform;
1438 SIMD::Int intermediate = state->getIntermediate(indexIds[i]).Int(0);
1439 if(nonUniform)
1440 {
1441 // NonUniform array data can deal with pointers not bound by a 32-bit address
1442 // space, so we need to ensure we're using an array pointer, and not a base+offset
1443 // pointer.
Nicolas Capens942c6392022-06-30 00:20:40 -04001444 std::vector<Pointer<Byte>> pointers(SIMD::Width);
Sean Rissera4c2e9b2022-05-03 14:47:41 -04001445 for(int i = 0; i < SIMD::Width; i++)
1446 {
1447 pointers[i] = ptr.getPointerForLane(i);
1448 }
1449 ptr = SIMD::Pointer(pointers);
1450 ptr += descriptorSize * intermediate;
1451 }
1452 else
1453 {
1454 ptr += descriptorSize * Extract(intermediate, 0);
1455 }
Nicolas Capens479d1432020-01-31 11:19:21 -05001456 }
Nicolas Capens157ba262019-12-10 17:49:14 -05001457 }
1458 else
1459 {
Nicolas Capensff9f9b52020-04-14 00:46:38 -04001460 auto stride = getType(type.element).componentCount * static_cast<uint32_t>(sizeof(float));
Nicolas Capens94c73622022-06-06 13:05:38 -04001461
1462 if(interleavedByLane)
1463 {
1464 stride *= SIMD::Width;
1465 }
1466
1467 if(getObject(indexIds[i]).kind == Object::Kind::Constant)
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001468 {
1469 ptr += stride * GetConstScalarInt(indexIds[i]);
1470 }
1471 else
1472 {
1473 ptr += SIMD::Int(stride) * state->getIntermediate(indexIds[i]).Int(0);
1474 }
Nicolas Capens157ba262019-12-10 17:49:14 -05001475 }
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001476 typeId = type.element;
Nicolas Capens157ba262019-12-10 17:49:14 -05001477 }
Nicolas Capens112faf42019-12-13 17:32:26 -05001478 break;
Nicolas Capens157ba262019-12-10 17:49:14 -05001479
Nicolas Capens112faf42019-12-13 17:32:26 -05001480 default:
1481 UNREACHABLE("%s", OpcodeName(type.opcode()));
Nicolas Capens157ba262019-12-10 17:49:14 -05001482 }
Ben Clayton76e9bc02019-02-26 15:02:18 +00001483 }
1484
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001485 if(constantOffset != 0)
Ben Clayton30ee92e2019-08-13 14:21:44 +01001486 {
Nicolas Capens94c73622022-06-06 13:05:38 -04001487 if(interleavedByLane)
1488 {
1489 constantOffset *= SIMD::Width;
1490 }
1491
Nicolas Capens157ba262019-12-10 17:49:14 -05001492 ptr += constantOffset;
1493 }
Nicolas Capens94c73622022-06-06 13:05:38 -04001494
Nicolas Capens157ba262019-12-10 17:49:14 -05001495 return ptr;
1496}
Ben Clayton30ee92e2019-08-13 14:21:44 +01001497
Nicolas Capens0b2a7682022-04-04 00:43:17 -04001498uint32_t SpirvShader::WalkLiteralAccessChain(Type::ID typeId, const Span &indexes) const
Nicolas Capens157ba262019-12-10 17:49:14 -05001499{
1500 uint32_t componentOffset = 0;
Ben Clayton30ee92e2019-08-13 14:21:44 +01001501
Nicolas Capens0b2a7682022-04-04 00:43:17 -04001502 for(uint32_t i = 0; i < indexes.size(); i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05001503 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001504 auto &type = getType(typeId);
Nicolas Capens157ba262019-12-10 17:49:14 -05001505 switch(type.opcode())
Ben Clayton30ee92e2019-08-13 14:21:44 +01001506 {
Nicolas Capens112faf42019-12-13 17:32:26 -05001507 case spv::OpTypeStruct:
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001508 {
1509 int memberIndex = indexes[i];
1510 int offsetIntoStruct = 0;
1511 for(auto j = 0; j < memberIndex; j++)
1512 {
1513 auto memberType = type.definition.word(2u + j);
Nicolas Capensff9f9b52020-04-14 00:46:38 -04001514 offsetIntoStruct += getType(memberType).componentCount;
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001515 }
1516 componentOffset += offsetIntoStruct;
1517 typeId = type.definition.word(2u + memberIndex);
Nicolas Capens157ba262019-12-10 17:49:14 -05001518 }
Nicolas Capens112faf42019-12-13 17:32:26 -05001519 break;
Ben Clayton30ee92e2019-08-13 14:21:44 +01001520
Nicolas Capens112faf42019-12-13 17:32:26 -05001521 case spv::OpTypeVector:
1522 case spv::OpTypeMatrix:
1523 case spv::OpTypeArray:
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001524 {
1525 auto elementType = type.definition.word(2);
Nicolas Capensff9f9b52020-04-14 00:46:38 -04001526 auto stride = getType(elementType).componentCount;
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001527 componentOffset += stride * indexes[i];
1528 typeId = elementType;
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001529 }
Nicolas Capens112faf42019-12-13 17:32:26 -05001530 break;
Ben Clayton30ee92e2019-08-13 14:21:44 +01001531
Nicolas Capens112faf42019-12-13 17:32:26 -05001532 default:
1533 UNREACHABLE("%s", OpcodeName(type.opcode()));
Nicolas Capens157ba262019-12-10 17:49:14 -05001534 }
1535 }
Ben Clayton30ee92e2019-08-13 14:21:44 +01001536
Nicolas Capens157ba262019-12-10 17:49:14 -05001537 return componentOffset;
1538}
Ben Clayton30ee92e2019-08-13 14:21:44 +01001539
Nicolas Capens157ba262019-12-10 17:49:14 -05001540void SpirvShader::Decorations::Apply(spv::Decoration decoration, uint32_t arg)
1541{
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001542 switch(decoration)
Nicolas Capens157ba262019-12-10 17:49:14 -05001543 {
Nicolas Capens112faf42019-12-13 17:32:26 -05001544 case spv::DecorationLocation:
1545 HasLocation = true;
1546 Location = static_cast<int32_t>(arg);
1547 break;
1548 case spv::DecorationComponent:
1549 HasComponent = true;
1550 Component = arg;
1551 break;
1552 case spv::DecorationBuiltIn:
1553 HasBuiltIn = true;
1554 BuiltIn = static_cast<spv::BuiltIn>(arg);
1555 break;
1556 case spv::DecorationFlat:
1557 Flat = true;
1558 break;
1559 case spv::DecorationNoPerspective:
1560 NoPerspective = true;
1561 break;
1562 case spv::DecorationCentroid:
1563 Centroid = true;
1564 break;
1565 case spv::DecorationBlock:
1566 Block = true;
1567 break;
1568 case spv::DecorationBufferBlock:
1569 BufferBlock = true;
1570 break;
1571 case spv::DecorationOffset:
1572 HasOffset = true;
1573 Offset = static_cast<int32_t>(arg);
1574 break;
1575 case spv::DecorationArrayStride:
1576 HasArrayStride = true;
1577 ArrayStride = static_cast<int32_t>(arg);
1578 break;
1579 case spv::DecorationMatrixStride:
1580 HasMatrixStride = true;
1581 MatrixStride = static_cast<int32_t>(arg);
1582 break;
1583 case spv::DecorationRelaxedPrecision:
1584 RelaxedPrecision = true;
1585 break;
1586 case spv::DecorationRowMajor:
1587 HasRowMajor = true;
1588 RowMajor = true;
1589 break;
1590 case spv::DecorationColMajor:
1591 HasRowMajor = true;
1592 RowMajor = false;
Sean Risserda08cb22022-04-08 20:49:06 -04001593 break;
1594 case spv::DecorationNonUniform:
1595 NonUniform = true;
1596 break;
Nicolas Capens112faf42019-12-13 17:32:26 -05001597 default:
1598 // Intentionally partial, there are many decorations we just don't care about.
1599 break;
Ben Clayton30ee92e2019-08-13 14:21:44 +01001600 }
Chris Forbesc25b8072018-12-10 15:10:39 -08001601}
Nicolas Capens157ba262019-12-10 17:49:14 -05001602
1603void SpirvShader::Decorations::Apply(const sw::SpirvShader::Decorations &src)
1604{
1605 // Apply a decoration group to this set of decorations
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001606 if(src.HasBuiltIn)
Nicolas Capens157ba262019-12-10 17:49:14 -05001607 {
1608 HasBuiltIn = true;
1609 BuiltIn = src.BuiltIn;
1610 }
1611
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001612 if(src.HasLocation)
Nicolas Capens157ba262019-12-10 17:49:14 -05001613 {
1614 HasLocation = true;
1615 Location = src.Location;
1616 }
1617
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001618 if(src.HasComponent)
Nicolas Capens157ba262019-12-10 17:49:14 -05001619 {
1620 HasComponent = true;
1621 Component = src.Component;
1622 }
1623
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001624 if(src.HasOffset)
Nicolas Capens157ba262019-12-10 17:49:14 -05001625 {
1626 HasOffset = true;
1627 Offset = src.Offset;
1628 }
1629
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001630 if(src.HasArrayStride)
Nicolas Capens157ba262019-12-10 17:49:14 -05001631 {
1632 HasArrayStride = true;
1633 ArrayStride = src.ArrayStride;
1634 }
1635
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001636 if(src.HasMatrixStride)
Nicolas Capens157ba262019-12-10 17:49:14 -05001637 {
1638 HasMatrixStride = true;
1639 MatrixStride = src.MatrixStride;
1640 }
1641
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001642 if(src.HasRowMajor)
Nicolas Capens157ba262019-12-10 17:49:14 -05001643 {
1644 HasRowMajor = true;
1645 RowMajor = src.RowMajor;
1646 }
1647
1648 Flat |= src.Flat;
1649 NoPerspective |= src.NoPerspective;
1650 Centroid |= src.Centroid;
1651 Block |= src.Block;
1652 BufferBlock |= src.BufferBlock;
1653 RelaxedPrecision |= src.RelaxedPrecision;
1654 InsideMatrix |= src.InsideMatrix;
Sean Risserda08cb22022-04-08 20:49:06 -04001655 NonUniform |= src.NonUniform;
Nicolas Capens157ba262019-12-10 17:49:14 -05001656}
1657
1658void SpirvShader::DescriptorDecorations::Apply(const sw::SpirvShader::DescriptorDecorations &src)
1659{
1660 if(src.DescriptorSet >= 0)
1661 {
1662 DescriptorSet = src.DescriptorSet;
1663 }
1664
1665 if(src.Binding >= 0)
1666 {
1667 Binding = src.Binding;
1668 }
1669
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001670 if(src.InputAttachmentIndex >= 0)
Nicolas Capens157ba262019-12-10 17:49:14 -05001671 {
1672 InputAttachmentIndex = src.InputAttachmentIndex;
1673 }
1674}
1675
Nicolas Capensd6806b32022-03-02 10:16:31 -05001676SpirvShader::Decorations SpirvShader::GetDecorationsForId(TypeOrObjectID id) const
1677{
1678 Decorations d;
1679 ApplyDecorationsForId(&d, id);
1680
1681 return d;
1682}
1683
Nicolas Capens157ba262019-12-10 17:49:14 -05001684void SpirvShader::ApplyDecorationsForId(Decorations *d, TypeOrObjectID id) const
1685{
1686 auto it = decorations.find(id);
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001687 if(it != decorations.end())
Nicolas Capensd6806b32022-03-02 10:16:31 -05001688 {
Nicolas Capens157ba262019-12-10 17:49:14 -05001689 d->Apply(it->second);
Nicolas Capensd6806b32022-03-02 10:16:31 -05001690 }
Nicolas Capens157ba262019-12-10 17:49:14 -05001691}
1692
1693void SpirvShader::ApplyDecorationsForIdMember(Decorations *d, Type::ID id, uint32_t member) const
1694{
1695 auto it = memberDecorations.find(id);
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001696 if(it != memberDecorations.end() && member < it->second.size())
Nicolas Capens157ba262019-12-10 17:49:14 -05001697 {
1698 d->Apply(it->second[member]);
1699 }
1700}
1701
1702void SpirvShader::DefineResult(const InsnIterator &insn)
1703{
1704 Type::ID typeId = insn.word(1);
1705 Object::ID resultId = insn.word(2);
1706 auto &object = defs[resultId];
Nicolas Capens157ba262019-12-10 17:49:14 -05001707
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001708 switch(getType(typeId).opcode())
Nicolas Capens157ba262019-12-10 17:49:14 -05001709 {
Nicolas Capens112faf42019-12-13 17:32:26 -05001710 case spv::OpTypePointer:
1711 case spv::OpTypeImage:
1712 case spv::OpTypeSampledImage:
1713 case spv::OpTypeSampler:
1714 object.kind = Object::Kind::Pointer;
1715 break;
Nicolas Capens157ba262019-12-10 17:49:14 -05001716
Nicolas Capens112faf42019-12-13 17:32:26 -05001717 default:
1718 object.kind = Object::Kind::Intermediate;
Nicolas Capens157ba262019-12-10 17:49:14 -05001719 }
1720
1721 object.definition = insn;
Ben Claytonb0ca2a82020-01-08 13:00:57 +00001722 dbgDeclareResult(insn, resultId);
Nicolas Capens157ba262019-12-10 17:49:14 -05001723}
1724
Alexis Hetu8941bde2021-11-17 17:45:40 -05001725OutOfBoundsBehavior SpirvShader::getOutOfBoundsBehavior(Object::ID pointerId, EmitState const *state) const
Nicolas Capens157ba262019-12-10 17:49:14 -05001726{
Alexis Hetu8941bde2021-11-17 17:45:40 -05001727 auto it = descriptorDecorations.find(pointerId);
1728 if(it != descriptorDecorations.end())
1729 {
1730 const auto &d = it->second;
1731 if((d.DescriptorSet >= 0) && (d.Binding >= 0))
1732 {
1733 auto descriptorType = state->routine->pipelineLayout->getDescriptorType(d.DescriptorSet, d.Binding);
1734 if(descriptorType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT)
1735 {
1736 return OutOfBoundsBehavior::UndefinedBehavior;
1737 }
1738 }
1739 }
1740
1741 auto &pointer = getObject(pointerId);
1742 auto &pointerTy = getType(pointer);
1743 switch(pointerTy.storageClass)
Nicolas Capens157ba262019-12-10 17:49:14 -05001744 {
Nicolas Capens112faf42019-12-13 17:32:26 -05001745 case spv::StorageClassUniform:
1746 case spv::StorageClassStorageBuffer:
1747 // Buffer resource access. robustBufferAccess feature applies.
1748 return robustBufferAccess ? OutOfBoundsBehavior::RobustBufferAccess
1749 : OutOfBoundsBehavior::UndefinedBehavior;
1750
Alexis Hetu71ec98e2022-06-14 16:58:44 -04001751 case spv::StorageClassPhysicalStorageBuffer:
1752 return OutOfBoundsBehavior::UndefinedBehavior;
1753
Nicolas Capens112faf42019-12-13 17:32:26 -05001754 case spv::StorageClassImage:
1755 // VK_EXT_image_robustness requires nullifying out-of-bounds accesses.
1756 // TODO(b/162327166): Only perform bounds checks when VK_EXT_image_robustness is enabled.
1757 return OutOfBoundsBehavior::Nullify;
1758
1759 case spv::StorageClassInput:
1760 if(executionModel == spv::ExecutionModelVertex)
1761 {
1762 // Vertex attributes follow robustBufferAccess rules.
Nicolas Capens157ba262019-12-10 17:49:14 -05001763 return robustBufferAccess ? OutOfBoundsBehavior::RobustBufferAccess
1764 : OutOfBoundsBehavior::UndefinedBehavior;
Nicolas Capens112faf42019-12-13 17:32:26 -05001765 }
1766 // Fall through to default case.
1767 default:
Nicolas Capense4b77942021-08-03 17:09:41 -04001768 // TODO(b/192310780): StorageClassFunction out-of-bounds accesses are undefined behavior.
Nicolas Capens112faf42019-12-13 17:32:26 -05001769 // TODO(b/137183137): Optimize if the pointer resulted from OpInBoundsAccessChain.
1770 // TODO(b/131224163): Optimize cases statically known to be within bounds.
1771 return OutOfBoundsBehavior::UndefinedValue;
Nicolas Capens157ba262019-12-10 17:49:14 -05001772 }
1773
1774 return OutOfBoundsBehavior::Nullify;
1775}
1776
1777// emit-time
1778
1779void SpirvShader::emitProlog(SpirvRoutine *routine) const
1780{
Daniele Vettorelf908b182022-02-09 17:38:08 +00001781 if(IsProfilingEnabled())
1782 {
1783 routine->profData = std::make_unique<SpirvProfileData>();
1784 }
1785
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001786 for(auto insn : *this)
Nicolas Capens157ba262019-12-10 17:49:14 -05001787 {
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001788 switch(insn.opcode())
Nicolas Capens157ba262019-12-10 17:49:14 -05001789 {
Nicolas Capens112faf42019-12-13 17:32:26 -05001790 case spv::OpVariable:
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001791 {
Nicolas Capens71186752020-04-09 01:05:31 -04001792 auto resultPointerType = getType(insn.resultTypeId());
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001793 auto pointeeType = getType(resultPointerType.element);
Nicolas Capens157ba262019-12-10 17:49:14 -05001794
Nicolas Capensff9f9b52020-04-14 00:46:38 -04001795 if(pointeeType.componentCount > 0) // TODO: what to do about zero-slot objects?
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001796 {
Nicolas Capensff9f9b52020-04-14 00:46:38 -04001797 routine->createVariable(insn.resultId(), pointeeType.componentCount);
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001798 }
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001799 }
Nicolas Capens112faf42019-12-13 17:32:26 -05001800 break;
1801
1802 case spv::OpPhi:
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001803 {
Nicolas Capens71186752020-04-09 01:05:31 -04001804 auto type = getType(insn.resultTypeId());
Nicolas Capensff9f9b52020-04-14 00:46:38 -04001805 routine->phis.emplace(insn.resultId(), SpirvRoutine::Variable(type.componentCount));
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001806 }
Nicolas Capens112faf42019-12-13 17:32:26 -05001807 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001808
Nicolas Capensf0e8ec22021-11-12 13:57:14 -05001809 case spv::OpImageSampleImplicitLod:
1810 case spv::OpImageSampleExplicitLod:
1811 case spv::OpImageSampleDrefImplicitLod:
1812 case spv::OpImageSampleDrefExplicitLod:
1813 case spv::OpImageSampleProjImplicitLod:
1814 case spv::OpImageSampleProjExplicitLod:
1815 case spv::OpImageSampleProjDrefImplicitLod:
1816 case spv::OpImageSampleProjDrefExplicitLod:
Nicolas Capens112faf42019-12-13 17:32:26 -05001817 case spv::OpImageFetch:
1818 case spv::OpImageGather:
Nicolas Capensf0e8ec22021-11-12 13:57:14 -05001819 case spv::OpImageDrefGather:
1820 case spv::OpImageWrite:
Nicolas Capens112faf42019-12-13 17:32:26 -05001821 case spv::OpImageQueryLod:
Nicolas Capens96b34f72021-11-09 00:41:40 -05001822 {
1823 // The 'inline' sampler caches must be created in the prolog to initialize the tags.
1824 uint32_t instructionPosition = insn.distanceFrom(this->begin());
1825 routine->samplerCache.emplace(instructionPosition, SpirvRoutine::SamplerCache{});
1826 }
Nicolas Capens112faf42019-12-13 17:32:26 -05001827 break;
Nicolas Capens157ba262019-12-10 17:49:14 -05001828
Nicolas Capens112faf42019-12-13 17:32:26 -05001829 default:
1830 // Nothing else produces interface variables, so can all be safely ignored.
1831 break;
Nicolas Capens157ba262019-12-10 17:49:14 -05001832 }
1833 }
1834}
1835
Alexis Hetu0bcb71f2021-01-14 12:05:12 -05001836void 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 -05001837{
Alexis Hetu8941bde2021-11-17 17:45:40 -05001838 EmitState state(routine, entryPoint, activeLaneMask, storesAndAtomicsMask, descriptorSets, multiSampleCount);
Nicolas Capens157ba262019-12-10 17:49:14 -05001839
Ben Claytonb0ca2a82020-01-08 13:00:57 +00001840 dbgBeginEmit(&state);
1841 defer(dbgEndEmit(&state));
1842
Nicolas Capens157ba262019-12-10 17:49:14 -05001843 // Emit everything up to the first label
1844 // TODO: Separate out dispatch of block from non-block instructions?
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001845 for(auto insn : *this)
Nicolas Capens157ba262019-12-10 17:49:14 -05001846 {
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001847 if(insn.opcode() == spv::OpLabel)
Nicolas Capens157ba262019-12-10 17:49:14 -05001848 {
1849 break;
1850 }
1851 EmitInstruction(insn, &state);
1852 }
1853
1854 // Emit all the blocks starting from entryPoint.
1855 EmitBlocks(getFunction(entryPoint).entry, &state);
1856}
1857
1858void SpirvShader::EmitInstructions(InsnIterator begin, InsnIterator end, EmitState *state) const
1859{
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001860 for(auto insn = begin; insn != end; insn++)
Nicolas Capens157ba262019-12-10 17:49:14 -05001861 {
1862 auto res = EmitInstruction(insn, state);
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001863 switch(res)
Nicolas Capens157ba262019-12-10 17:49:14 -05001864 {
Nicolas Capens112faf42019-12-13 17:32:26 -05001865 case EmitResult::Continue:
1866 continue;
1867 case EmitResult::Terminator:
1868 break;
1869 default:
1870 UNREACHABLE("Unexpected EmitResult %d", int(res));
1871 break;
Nicolas Capens157ba262019-12-10 17:49:14 -05001872 }
1873 }
1874}
1875
1876SpirvShader::EmitResult SpirvShader::EmitInstruction(InsnIterator insn, EmitState *state) const
1877{
Ben Claytonb0ca2a82020-01-08 13:00:57 +00001878 dbgBeginEmitInstruction(insn, state);
1879 defer(dbgEndEmitInstruction(insn, state));
1880
Nicolas Capens157ba262019-12-10 17:49:14 -05001881 auto opcode = insn.opcode();
1882
Daniele Vettorelf908b182022-02-09 17:38:08 +00001883 if(IsProfilingEnabled() && IsStatement(opcode))
1884 {
1885 int64_t *counter = &state->routine->profData->spvOpExecutionCount[opcode];
1886 AddAtomic(Pointer<Long>(ConstantPointer(counter)), 1);
1887 }
1888
Ben Claytonfc951cd2019-05-15 17:16:56 +01001889#if SPIRV_SHADER_ENABLE_DBG
1890 {
1891 auto text = spvtools::spvInstructionBinaryToText(
Sean Risser019feda2020-11-09 14:19:27 -05001892 vk::SPIRV_VERSION,
Nicolas Capens0b2a7682022-04-04 00:43:17 -04001893 insn.data(),
Ben Claytonfc951cd2019-05-15 17:16:56 +01001894 insn.wordCount(),
1895 insns.data(),
1896 insns.size(),
1897 SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
1898 SPIRV_SHADER_DBG("{0}", text);
1899 }
1900#endif // ENABLE_DBG_MSGS
1901
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001902 switch(opcode)
Nicolas Capens157ba262019-12-10 17:49:14 -05001903 {
Nicolas Capens112faf42019-12-13 17:32:26 -05001904 case spv::OpTypeVoid:
1905 case spv::OpTypeInt:
1906 case spv::OpTypeFloat:
1907 case spv::OpTypeBool:
1908 case spv::OpTypeVector:
1909 case spv::OpTypeArray:
1910 case spv::OpTypeRuntimeArray:
1911 case spv::OpTypeMatrix:
1912 case spv::OpTypeStruct:
1913 case spv::OpTypePointer:
Alexis Hetuc582db22022-06-14 16:46:56 -04001914 case spv::OpTypeForwardPointer:
Nicolas Capens112faf42019-12-13 17:32:26 -05001915 case spv::OpTypeFunction:
1916 case spv::OpTypeImage:
1917 case spv::OpTypeSampledImage:
1918 case spv::OpTypeSampler:
1919 case spv::OpExecutionMode:
Alexis Hetu09ed4582022-02-23 14:24:50 -05001920 case spv::OpExecutionModeId:
Nicolas Capens112faf42019-12-13 17:32:26 -05001921 case spv::OpMemoryModel:
1922 case spv::OpFunction:
1923 case spv::OpFunctionEnd:
1924 case spv::OpConstant:
1925 case spv::OpConstantNull:
1926 case spv::OpConstantTrue:
1927 case spv::OpConstantFalse:
1928 case spv::OpConstantComposite:
1929 case spv::OpSpecConstant:
1930 case spv::OpSpecConstantTrue:
1931 case spv::OpSpecConstantFalse:
1932 case spv::OpSpecConstantComposite:
1933 case spv::OpSpecConstantOp:
1934 case spv::OpUndef:
1935 case spv::OpExtension:
1936 case spv::OpCapability:
1937 case spv::OpEntryPoint:
1938 case spv::OpExtInstImport:
1939 case spv::OpDecorate:
1940 case spv::OpMemberDecorate:
1941 case spv::OpGroupDecorate:
1942 case spv::OpGroupMemberDecorate:
1943 case spv::OpDecorationGroup:
1944 case spv::OpDecorateId:
1945 case spv::OpDecorateString:
1946 case spv::OpMemberDecorateString:
1947 case spv::OpName:
1948 case spv::OpMemberName:
1949 case spv::OpSource:
1950 case spv::OpSourceContinued:
1951 case spv::OpSourceExtension:
1952 case spv::OpNoLine:
1953 case spv::OpModuleProcessed:
1954 case spv::OpString:
1955 // Nothing to do at emit time. These are either fully handled at analysis time,
1956 // or don't require any work at all.
1957 return EmitResult::Continue;
Nicolas Capens157ba262019-12-10 17:49:14 -05001958
Nicolas Capens112faf42019-12-13 17:32:26 -05001959 case spv::OpLine:
1960 return EmitLine(insn, state);
Ben Claytonb0ca2a82020-01-08 13:00:57 +00001961
Nicolas Capens112faf42019-12-13 17:32:26 -05001962 case spv::OpLabel:
1963 return EmitResult::Continue;
Nicolas Capens157ba262019-12-10 17:49:14 -05001964
Nicolas Capens112faf42019-12-13 17:32:26 -05001965 case spv::OpVariable:
1966 return EmitVariable(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001967
Nicolas Capens112faf42019-12-13 17:32:26 -05001968 case spv::OpLoad:
1969 case spv::OpAtomicLoad:
1970 return EmitLoad(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001971
Nicolas Capens112faf42019-12-13 17:32:26 -05001972 case spv::OpStore:
1973 case spv::OpAtomicStore:
1974 return EmitStore(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001975
Nicolas Capens112faf42019-12-13 17:32:26 -05001976 case spv::OpAtomicIAdd:
1977 case spv::OpAtomicISub:
1978 case spv::OpAtomicSMin:
1979 case spv::OpAtomicSMax:
1980 case spv::OpAtomicUMin:
1981 case spv::OpAtomicUMax:
1982 case spv::OpAtomicAnd:
1983 case spv::OpAtomicOr:
1984 case spv::OpAtomicXor:
1985 case spv::OpAtomicIIncrement:
1986 case spv::OpAtomicIDecrement:
1987 case spv::OpAtomicExchange:
1988 return EmitAtomicOp(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001989
Nicolas Capens112faf42019-12-13 17:32:26 -05001990 case spv::OpAtomicCompareExchange:
1991 return EmitAtomicCompareExchange(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001992
Nicolas Capens112faf42019-12-13 17:32:26 -05001993 case spv::OpAccessChain:
1994 case spv::OpInBoundsAccessChain:
Alexis Hetu47c22462022-06-06 18:00:16 -04001995 case spv::OpPtrAccessChain:
Nicolas Capens112faf42019-12-13 17:32:26 -05001996 return EmitAccessChain(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05001997
Nicolas Capens112faf42019-12-13 17:32:26 -05001998 case spv::OpCompositeConstruct:
1999 return EmitCompositeConstruct(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002000
Nicolas Capens112faf42019-12-13 17:32:26 -05002001 case spv::OpCompositeInsert:
2002 return EmitCompositeInsert(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002003
Nicolas Capens112faf42019-12-13 17:32:26 -05002004 case spv::OpCompositeExtract:
2005 return EmitCompositeExtract(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002006
Nicolas Capens112faf42019-12-13 17:32:26 -05002007 case spv::OpVectorShuffle:
2008 return EmitVectorShuffle(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002009
Nicolas Capens112faf42019-12-13 17:32:26 -05002010 case spv::OpVectorExtractDynamic:
2011 return EmitVectorExtractDynamic(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002012
Nicolas Capens112faf42019-12-13 17:32:26 -05002013 case spv::OpVectorInsertDynamic:
2014 return EmitVectorInsertDynamic(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002015
Nicolas Capens112faf42019-12-13 17:32:26 -05002016 case spv::OpVectorTimesScalar:
2017 case spv::OpMatrixTimesScalar:
2018 return EmitVectorTimesScalar(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002019
Nicolas Capens112faf42019-12-13 17:32:26 -05002020 case spv::OpMatrixTimesVector:
2021 return EmitMatrixTimesVector(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002022
Nicolas Capens112faf42019-12-13 17:32:26 -05002023 case spv::OpVectorTimesMatrix:
2024 return EmitVectorTimesMatrix(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002025
Nicolas Capens112faf42019-12-13 17:32:26 -05002026 case spv::OpMatrixTimesMatrix:
2027 return EmitMatrixTimesMatrix(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002028
Nicolas Capens112faf42019-12-13 17:32:26 -05002029 case spv::OpOuterProduct:
2030 return EmitOuterProduct(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002031
Nicolas Capens112faf42019-12-13 17:32:26 -05002032 case spv::OpTranspose:
2033 return EmitTranspose(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002034
Nicolas Capens112faf42019-12-13 17:32:26 -05002035 case spv::OpNot:
2036 case spv::OpBitFieldInsert:
2037 case spv::OpBitFieldSExtract:
2038 case spv::OpBitFieldUExtract:
2039 case spv::OpBitReverse:
2040 case spv::OpBitCount:
2041 case spv::OpSNegate:
2042 case spv::OpFNegate:
2043 case spv::OpLogicalNot:
2044 case spv::OpConvertFToU:
2045 case spv::OpConvertFToS:
2046 case spv::OpConvertSToF:
2047 case spv::OpConvertUToF:
2048 case spv::OpBitcast:
2049 case spv::OpIsInf:
2050 case spv::OpIsNan:
2051 case spv::OpDPdx:
2052 case spv::OpDPdxCoarse:
2053 case spv::OpDPdy:
2054 case spv::OpDPdyCoarse:
2055 case spv::OpFwidth:
2056 case spv::OpFwidthCoarse:
2057 case spv::OpDPdxFine:
2058 case spv::OpDPdyFine:
2059 case spv::OpFwidthFine:
2060 case spv::OpQuantizeToF16:
2061 return EmitUnaryOp(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002062
Nicolas Capens112faf42019-12-13 17:32:26 -05002063 case spv::OpIAdd:
2064 case spv::OpISub:
2065 case spv::OpIMul:
2066 case spv::OpSDiv:
2067 case spv::OpUDiv:
2068 case spv::OpFAdd:
2069 case spv::OpFSub:
2070 case spv::OpFMul:
2071 case spv::OpFDiv:
2072 case spv::OpFMod:
2073 case spv::OpFRem:
2074 case spv::OpFOrdEqual:
2075 case spv::OpFUnordEqual:
2076 case spv::OpFOrdNotEqual:
2077 case spv::OpFUnordNotEqual:
2078 case spv::OpFOrdLessThan:
2079 case spv::OpFUnordLessThan:
2080 case spv::OpFOrdGreaterThan:
2081 case spv::OpFUnordGreaterThan:
2082 case spv::OpFOrdLessThanEqual:
2083 case spv::OpFUnordLessThanEqual:
2084 case spv::OpFOrdGreaterThanEqual:
2085 case spv::OpFUnordGreaterThanEqual:
2086 case spv::OpSMod:
2087 case spv::OpSRem:
2088 case spv::OpUMod:
2089 case spv::OpIEqual:
2090 case spv::OpINotEqual:
2091 case spv::OpUGreaterThan:
2092 case spv::OpSGreaterThan:
2093 case spv::OpUGreaterThanEqual:
2094 case spv::OpSGreaterThanEqual:
2095 case spv::OpULessThan:
2096 case spv::OpSLessThan:
2097 case spv::OpULessThanEqual:
2098 case spv::OpSLessThanEqual:
2099 case spv::OpShiftRightLogical:
2100 case spv::OpShiftRightArithmetic:
2101 case spv::OpShiftLeftLogical:
2102 case spv::OpBitwiseOr:
2103 case spv::OpBitwiseXor:
2104 case spv::OpBitwiseAnd:
2105 case spv::OpLogicalOr:
2106 case spv::OpLogicalAnd:
2107 case spv::OpLogicalEqual:
2108 case spv::OpLogicalNotEqual:
2109 case spv::OpUMulExtended:
2110 case spv::OpSMulExtended:
2111 case spv::OpIAddCarry:
2112 case spv::OpISubBorrow:
2113 return EmitBinaryOp(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002114
Nicolas Capens112faf42019-12-13 17:32:26 -05002115 case spv::OpDot:
sugoi1e3d910c2022-02-22 15:07:21 -05002116 case spv::OpSDot:
2117 case spv::OpUDot:
2118 case spv::OpSUDot:
2119 case spv::OpSDotAccSat:
2120 case spv::OpUDotAccSat:
2121 case spv::OpSUDotAccSat:
Nicolas Capens112faf42019-12-13 17:32:26 -05002122 return EmitDot(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002123
Nicolas Capens112faf42019-12-13 17:32:26 -05002124 case spv::OpSelect:
2125 return EmitSelect(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002126
Nicolas Capens112faf42019-12-13 17:32:26 -05002127 case spv::OpExtInst:
2128 return EmitExtendedInstruction(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002129
Nicolas Capens112faf42019-12-13 17:32:26 -05002130 case spv::OpAny:
2131 return EmitAny(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002132
Nicolas Capens112faf42019-12-13 17:32:26 -05002133 case spv::OpAll:
2134 return EmitAll(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002135
Nicolas Capens112faf42019-12-13 17:32:26 -05002136 case spv::OpBranch:
2137 return EmitBranch(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002138
Nicolas Capens112faf42019-12-13 17:32:26 -05002139 case spv::OpPhi:
2140 return EmitPhi(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002141
Nicolas Capens112faf42019-12-13 17:32:26 -05002142 case spv::OpSelectionMerge:
2143 case spv::OpLoopMerge:
2144 return EmitResult::Continue;
Nicolas Capens157ba262019-12-10 17:49:14 -05002145
Nicolas Capens112faf42019-12-13 17:32:26 -05002146 case spv::OpBranchConditional:
2147 return EmitBranchConditional(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002148
Nicolas Capens112faf42019-12-13 17:32:26 -05002149 case spv::OpSwitch:
2150 return EmitSwitch(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002151
Nicolas Capens112faf42019-12-13 17:32:26 -05002152 case spv::OpUnreachable:
2153 return EmitUnreachable(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002154
Nicolas Capens112faf42019-12-13 17:32:26 -05002155 case spv::OpReturn:
2156 return EmitReturn(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002157
Nicolas Capens112faf42019-12-13 17:32:26 -05002158 case spv::OpFunctionCall:
2159 return EmitFunctionCall(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002160
Nicolas Capens112faf42019-12-13 17:32:26 -05002161 case spv::OpKill:
Alexis Hetubbe92e92022-03-23 13:32:00 -04002162 case spv::OpTerminateInvocation:
Nicolas Capens23ccff72022-04-05 13:00:22 -04002163 return EmitTerminateInvocation(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002164
Alexis Hetu4d2f9f12022-02-22 17:16:13 -05002165 case spv::OpDemoteToHelperInvocation:
2166 return EmitDemoteToHelperInvocation(insn, state);
2167
2168 case spv::OpIsHelperInvocationEXT:
2169 return EmitIsHelperInvocation(insn, state);
2170
Nicolas Capens112faf42019-12-13 17:32:26 -05002171 case spv::OpImageSampleImplicitLod:
Nicolas Capens112faf42019-12-13 17:32:26 -05002172 case spv::OpImageSampleExplicitLod:
Nicolas Capens112faf42019-12-13 17:32:26 -05002173 case spv::OpImageSampleDrefImplicitLod:
Nicolas Capens112faf42019-12-13 17:32:26 -05002174 case spv::OpImageSampleDrefExplicitLod:
Nicolas Capens112faf42019-12-13 17:32:26 -05002175 case spv::OpImageSampleProjImplicitLod:
Nicolas Capens112faf42019-12-13 17:32:26 -05002176 case spv::OpImageSampleProjExplicitLod:
Nicolas Capens112faf42019-12-13 17:32:26 -05002177 case spv::OpImageSampleProjDrefImplicitLod:
Nicolas Capens112faf42019-12-13 17:32:26 -05002178 case spv::OpImageSampleProjDrefExplicitLod:
Nicolas Capens112faf42019-12-13 17:32:26 -05002179 case spv::OpImageGather:
Nicolas Capens112faf42019-12-13 17:32:26 -05002180 case spv::OpImageDrefGather:
Nicolas Capens112faf42019-12-13 17:32:26 -05002181 case spv::OpImageFetch:
Nicolas Capens05963ef2021-11-08 20:27:35 -05002182 case spv::OpImageQueryLod:
Nicolas Capens6745fce2021-11-04 16:01:31 -04002183 return EmitImageSample(ImageInstruction(insn, *this), state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002184
Nicolas Capens112faf42019-12-13 17:32:26 -05002185 case spv::OpImageQuerySizeLod:
2186 return EmitImageQuerySizeLod(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002187
Nicolas Capens112faf42019-12-13 17:32:26 -05002188 case spv::OpImageQuerySize:
2189 return EmitImageQuerySize(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002190
Nicolas Capens112faf42019-12-13 17:32:26 -05002191 case spv::OpImageQueryLevels:
2192 return EmitImageQueryLevels(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002193
Nicolas Capens112faf42019-12-13 17:32:26 -05002194 case spv::OpImageQuerySamples:
2195 return EmitImageQuerySamples(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002196
Nicolas Capens112faf42019-12-13 17:32:26 -05002197 case spv::OpImageRead:
Nicolas Capens6745fce2021-11-04 16:01:31 -04002198 return EmitImageRead(ImageInstruction(insn, *this), state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002199
Nicolas Capens112faf42019-12-13 17:32:26 -05002200 case spv::OpImageWrite:
Nicolas Capens6745fce2021-11-04 16:01:31 -04002201 return EmitImageWrite(ImageInstruction(insn, *this), state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002202
Nicolas Capens112faf42019-12-13 17:32:26 -05002203 case spv::OpImageTexelPointer:
Nicolas Capens0b241e72021-11-11 01:49:50 -05002204 return EmitImageTexelPointer(ImageInstruction(insn, *this), state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002205
Nicolas Capens112faf42019-12-13 17:32:26 -05002206 case spv::OpSampledImage:
2207 case spv::OpImage:
2208 return EmitSampledImageCombineOrSplit(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002209
Nicolas Capens112faf42019-12-13 17:32:26 -05002210 case spv::OpCopyObject:
2211 case spv::OpCopyLogical:
2212 return EmitCopyObject(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002213
Nicolas Capens112faf42019-12-13 17:32:26 -05002214 case spv::OpCopyMemory:
2215 return EmitCopyMemory(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002216
Nicolas Capens112faf42019-12-13 17:32:26 -05002217 case spv::OpControlBarrier:
2218 return EmitControlBarrier(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002219
Nicolas Capens112faf42019-12-13 17:32:26 -05002220 case spv::OpMemoryBarrier:
2221 return EmitMemoryBarrier(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002222
Nicolas Capens112faf42019-12-13 17:32:26 -05002223 case spv::OpGroupNonUniformElect:
2224 case spv::OpGroupNonUniformAll:
2225 case spv::OpGroupNonUniformAny:
2226 case spv::OpGroupNonUniformAllEqual:
2227 case spv::OpGroupNonUniformBroadcast:
2228 case spv::OpGroupNonUniformBroadcastFirst:
Sean Risser1144d582022-06-23 13:53:11 -04002229 case spv::OpGroupNonUniformQuadBroadcast:
2230 case spv::OpGroupNonUniformQuadSwap:
Nicolas Capens112faf42019-12-13 17:32:26 -05002231 case spv::OpGroupNonUniformBallot:
2232 case spv::OpGroupNonUniformInverseBallot:
2233 case spv::OpGroupNonUniformBallotBitExtract:
2234 case spv::OpGroupNonUniformBallotBitCount:
2235 case spv::OpGroupNonUniformBallotFindLSB:
2236 case spv::OpGroupNonUniformBallotFindMSB:
2237 case spv::OpGroupNonUniformShuffle:
2238 case spv::OpGroupNonUniformShuffleXor:
2239 case spv::OpGroupNonUniformShuffleUp:
2240 case spv::OpGroupNonUniformShuffleDown:
2241 case spv::OpGroupNonUniformIAdd:
2242 case spv::OpGroupNonUniformFAdd:
2243 case spv::OpGroupNonUniformIMul:
2244 case spv::OpGroupNonUniformFMul:
2245 case spv::OpGroupNonUniformSMin:
2246 case spv::OpGroupNonUniformUMin:
2247 case spv::OpGroupNonUniformFMin:
2248 case spv::OpGroupNonUniformSMax:
2249 case spv::OpGroupNonUniformUMax:
2250 case spv::OpGroupNonUniformFMax:
2251 case spv::OpGroupNonUniformBitwiseAnd:
2252 case spv::OpGroupNonUniformBitwiseOr:
2253 case spv::OpGroupNonUniformBitwiseXor:
2254 case spv::OpGroupNonUniformLogicalAnd:
2255 case spv::OpGroupNonUniformLogicalOr:
2256 case spv::OpGroupNonUniformLogicalXor:
2257 return EmitGroupNonUniform(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002258
Nicolas Capens112faf42019-12-13 17:32:26 -05002259 case spv::OpArrayLength:
2260 return EmitArrayLength(insn, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002261
Nicolas Capens112faf42019-12-13 17:32:26 -05002262 default:
2263 UNREACHABLE("%s", OpcodeName(opcode));
2264 break;
Nicolas Capens157ba262019-12-10 17:49:14 -05002265 }
2266
2267 return EmitResult::Continue;
2268}
2269
2270SpirvShader::EmitResult SpirvShader::EmitAccessChain(InsnIterator insn, EmitState *state) const
2271{
2272 Type::ID typeId = insn.word(1);
2273 Object::ID resultId = insn.word(2);
Sean Risserda08cb22022-04-08 20:49:06 -04002274 bool nonUniform = GetDecorationsForId(resultId).NonUniform;
Nicolas Capens157ba262019-12-10 17:49:14 -05002275 Object::ID baseId = insn.word(3);
Nicolas Capens157ba262019-12-10 17:49:14 -05002276 auto &type = getType(typeId);
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002277 ASSERT(type.componentCount == 1);
Nicolas Capens157ba262019-12-10 17:49:14 -05002278 ASSERT(getObject(resultId).kind == Object::Kind::Pointer);
2279
Alexis Hetu47c22462022-06-06 18:00:16 -04002280 Object::ID elementId = (insn.opcode() == spv::OpPtrAccessChain) ? insn.word(4) : 0;
2281 int indexId = (insn.opcode() == spv::OpPtrAccessChain) ? 5 : 4;
Sean Rissera4c2e9b2022-05-03 14:47:41 -04002282 // TODO(b/236280746): Eliminate lookahead by optimizing inside SIMD::Pointer.
2283 for(auto it = insn; it != end(); it++)
2284 {
2285 if(it.opcode() == spv::OpLoad)
2286 {
2287 Object::ID pointerId = it.word(3);
2288 if(pointerId.value() == resultId.value())
2289 {
2290 nonUniform |= GetDecorationsForId(it.word(2)).NonUniform;
2291 break;
2292 }
2293 }
2294 }
Alexis Hetu47c22462022-06-06 18:00:16 -04002295
Nicolas Capens157ba262019-12-10 17:49:14 -05002296 if(type.storageClass == spv::StorageClassPushConstant ||
2297 type.storageClass == spv::StorageClassUniform ||
Alexis Hetu71ec98e2022-06-14 16:58:44 -04002298 type.storageClass == spv::StorageClassStorageBuffer ||
2299 type.storageClass == spv::StorageClassPhysicalStorageBuffer)
Nicolas Capens157ba262019-12-10 17:49:14 -05002300 {
Sean Risserda08cb22022-04-08 20:49:06 -04002301 auto ptr = WalkExplicitLayoutAccessChain(baseId, elementId, Span(insn, indexId, insn.wordCount() - indexId), nonUniform, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002302 state->createPointer(resultId, ptr);
2303 }
2304 else
2305 {
Sean Rissera4c2e9b2022-05-03 14:47:41 -04002306 auto ptr = WalkAccessChain(baseId, elementId, Span(insn, indexId, insn.wordCount() - indexId), nonUniform, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002307 state->createPointer(resultId, ptr);
2308 }
2309
2310 return EmitResult::Continue;
2311}
2312
2313SpirvShader::EmitResult SpirvShader::EmitCompositeConstruct(InsnIterator insn, EmitState *state) const
2314{
Nicolas Capens71186752020-04-09 01:05:31 -04002315 auto &type = getType(insn.resultTypeId());
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002316 auto &dst = state->createIntermediate(insn.resultId(), type.componentCount);
Nicolas Capens157ba262019-12-10 17:49:14 -05002317 auto offset = 0u;
2318
Nicolas Capens81bc9d92019-12-16 15:05:57 -05002319 for(auto i = 0u; i < insn.wordCount() - 3; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002320 {
2321 Object::ID srcObjectId = insn.word(3u + i);
Ben Claytonbc1c067be2019-12-17 20:37:37 +00002322 auto &srcObject = getObject(srcObjectId);
Nicolas Capens72f089c2020-04-08 23:37:08 -04002323 auto &srcObjectTy = getType(srcObject);
Nicolas Capense6f65d92020-04-08 21:55:43 -04002324 Operand srcObjectAccess(this, state, srcObjectId);
Nicolas Capens157ba262019-12-10 17:49:14 -05002325
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002326 for(auto j = 0u; j < srcObjectTy.componentCount; j++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002327 {
2328 dst.move(offset++, srcObjectAccess.Float(j));
2329 }
2330 }
2331
2332 return EmitResult::Continue;
2333}
2334
2335SpirvShader::EmitResult SpirvShader::EmitCompositeInsert(InsnIterator insn, EmitState *state) const
2336{
2337 Type::ID resultTypeId = insn.word(1);
2338 auto &type = getType(resultTypeId);
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002339 auto &dst = state->createIntermediate(insn.resultId(), type.componentCount);
Nicolas Capens157ba262019-12-10 17:49:14 -05002340 auto &newPartObject = getObject(insn.word(3));
Nicolas Capens72f089c2020-04-08 23:37:08 -04002341 auto &newPartObjectTy = getType(newPartObject);
Nicolas Capens0b2a7682022-04-04 00:43:17 -04002342 auto firstNewComponent = WalkLiteralAccessChain(resultTypeId, Span(insn, 5, insn.wordCount() - 5));
Nicolas Capens157ba262019-12-10 17:49:14 -05002343
Nicolas Capense6f65d92020-04-08 21:55:43 -04002344 Operand srcObjectAccess(this, state, insn.word(4));
2345 Operand newPartObjectAccess(this, state, insn.word(3));
Nicolas Capens157ba262019-12-10 17:49:14 -05002346
2347 // old components before
Nicolas Capens81bc9d92019-12-16 15:05:57 -05002348 for(auto i = 0u; i < firstNewComponent; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002349 {
2350 dst.move(i, srcObjectAccess.Float(i));
2351 }
2352 // new part
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002353 for(auto i = 0u; i < newPartObjectTy.componentCount; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002354 {
2355 dst.move(firstNewComponent + i, newPartObjectAccess.Float(i));
2356 }
2357 // old components after
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002358 for(auto i = firstNewComponent + newPartObjectTy.componentCount; i < type.componentCount; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002359 {
2360 dst.move(i, srcObjectAccess.Float(i));
2361 }
2362
2363 return EmitResult::Continue;
2364}
2365
2366SpirvShader::EmitResult SpirvShader::EmitCompositeExtract(InsnIterator insn, EmitState *state) const
2367{
Nicolas Capens71186752020-04-09 01:05:31 -04002368 auto &type = getType(insn.resultTypeId());
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002369 auto &dst = state->createIntermediate(insn.resultId(), type.componentCount);
Nicolas Capens157ba262019-12-10 17:49:14 -05002370 auto &compositeObject = getObject(insn.word(3));
2371 Type::ID compositeTypeId = compositeObject.definition.word(1);
Nicolas Capens0b2a7682022-04-04 00:43:17 -04002372 auto firstComponent = WalkLiteralAccessChain(compositeTypeId, Span(insn, 4, insn.wordCount() - 4));
Nicolas Capens157ba262019-12-10 17:49:14 -05002373
Nicolas Capense6f65d92020-04-08 21:55:43 -04002374 Operand compositeObjectAccess(this, state, insn.word(3));
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002375 for(auto i = 0u; i < type.componentCount; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002376 {
2377 dst.move(i, compositeObjectAccess.Float(firstComponent + i));
2378 }
2379
2380 return EmitResult::Continue;
2381}
2382
2383SpirvShader::EmitResult SpirvShader::EmitVectorShuffle(InsnIterator insn, EmitState *state) const
2384{
Nicolas Capens71186752020-04-09 01:05:31 -04002385 auto &type = getType(insn.resultTypeId());
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002386 auto &dst = state->createIntermediate(insn.resultId(), type.componentCount);
Nicolas Capens157ba262019-12-10 17:49:14 -05002387
2388 // Note: number of components in result type, first half type, and second
2389 // half type are all independent.
Nicolas Capense7355b92021-11-08 22:48:34 -05002390 auto &firstHalfType = getObjectType(insn.word(3));
Nicolas Capens157ba262019-12-10 17:49:14 -05002391
Nicolas Capense6f65d92020-04-08 21:55:43 -04002392 Operand firstHalfAccess(this, state, insn.word(3));
2393 Operand secondHalfAccess(this, state, insn.word(4));
Nicolas Capens157ba262019-12-10 17:49:14 -05002394
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002395 for(auto i = 0u; i < type.componentCount; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002396 {
2397 auto selector = insn.word(5 + i);
Nicolas Capens81bc9d92019-12-16 15:05:57 -05002398 if(selector == static_cast<uint32_t>(-1))
Nicolas Capens157ba262019-12-10 17:49:14 -05002399 {
2400 // Undefined value. Until we decide to do real undef values, zero is as good
2401 // a value as any
2402 dst.move(i, RValue<SIMD::Float>(0.0f));
2403 }
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002404 else if(selector < firstHalfType.componentCount)
Nicolas Capens157ba262019-12-10 17:49:14 -05002405 {
2406 dst.move(i, firstHalfAccess.Float(selector));
2407 }
2408 else
2409 {
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002410 dst.move(i, secondHalfAccess.Float(selector - firstHalfType.componentCount));
Nicolas Capens157ba262019-12-10 17:49:14 -05002411 }
2412 }
2413
2414 return EmitResult::Continue;
2415}
2416
2417SpirvShader::EmitResult SpirvShader::EmitVectorExtractDynamic(InsnIterator insn, EmitState *state) const
2418{
Nicolas Capens71186752020-04-09 01:05:31 -04002419 auto &type = getType(insn.resultTypeId());
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002420 auto &dst = state->createIntermediate(insn.resultId(), type.componentCount);
Nicolas Capense7355b92021-11-08 22:48:34 -05002421 auto &srcType = getObjectType(insn.word(3));
Nicolas Capens157ba262019-12-10 17:49:14 -05002422
Nicolas Capense6f65d92020-04-08 21:55:43 -04002423 Operand src(this, state, insn.word(3));
2424 Operand index(this, state, insn.word(4));
Nicolas Capens157ba262019-12-10 17:49:14 -05002425
2426 SIMD::UInt v = SIMD::UInt(0);
2427
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002428 for(auto i = 0u; i < srcType.componentCount; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002429 {
2430 v |= CmpEQ(index.UInt(0), SIMD::UInt(i)) & src.UInt(i);
2431 }
2432
2433 dst.move(0, v);
2434 return EmitResult::Continue;
2435}
2436
2437SpirvShader::EmitResult SpirvShader::EmitVectorInsertDynamic(InsnIterator insn, EmitState *state) const
2438{
Nicolas Capens71186752020-04-09 01:05:31 -04002439 auto &type = getType(insn.resultTypeId());
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002440 auto &dst = state->createIntermediate(insn.resultId(), type.componentCount);
Nicolas Capens157ba262019-12-10 17:49:14 -05002441
Nicolas Capense6f65d92020-04-08 21:55:43 -04002442 Operand src(this, state, insn.word(3));
2443 Operand component(this, state, insn.word(4));
2444 Operand index(this, state, insn.word(5));
Nicolas Capens157ba262019-12-10 17:49:14 -05002445
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002446 for(auto i = 0u; i < type.componentCount; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002447 {
2448 SIMD::UInt mask = CmpEQ(SIMD::UInt(i), index.UInt(0));
2449 dst.move(i, (src.UInt(i) & ~mask) | (component.UInt(0) & mask));
2450 }
2451 return EmitResult::Continue;
2452}
2453
2454SpirvShader::EmitResult SpirvShader::EmitSelect(InsnIterator insn, EmitState *state) const
2455{
Nicolas Capens71186752020-04-09 01:05:31 -04002456 auto &type = getType(insn.resultTypeId());
Alexis Hetuf1a62bb2022-06-07 12:29:37 -04002457 auto result = getObject(insn.resultId());
Nicolas Capense6f65d92020-04-08 21:55:43 -04002458 auto cond = Operand(this, state, insn.word(3));
Nicolas Capens2f4b6032020-04-09 02:01:50 -04002459 auto condIsScalar = (cond.componentCount == 1);
Nicolas Capens157ba262019-12-10 17:49:14 -05002460
Alexis Hetuf1a62bb2022-06-07 12:29:37 -04002461 switch(result.kind)
Nicolas Capens157ba262019-12-10 17:49:14 -05002462 {
Alexis Hetuf1a62bb2022-06-07 12:29:37 -04002463 case Object::Kind::Pointer:
2464 {
2465 ASSERT(condIsScalar);
2466 ASSERT(type.storageClass == spv::StorageClassPhysicalStorageBuffer);
2467
2468 auto &lhs = state->getPointer(insn.word(4));
2469 auto &rhs = state->getPointer(insn.word(5));
2470 state->createPointer(insn.resultId(), SIMD::Pointer::IfThenElse(cond.Int(0), lhs, rhs));
Alexis Hetuec31f542022-06-22 16:47:48 -04002471
2472 SPIRV_SHADER_DBG("{0}: {1}", insn.word(3), cond);
2473 SPIRV_SHADER_DBG("{0}: {1}", insn.word(4), lhs);
2474 SPIRV_SHADER_DBG("{0}: {1}", insn.word(5), rhs);
Alexis Hetuf1a62bb2022-06-07 12:29:37 -04002475 }
2476 break;
2477 default:
2478 {
2479 auto lhs = Operand(this, state, insn.word(4));
2480 auto rhs = Operand(this, state, insn.word(5));
2481 auto &dst = state->createIntermediate(insn.resultId(), type.componentCount);
2482 for(auto i = 0u; i < type.componentCount; i++)
2483 {
2484 auto sel = cond.Int(condIsScalar ? 0 : i);
2485 dst.move(i, (sel & lhs.Int(i)) | (~sel & rhs.Int(i))); // TODO: IfThenElse()
2486 }
Alexis Hetuec31f542022-06-22 16:47:48 -04002487
2488 SPIRV_SHADER_DBG("{0}: {1}", insn.word(2), dst);
2489 SPIRV_SHADER_DBG("{0}: {1}", insn.word(3), cond);
2490 SPIRV_SHADER_DBG("{0}: {1}", insn.word(4), lhs);
2491 SPIRV_SHADER_DBG("{0}: {1}", insn.word(5), rhs);
Alexis Hetuf1a62bb2022-06-07 12:29:37 -04002492 }
2493 break;
Nicolas Capens157ba262019-12-10 17:49:14 -05002494 }
2495
2496 return EmitResult::Continue;
2497}
2498
2499SpirvShader::EmitResult SpirvShader::EmitAny(InsnIterator insn, EmitState *state) const
2500{
Nicolas Capens71186752020-04-09 01:05:31 -04002501 auto &type = getType(insn.resultTypeId());
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002502 ASSERT(type.componentCount == 1);
2503 auto &dst = state->createIntermediate(insn.resultId(), type.componentCount);
Nicolas Capense7355b92021-11-08 22:48:34 -05002504 auto &srcType = getObjectType(insn.word(3));
Nicolas Capense6f65d92020-04-08 21:55:43 -04002505 auto src = Operand(this, state, insn.word(3));
Nicolas Capens157ba262019-12-10 17:49:14 -05002506
2507 SIMD::UInt result = src.UInt(0);
2508
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002509 for(auto i = 1u; i < srcType.componentCount; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002510 {
2511 result |= src.UInt(i);
2512 }
2513
2514 dst.move(0, result);
2515 return EmitResult::Continue;
2516}
2517
2518SpirvShader::EmitResult SpirvShader::EmitAll(InsnIterator insn, EmitState *state) const
2519{
Nicolas Capens71186752020-04-09 01:05:31 -04002520 auto &type = getType(insn.resultTypeId());
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002521 ASSERT(type.componentCount == 1);
2522 auto &dst = state->createIntermediate(insn.resultId(), type.componentCount);
Nicolas Capense7355b92021-11-08 22:48:34 -05002523 auto &srcType = getObjectType(insn.word(3));
Nicolas Capense6f65d92020-04-08 21:55:43 -04002524 auto src = Operand(this, state, insn.word(3));
Nicolas Capens157ba262019-12-10 17:49:14 -05002525
2526 SIMD::UInt result = src.UInt(0);
2527
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002528 for(auto i = 1u; i < srcType.componentCount; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002529 {
2530 result &= src.UInt(i);
2531 }
2532
2533 dst.move(0, result);
2534 return EmitResult::Continue;
2535}
2536
2537SpirvShader::EmitResult SpirvShader::EmitAtomicOp(InsnIterator insn, EmitState *state) const
2538{
2539 auto &resultType = getType(Type::ID(insn.word(1)));
2540 Object::ID resultId = insn.word(2);
Nicolas Capens7c84c9e2020-07-24 22:13:44 -04002541 Object::ID pointerId = insn.word(3);
Nicolas Capens157ba262019-12-10 17:49:14 -05002542 Object::ID semanticsId = insn.word(5);
2543 auto memorySemantics = static_cast<spv::MemorySemanticsMask>(getObject(semanticsId).constantValue[0]);
2544 auto memoryOrder = MemoryOrder(memorySemantics);
2545 // Where no value is provided (increment/decrement) use an implicit value of 1.
Nicolas Capense6f65d92020-04-08 21:55:43 -04002546 auto value = (insn.wordCount() == 7) ? Operand(this, state, insn.word(6)).UInt(0) : RValue<SIMD::UInt>(1);
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002547 auto &dst = state->createIntermediate(resultId, resultType.componentCount);
Nicolas Capens7c84c9e2020-07-24 22:13:44 -04002548 auto ptr = state->getPointer(pointerId);
Nicolas Capens157ba262019-12-10 17:49:14 -05002549
Nicolas Capens7c84c9e2020-07-24 22:13:44 -04002550 SIMD::Int mask = state->activeLaneMask() & state->storesAndAtomicsMask();
2551
2552 if(getObject(pointerId).opcode() == spv::OpImageTexelPointer)
2553 {
2554 mask &= ptr.isInBounds(sizeof(int32_t), OutOfBoundsBehavior::Nullify);
2555 }
2556
2557 SIMD::UInt result(0);
Nicolas Capens81bc9d92019-12-16 15:05:57 -05002558 for(int j = 0; j < SIMD::Width; j++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002559 {
2560 If(Extract(mask, j) != 0)
2561 {
Nicolas Capens157ba262019-12-10 17:49:14 -05002562 auto laneValue = Extract(value, j);
2563 UInt v;
Nicolas Capens81bc9d92019-12-16 15:05:57 -05002564 switch(insn.opcode())
Nicolas Capens157ba262019-12-10 17:49:14 -05002565 {
Nicolas Capens112faf42019-12-13 17:32:26 -05002566 case spv::OpAtomicIAdd:
2567 case spv::OpAtomicIIncrement:
Sean Risseree0d0b42022-04-20 16:27:26 -04002568 v = AddAtomic(Pointer<UInt>(ptr.getPointerForLane(j)), laneValue, memoryOrder);
Nicolas Capens112faf42019-12-13 17:32:26 -05002569 break;
2570 case spv::OpAtomicISub:
2571 case spv::OpAtomicIDecrement:
Sean Risseree0d0b42022-04-20 16:27:26 -04002572 v = SubAtomic(Pointer<UInt>(ptr.getPointerForLane(j)), laneValue, memoryOrder);
Nicolas Capens112faf42019-12-13 17:32:26 -05002573 break;
2574 case spv::OpAtomicAnd:
Sean Risseree0d0b42022-04-20 16:27:26 -04002575 v = AndAtomic(Pointer<UInt>(ptr.getPointerForLane(j)), laneValue, memoryOrder);
Nicolas Capens112faf42019-12-13 17:32:26 -05002576 break;
2577 case spv::OpAtomicOr:
Sean Risseree0d0b42022-04-20 16:27:26 -04002578 v = OrAtomic(Pointer<UInt>(ptr.getPointerForLane(j)), laneValue, memoryOrder);
Nicolas Capens112faf42019-12-13 17:32:26 -05002579 break;
2580 case spv::OpAtomicXor:
Sean Risseree0d0b42022-04-20 16:27:26 -04002581 v = XorAtomic(Pointer<UInt>(ptr.getPointerForLane(j)), laneValue, memoryOrder);
Nicolas Capens112faf42019-12-13 17:32:26 -05002582 break;
2583 case spv::OpAtomicSMin:
Sean Risseree0d0b42022-04-20 16:27:26 -04002584 v = As<UInt>(MinAtomic(Pointer<Int>(ptr.getPointerForLane(j)), As<Int>(laneValue), memoryOrder));
Nicolas Capens112faf42019-12-13 17:32:26 -05002585 break;
2586 case spv::OpAtomicSMax:
Sean Risseree0d0b42022-04-20 16:27:26 -04002587 v = As<UInt>(MaxAtomic(Pointer<Int>(ptr.getPointerForLane(j)), As<Int>(laneValue), memoryOrder));
Nicolas Capens112faf42019-12-13 17:32:26 -05002588 break;
2589 case spv::OpAtomicUMin:
Sean Risseree0d0b42022-04-20 16:27:26 -04002590 v = MinAtomic(Pointer<UInt>(ptr.getPointerForLane(j)), laneValue, memoryOrder);
Nicolas Capens112faf42019-12-13 17:32:26 -05002591 break;
2592 case spv::OpAtomicUMax:
Sean Risseree0d0b42022-04-20 16:27:26 -04002593 v = MaxAtomic(Pointer<UInt>(ptr.getPointerForLane(j)), laneValue, memoryOrder);
Nicolas Capens112faf42019-12-13 17:32:26 -05002594 break;
2595 case spv::OpAtomicExchange:
Sean Risseree0d0b42022-04-20 16:27:26 -04002596 v = ExchangeAtomic(Pointer<UInt>(ptr.getPointerForLane(j)), laneValue, memoryOrder);
Nicolas Capens112faf42019-12-13 17:32:26 -05002597 break;
2598 default:
2599 UNREACHABLE("%s", OpcodeName(insn.opcode()));
2600 break;
Nicolas Capens157ba262019-12-10 17:49:14 -05002601 }
Nicolas Capens7c84c9e2020-07-24 22:13:44 -04002602 result = Insert(result, v, j);
Nicolas Capens157ba262019-12-10 17:49:14 -05002603 }
2604 }
2605
Nicolas Capens7c84c9e2020-07-24 22:13:44 -04002606 dst.move(0, result);
Nicolas Capens157ba262019-12-10 17:49:14 -05002607 return EmitResult::Continue;
2608}
2609
2610SpirvShader::EmitResult SpirvShader::EmitAtomicCompareExchange(InsnIterator insn, EmitState *state) const
2611{
2612 // Separate from EmitAtomicOp due to different instruction encoding
2613 auto &resultType = getType(Type::ID(insn.word(1)));
2614 Object::ID resultId = insn.word(2);
2615
2616 auto memorySemanticsEqual = static_cast<spv::MemorySemanticsMask>(getObject(insn.word(5)).constantValue[0]);
2617 auto memoryOrderEqual = MemoryOrder(memorySemanticsEqual);
2618 auto memorySemanticsUnequal = static_cast<spv::MemorySemanticsMask>(getObject(insn.word(6)).constantValue[0]);
2619 auto memoryOrderUnequal = MemoryOrder(memorySemanticsUnequal);
2620
Nicolas Capense6f65d92020-04-08 21:55:43 -04002621 auto value = Operand(this, state, insn.word(7));
2622 auto comparator = Operand(this, state, insn.word(8));
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002623 auto &dst = state->createIntermediate(resultId, resultType.componentCount);
Nicolas Capens157ba262019-12-10 17:49:14 -05002624 auto ptr = state->getPointer(insn.word(3));
Nicolas Capens157ba262019-12-10 17:49:14 -05002625
2626 SIMD::UInt x(0);
2627 auto mask = state->activeLaneMask() & state->storesAndAtomicsMask();
Nicolas Capens81bc9d92019-12-16 15:05:57 -05002628 for(int j = 0; j < SIMD::Width; j++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002629 {
2630 If(Extract(mask, j) != 0)
2631 {
Nicolas Capens157ba262019-12-10 17:49:14 -05002632 auto laneValue = Extract(value.UInt(0), j);
2633 auto laneComparator = Extract(comparator.UInt(0), j);
Sean Risseree0d0b42022-04-20 16:27:26 -04002634 UInt v = CompareExchangeAtomic(Pointer<UInt>(ptr.getPointerForLane(j)), laneValue, laneComparator, memoryOrderEqual, memoryOrderUnequal);
Nicolas Capens157ba262019-12-10 17:49:14 -05002635 x = Insert(x, v, j);
2636 }
2637 }
2638
2639 dst.move(0, x);
2640 return EmitResult::Continue;
2641}
2642
2643SpirvShader::EmitResult SpirvShader::EmitCopyObject(InsnIterator insn, EmitState *state) const
2644{
Nicolas Capense6f65d92020-04-08 21:55:43 -04002645 auto src = Operand(this, state, insn.word(3));
Alexis Hetu150bc8c2022-08-30 12:01:15 -04002646 if(src.isPointer())
Nicolas Capens157ba262019-12-10 17:49:14 -05002647 {
Alexis Hetu150bc8c2022-08-30 12:01:15 -04002648 state->createPointer(insn.resultId(), src.Pointer(0));
2649 }
2650 else
2651 {
2652 auto type = getType(insn.resultTypeId());
2653 auto &dst = state->createIntermediate(insn.resultId(), type.componentCount);
2654 for(uint32_t i = 0; i < type.componentCount; i++)
2655 {
2656 dst.move(i, src.Int(i));
2657 }
Nicolas Capens157ba262019-12-10 17:49:14 -05002658 }
2659 return EmitResult::Continue;
2660}
2661
2662SpirvShader::EmitResult SpirvShader::EmitArrayLength(InsnIterator insn, EmitState *state) const
2663{
Nicolas Capens157ba262019-12-10 17:49:14 -05002664 auto structPtrId = Object::ID(insn.word(3));
2665 auto arrayFieldIdx = insn.word(4);
2666
Nicolas Capens71186752020-04-09 01:05:31 -04002667 auto &resultType = getType(insn.resultTypeId());
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002668 ASSERT(resultType.componentCount == 1);
Nicolas Capens157ba262019-12-10 17:49:14 -05002669 ASSERT(resultType.definition.opcode() == spv::OpTypeInt);
2670
Nicolas Capense7355b92021-11-08 22:48:34 -05002671 auto &structPtrTy = getObjectType(structPtrId);
Nicolas Capens157ba262019-12-10 17:49:14 -05002672 auto &structTy = getType(structPtrTy.element);
Alexis Hetu74d3f372020-02-14 15:32:37 -05002673 auto arrayId = Type::ID(structTy.definition.word(2 + arrayFieldIdx));
Nicolas Capens157ba262019-12-10 17:49:14 -05002674
Nicolas Capens71186752020-04-09 01:05:31 -04002675 auto &result = state->createIntermediate(insn.resultId(), 1);
Sean Risserda08cb22022-04-08 20:49:06 -04002676 auto structBase = GetPointerToData(structPtrId, 0, false, state);
Nicolas Capens157ba262019-12-10 17:49:14 -05002677
Alexis Hetu74d3f372020-02-14 15:32:37 -05002678 Decorations structDecorations = {};
2679 ApplyDecorationsForIdMember(&structDecorations, structPtrTy.element, arrayFieldIdx);
2680 ASSERT(structDecorations.HasOffset);
Nicolas Capens157ba262019-12-10 17:49:14 -05002681
Alexis Hetu74d3f372020-02-14 15:32:37 -05002682 auto arrayBase = structBase + structDecorations.Offset;
Nicolas Capens157ba262019-12-10 17:49:14 -05002683 auto arraySizeInBytes = SIMD::Int(arrayBase.limit()) - arrayBase.offsets();
Alexis Hetu74d3f372020-02-14 15:32:37 -05002684
Nicolas Capensd6806b32022-03-02 10:16:31 -05002685 Decorations arrayDecorations = GetDecorationsForId(arrayId);
Alexis Hetu74d3f372020-02-14 15:32:37 -05002686 ASSERT(arrayDecorations.HasArrayStride);
2687 auto arrayLength = arraySizeInBytes / SIMD::Int(arrayDecorations.ArrayStride);
Nicolas Capens157ba262019-12-10 17:49:14 -05002688
2689 result.move(0, SIMD::Int(arrayLength));
2690
2691 return EmitResult::Continue;
2692}
2693
Ben Claytonb36dbbe2020-01-08 12:18:43 +00002694SpirvShader::EmitResult SpirvShader::EmitExtendedInstruction(InsnIterator insn, EmitState *state) const
2695{
2696 auto ext = getExtension(insn.word(3));
2697 switch(ext.name)
2698 {
Nicolas Capens112faf42019-12-13 17:32:26 -05002699 case Extension::GLSLstd450:
2700 return EmitExtGLSLstd450(insn, state);
2701 case Extension::OpenCLDebugInfo100:
2702 return EmitOpenCLDebugInfo100(insn, state);
sugoi1cd8e0282022-02-22 15:50:46 -05002703 case Extension::NonSemanticInfo:
2704 // An extended set name which is prefixed with "NonSemantic." is
2705 // guaranteed to contain only non-semantic instructions and all
2706 // OpExtInst instructions referencing this set can be ignored.
2707 break;
Nicolas Capens112faf42019-12-13 17:32:26 -05002708 default:
2709 UNREACHABLE("Unknown Extension::Name<%d>", int(ext.name));
Ben Claytonb36dbbe2020-01-08 12:18:43 +00002710 }
2711 return EmitResult::Continue;
2712}
2713
Nicolas Capens157ba262019-12-10 17:49:14 -05002714uint32_t SpirvShader::GetConstScalarInt(Object::ID id) const
2715{
2716 auto &scopeObj = getObject(id);
2717 ASSERT(scopeObj.kind == Object::Kind::Constant);
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002718 ASSERT(getType(scopeObj).componentCount == 1);
Nicolas Capens157ba262019-12-10 17:49:14 -05002719 return scopeObj.constantValue[0];
2720}
2721
2722void SpirvShader::emitEpilog(SpirvRoutine *routine) const
2723{
Nicolas Capens81bc9d92019-12-16 15:05:57 -05002724 for(auto insn : *this)
Nicolas Capens157ba262019-12-10 17:49:14 -05002725 {
Nicolas Capens81bc9d92019-12-16 15:05:57 -05002726 switch(insn.opcode())
Nicolas Capens157ba262019-12-10 17:49:14 -05002727 {
Nicolas Capens112faf42019-12-13 17:32:26 -05002728 case spv::OpVariable:
Nicolas Capens157ba262019-12-10 17:49:14 -05002729 {
Nicolas Capens71186752020-04-09 01:05:31 -04002730 auto &object = getObject(insn.resultId());
Nicolas Capens72f089c2020-04-08 23:37:08 -04002731 auto &objectTy = getType(object);
Ben Claytonbc1c067be2019-12-17 20:37:37 +00002732 if(object.kind == Object::Kind::InterfaceVariable && objectTy.storageClass == spv::StorageClassOutput)
2733 {
Nicolas Capens71186752020-04-09 01:05:31 -04002734 auto &dst = routine->getVariable(insn.resultId());
Ben Claytonbc1c067be2019-12-17 20:37:37 +00002735 int offset = 0;
Nicolas Capens71186752020-04-09 01:05:31 -04002736 VisitInterface(insn.resultId(),
Ben Claytonbc1c067be2019-12-17 20:37:37 +00002737 [&](Decorations const &d, AttribType type) {
2738 auto scalarSlot = d.Location << 2 | d.Component;
2739 routine->outputs[scalarSlot] = dst[offset++];
2740 });
2741 }
Nicolas Capens157ba262019-12-10 17:49:14 -05002742 }
Nicolas Capens112faf42019-12-13 17:32:26 -05002743 break;
2744 default:
2745 break;
Nicolas Capens157ba262019-12-10 17:49:14 -05002746 }
2747 }
Daniele Vettorelf908b182022-02-09 17:38:08 +00002748
2749 if(IsProfilingEnabled())
2750 {
2751 profiler->RegisterShaderForProfiling(std::to_string(insns.getIdentifier()) + "_" + std::to_string((uintptr_t)routine), std::move(routine->profData));
2752 }
Alexis Hetu09df3eb2021-01-14 10:46:33 -05002753}
Nicolas Capens157ba262019-12-10 17:49:14 -05002754
Alexis Hetu09df3eb2021-01-14 10:46:33 -05002755void SpirvShader::clearPhis(SpirvRoutine *routine) const
2756{
Nicolas Capens157ba262019-12-10 17:49:14 -05002757 // Clear phis that are no longer used. This serves two purposes:
2758 // (1) The phi rr::Variables are destructed, preventing pointless
2759 // materialization.
2760 // (2) Frees memory that will never be used again.
2761 routine->phis.clear();
2762}
2763
2764VkShaderStageFlagBits SpirvShader::executionModelToStage(spv::ExecutionModel model)
2765{
Nicolas Capens81bc9d92019-12-16 15:05:57 -05002766 switch(model)
Nicolas Capens157ba262019-12-10 17:49:14 -05002767 {
Nicolas Capens112faf42019-12-13 17:32:26 -05002768 case spv::ExecutionModelVertex: return VK_SHADER_STAGE_VERTEX_BIT;
2769 // case spv::ExecutionModelTessellationControl: return VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
2770 // case spv::ExecutionModelTessellationEvaluation: return VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
2771 // case spv::ExecutionModelGeometry: return VK_SHADER_STAGE_GEOMETRY_BIT;
2772 case spv::ExecutionModelFragment: return VK_SHADER_STAGE_FRAGMENT_BIT;
2773 case spv::ExecutionModelGLCompute: return VK_SHADER_STAGE_COMPUTE_BIT;
2774 // case spv::ExecutionModelKernel: return VkShaderStageFlagBits(0); // Not supported by vulkan.
2775 // case spv::ExecutionModelTaskNV: return VK_SHADER_STAGE_TASK_BIT_NV;
2776 // case spv::ExecutionModelMeshNV: return VK_SHADER_STAGE_MESH_BIT_NV;
2777 // case spv::ExecutionModelRayGenerationNV: return VK_SHADER_STAGE_RAYGEN_BIT_NV;
2778 // case spv::ExecutionModelIntersectionNV: return VK_SHADER_STAGE_INTERSECTION_BIT_NV;
2779 // case spv::ExecutionModelAnyHitNV: return VK_SHADER_STAGE_ANY_HIT_BIT_NV;
2780 // case spv::ExecutionModelClosestHitNV: return VK_SHADER_STAGE_CLOSEST_HIT_BIT_NV;
2781 // case spv::ExecutionModelMissNV: return VK_SHADER_STAGE_MISS_BIT_NV;
2782 // case spv::ExecutionModelCallableNV: return VK_SHADER_STAGE_CALLABLE_BIT_NV;
2783 default:
2784 UNSUPPORTED("ExecutionModel: %d", int(model));
2785 return VkShaderStageFlagBits(0);
Nicolas Capens157ba262019-12-10 17:49:14 -05002786 }
2787}
2788
Nicolas Capens2f4b6032020-04-09 02:01:50 -04002789SpirvShader::Operand::Operand(const SpirvShader *shader, const EmitState *state, SpirvShader::Object::ID objectId)
2790 : Operand(state, shader->getObject(objectId))
Ben Claytonbc1c067be2019-12-17 20:37:37 +00002791{}
Nicolas Capens157ba262019-12-10 17:49:14 -05002792
Nicolas Capens2f4b6032020-04-09 02:01:50 -04002793SpirvShader::Operand::Operand(const EmitState *state, const Object &object)
Nicolas Capens3c0e0582020-08-26 11:04:37 -04002794 : constant(object.kind == SpirvShader::Object::Kind::Constant ? object.constantValue.data() : nullptr)
Nicolas Capens2f4b6032020-04-09 02:01:50 -04002795 , intermediate(object.kind == SpirvShader::Object::Kind::Intermediate ? &state->getIntermediate(object.id()) : nullptr)
Sean Risser5cb6a632022-06-20 12:37:40 -04002796 , pointer(object.kind == SpirvShader::Object::Kind::Pointer ? &state->getPointer(object.id()) : nullptr)
Nicolas Capens2f4b6032020-04-09 02:01:50 -04002797 , componentCount(intermediate ? intermediate->componentCount : object.constantValue.size())
2798{
Alexis Hetudd26f342022-06-14 17:35:26 -04002799 ASSERT(intermediate || constant || pointer);
Nicolas Capens2f4b6032020-04-09 02:01:50 -04002800}
2801
Nicolas Capens20220a02020-04-09 02:48:16 -04002802SpirvShader::Operand::Operand(const Intermediate &value)
2803 : constant(nullptr)
2804 , intermediate(&value)
Alexis Hetudd26f342022-06-14 17:35:26 -04002805 , pointer(nullptr)
Nicolas Capens20220a02020-04-09 02:48:16 -04002806 , componentCount(value.componentCount)
2807{
2808}
2809
Nicolas Capens8dccb372021-11-11 14:24:34 -05002810bool SpirvShader::Object::isConstantZero() const
Nicolas Capens3c0e0582020-08-26 11:04:37 -04002811{
Nicolas Capens8dccb372021-11-11 14:24:34 -05002812 if(kind != Kind::Constant)
Nicolas Capens3c0e0582020-08-26 11:04:37 -04002813 {
2814 return false;
2815 }
2816
Nicolas Capens8dccb372021-11-11 14:24:34 -05002817 for(uint32_t i = 0; i < constantValue.size(); i++)
Nicolas Capens3c0e0582020-08-26 11:04:37 -04002818 {
Nicolas Capens8dccb372021-11-11 14:24:34 -05002819 if(constantValue[i] != 0)
Nicolas Capens3c0e0582020-08-26 11:04:37 -04002820 {
2821 return false;
2822 }
2823 }
2824
2825 return true;
2826}
2827
Ben Claytonbc1c067be2019-12-17 20:37:37 +00002828SpirvRoutine::SpirvRoutine(vk::PipelineLayout const *pipelineLayout)
2829 : pipelineLayout(pipelineLayout)
Nicolas Capens157ba262019-12-10 17:49:14 -05002830{
2831}
2832
2833void SpirvRoutine::setImmutableInputBuiltins(SpirvShader const *shader)
2834{
Ben Claytonbc1c067be2019-12-17 20:37:37 +00002835 setInputBuiltin(shader, spv::BuiltInSubgroupLocalInvocationId, [&](const SpirvShader::BuiltinMapping &builtin, Array<SIMD::Float> &value) {
Nicolas Capens157ba262019-12-10 17:49:14 -05002836 ASSERT(builtin.SizeInComponents == 1);
2837 value[builtin.FirstComponent] = As<SIMD::Float>(SIMD::Int(0, 1, 2, 3));
2838 });
2839
Ben Claytonbc1c067be2019-12-17 20:37:37 +00002840 setInputBuiltin(shader, spv::BuiltInSubgroupEqMask, [&](const SpirvShader::BuiltinMapping &builtin, Array<SIMD::Float> &value) {
Nicolas Capens157ba262019-12-10 17:49:14 -05002841 ASSERT(builtin.SizeInComponents == 4);
2842 value[builtin.FirstComponent + 0] = As<SIMD::Float>(SIMD::Int(1, 2, 4, 8));
2843 value[builtin.FirstComponent + 1] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2844 value[builtin.FirstComponent + 2] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2845 value[builtin.FirstComponent + 3] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2846 });
2847
Ben Claytonbc1c067be2019-12-17 20:37:37 +00002848 setInputBuiltin(shader, spv::BuiltInSubgroupGeMask, [&](const SpirvShader::BuiltinMapping &builtin, Array<SIMD::Float> &value) {
Nicolas Capens157ba262019-12-10 17:49:14 -05002849 ASSERT(builtin.SizeInComponents == 4);
2850 value[builtin.FirstComponent + 0] = As<SIMD::Float>(SIMD::Int(15, 14, 12, 8));
2851 value[builtin.FirstComponent + 1] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2852 value[builtin.FirstComponent + 2] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2853 value[builtin.FirstComponent + 3] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2854 });
2855
Ben Claytonbc1c067be2019-12-17 20:37:37 +00002856 setInputBuiltin(shader, spv::BuiltInSubgroupGtMask, [&](const SpirvShader::BuiltinMapping &builtin, Array<SIMD::Float> &value) {
Nicolas Capens157ba262019-12-10 17:49:14 -05002857 ASSERT(builtin.SizeInComponents == 4);
2858 value[builtin.FirstComponent + 0] = As<SIMD::Float>(SIMD::Int(14, 12, 8, 0));
2859 value[builtin.FirstComponent + 1] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2860 value[builtin.FirstComponent + 2] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2861 value[builtin.FirstComponent + 3] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2862 });
2863
Ben Claytonbc1c067be2019-12-17 20:37:37 +00002864 setInputBuiltin(shader, spv::BuiltInSubgroupLeMask, [&](const SpirvShader::BuiltinMapping &builtin, Array<SIMD::Float> &value) {
Nicolas Capens157ba262019-12-10 17:49:14 -05002865 ASSERT(builtin.SizeInComponents == 4);
2866 value[builtin.FirstComponent + 0] = As<SIMD::Float>(SIMD::Int(1, 3, 7, 15));
2867 value[builtin.FirstComponent + 1] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2868 value[builtin.FirstComponent + 2] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2869 value[builtin.FirstComponent + 3] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2870 });
2871
Ben Claytonbc1c067be2019-12-17 20:37:37 +00002872 setInputBuiltin(shader, spv::BuiltInSubgroupLtMask, [&](const SpirvShader::BuiltinMapping &builtin, Array<SIMD::Float> &value) {
Nicolas Capens157ba262019-12-10 17:49:14 -05002873 ASSERT(builtin.SizeInComponents == 4);
2874 value[builtin.FirstComponent + 0] = As<SIMD::Float>(SIMD::Int(0, 1, 3, 7));
2875 value[builtin.FirstComponent + 1] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2876 value[builtin.FirstComponent + 2] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2877 value[builtin.FirstComponent + 3] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2878 });
2879
Ben Claytonbc1c067be2019-12-17 20:37:37 +00002880 setInputBuiltin(shader, spv::BuiltInDeviceIndex, [&](const SpirvShader::BuiltinMapping &builtin, Array<SIMD::Float> &value) {
Nicolas Capens157ba262019-12-10 17:49:14 -05002881 ASSERT(builtin.SizeInComponents == 1);
2882 // Only a single physical device is supported.
2883 value[builtin.FirstComponent] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2884 });
2885}
2886
2887} // namespace sw