blob: ec808560dfa7221b4d232879ad84967a7ea3a138 [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
Nicolas Capens71134742022-10-12 12:44:16 -040030Spirv::Spirv(
Ben Claytonbc1c067be2019-12-17 20:37:37 +000031 VkShaderStageFlagBits pipelineStage,
32 const char *entryPointName,
Nicolas Capens6beafb42022-10-12 16:11:39 -040033 const SpirvBinary &insns)
Ben Claytonbc1c067be2019-12-17 20:37:37 +000034 : insns{ insns }
35 , inputs{ MAX_INTERFACE_COMPONENTS }
36 , outputs{ MAX_INTERFACE_COMPONENTS }
Chris Forbesaf4ed532018-12-06 18:33:27 -080037{
Nicolas Capens157ba262019-12-10 17:49:14 -050038 ASSERT(insns.size() > 0);
Ben Clayton9e4bc1b2019-04-16 16:52:02 -040039
Ben Clayton964b9e32021-06-25 09:00:22 +010040 // The identifiers of all OpVariables that define the entry point's IO variables.
41 std::unordered_set<Object::ID> interfaceIds;
Nicolas Capens157ba262019-12-10 17:49:14 -050042
43 Function::ID currentFunction;
44 Block::ID currentBlock;
45 InsnIterator blockStart;
46
Nicolas Capens81bc9d92019-12-16 15:05:57 -050047 for(auto insn : *this)
Ben Clayton0bb83b82019-02-26 11:41:07 +000048 {
Nicolas Capens157ba262019-12-10 17:49:14 -050049 spv::Op opcode = insn.opcode();
Nicolas Capens82eb22e2019-04-10 01:15:43 -040050
Nicolas Capens81bc9d92019-12-16 15:05:57 -050051 switch(opcode)
Ben Clayton9b156612019-03-13 19:48:31 +000052 {
Nicolas Capens112faf42019-12-13 17:32:26 -050053 case spv::OpEntryPoint:
Nicolas Capens157ba262019-12-10 17:49:14 -050054 {
Nicolas Capens5806db92021-09-27 07:07:27 +000055 spv::ExecutionModel executionModel = spv::ExecutionModel(insn.word(1));
56 Function::ID entryPoint = Function::ID(insn.word(2));
57 const char *name = insn.string(3);
58 VkShaderStageFlagBits stage = executionModelToStage(executionModel);
59
Ben Claytonbc1c067be2019-12-17 20:37:37 +000060 if(stage == pipelineStage && strcmp(name, entryPointName) == 0)
61 {
Nicolas Capens5806db92021-09-27 07:07:27 +000062 ASSERT_MSG(this->entryPoint == 0, "Duplicate entry point with name '%s' and stage %d", name, int(stage));
63 this->entryPoint = entryPoint;
64 this->executionModel = executionModel;
Ben Clayton964b9e32021-06-25 09:00:22 +010065
66 auto interfaceIdsOffset = 3 + insn.stringSizeInWords(3);
67 for(uint32_t i = interfaceIdsOffset; i < insn.wordCount(); i++)
68 {
69 interfaceIds.emplace(insn.word(i));
70 }
Ben Claytonbc1c067be2019-12-17 20:37:37 +000071 }
Nicolas Capens157ba262019-12-10 17:49:14 -050072 }
Nicolas Capens112faf42019-12-13 17:32:26 -050073 break;
Nicolas Capens157ba262019-12-10 17:49:14 -050074
Nicolas Capens112faf42019-12-13 17:32:26 -050075 case spv::OpExecutionMode:
Alexis Hetu09ed4582022-02-23 14:24:50 -050076 case spv::OpExecutionModeId:
Nicolas Capens112faf42019-12-13 17:32:26 -050077 ProcessExecutionMode(insn);
78 break;
Nicolas Capens157ba262019-12-10 17:49:14 -050079
Nicolas Capens112faf42019-12-13 17:32:26 -050080 case spv::OpDecorate:
Nicolas Capens157ba262019-12-10 17:49:14 -050081 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +000082 TypeOrObjectID targetId = insn.word(1);
83 auto decoration = static_cast<spv::Decoration>(insn.word(2));
84 uint32_t value = insn.wordCount() > 3 ? insn.word(3) : 0;
85
86 decorations[targetId].Apply(decoration, value);
87
88 switch(decoration)
89 {
Nicolas Capens112faf42019-12-13 17:32:26 -050090 case spv::DecorationDescriptorSet:
91 descriptorDecorations[targetId].DescriptorSet = value;
92 break;
93 case spv::DecorationBinding:
94 descriptorDecorations[targetId].Binding = value;
95 break;
96 case spv::DecorationInputAttachmentIndex:
97 descriptorDecorations[targetId].InputAttachmentIndex = value;
98 break;
99 case spv::DecorationSample:
Nicolas Capens15941842021-08-13 15:24:28 -0400100 analysis.ContainsSampleQualifier = true;
Nicolas Capens112faf42019-12-13 17:32:26 -0500101 break;
102 default:
103 // Only handling descriptor decorations here.
104 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000105 }
106
107 if(decoration == spv::DecorationCentroid)
Nicolas Capens112faf42019-12-13 17:32:26 -0500108 {
Nicolas Capens15941842021-08-13 15:24:28 -0400109 analysis.NeedsCentroid = true;
Nicolas Capens112faf42019-12-13 17:32:26 -0500110 }
Nicolas Capens157ba262019-12-10 17:49:14 -0500111 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500112 break;
Nicolas Capens157ba262019-12-10 17:49:14 -0500113
Nicolas Capens112faf42019-12-13 17:32:26 -0500114 case spv::OpMemberDecorate:
Nicolas Capens157ba262019-12-10 17:49:14 -0500115 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000116 Type::ID targetId = insn.word(1);
117 auto memberIndex = insn.word(2);
118 auto decoration = static_cast<spv::Decoration>(insn.word(3));
119 uint32_t value = insn.wordCount() > 4 ? insn.word(4) : 0;
120
121 auto &d = memberDecorations[targetId];
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500122 if(memberIndex >= d.size())
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000123 d.resize(memberIndex + 1); // on demand; exact size would require another pass...
124
125 d[memberIndex].Apply(decoration, value);
126
127 if(decoration == spv::DecorationCentroid)
Nicolas Capens112faf42019-12-13 17:32:26 -0500128 {
Nicolas Capens15941842021-08-13 15:24:28 -0400129 analysis.NeedsCentroid = true;
Nicolas Capens112faf42019-12-13 17:32:26 -0500130 }
Nicolas Capens157ba262019-12-10 17:49:14 -0500131 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500132 break;
Nicolas Capens157ba262019-12-10 17:49:14 -0500133
Nicolas Capens112faf42019-12-13 17:32:26 -0500134 case spv::OpDecorateId:
Sean Risser79a271a2020-12-02 16:56:03 -0500135 {
136 auto decoration = static_cast<spv::Decoration>(insn.word(2));
137
138 // Currently OpDecorateId only supports UniformId, which provides information for
139 // potential optimizations that we don't perform, and CounterBuffer, which is used
140 // by HLSL to build the graphics pipeline with shader reflection. At the driver level,
141 // the CounterBuffer decoration does nothing, so we can safely ignore both decorations.
142 ASSERT(decoration == spv::DecorationUniformId || decoration == spv::DecorationCounterBuffer);
Sean Risser79a271a2020-12-02 16:56:03 -0500143 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500144 break;
Sean Risser79a271a2020-12-02 16:56:03 -0500145
Nicolas Capens112faf42019-12-13 17:32:26 -0500146 case spv::OpDecorateString:
Nicolas Capens4fd9ef92022-01-14 16:11:27 -0500147 {
148 auto decoration = static_cast<spv::Decoration>(insn.word(2));
149
150 // We assume these are for HLSL semantics, ignore them (b/214576937).
Nicolas Capens9b1a72a2022-01-14 16:34:01 -0500151 ASSERT(decoration == spv::DecorationUserSemantic || decoration == spv::DecorationUserTypeGOOGLE);
Nicolas Capens4fd9ef92022-01-14 16:11:27 -0500152 }
153 break;
154
Nicolas Capens112faf42019-12-13 17:32:26 -0500155 case spv::OpMemberDecorateString:
Nicolas Capens4fd9ef92022-01-14 16:11:27 -0500156 {
157 auto decoration = static_cast<spv::Decoration>(insn.word(3));
158
159 // We assume these are for HLSL semantics, ignore them (b/214576937).
Nicolas Capens9b1a72a2022-01-14 16:34:01 -0500160 ASSERT(decoration == spv::DecorationUserSemantic || decoration == spv::DecorationUserTypeGOOGLE);
Nicolas Capens4fd9ef92022-01-14 16:11:27 -0500161 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500162 break;
Sean Risser79a271a2020-12-02 16:56:03 -0500163
Nicolas Capens112faf42019-12-13 17:32:26 -0500164 case spv::OpDecorationGroup:
165 // Nothing to do here. We don't need to record the definition of the group; we'll just have
166 // the bundle of decorations float around. If we were to ever walk the decorations directly,
167 // we might think about introducing this as a real Object.
168 break;
Nicolas Capens157ba262019-12-10 17:49:14 -0500169
Nicolas Capens112faf42019-12-13 17:32:26 -0500170 case spv::OpGroupDecorate:
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000171 {
172 uint32_t group = insn.word(1);
Shahbaz Youssefi4dbbcd02022-09-13 22:23:30 -0400173 const auto &groupDecorations = decorations[group];
174 const auto &descriptorGroupDecorations = descriptorDecorations[group];
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000175 for(auto i = 2u; i < insn.wordCount(); i++)
176 {
177 // Remaining operands are targets to apply the group to.
178 uint32_t target = insn.word(i);
179 decorations[target].Apply(groupDecorations);
180 descriptorDecorations[target].Apply(descriptorGroupDecorations);
181 }
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000182 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500183 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000184
Nicolas Capens112faf42019-12-13 17:32:26 -0500185 case spv::OpGroupMemberDecorate:
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000186 {
Shahbaz Youssefi4dbbcd02022-09-13 22:23:30 -0400187 const auto &srcDecorations = decorations[insn.word(1)];
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000188 for(auto i = 2u; i < insn.wordCount(); i += 2)
189 {
190 // remaining operands are pairs of <id>, literal for members to apply to.
191 auto &d = memberDecorations[insn.word(i)];
192 auto memberIndex = insn.word(i + 1);
193 if(memberIndex >= d.size())
194 d.resize(memberIndex + 1); // on demand resize, see above...
195 d[memberIndex].Apply(srcDecorations);
196 }
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000197 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500198 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000199
Nicolas Capens112faf42019-12-13 17:32:26 -0500200 case spv::OpLabel:
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000201 {
Nicolas Capensff9bb522021-11-08 21:29:29 -0500202 ASSERT(currentBlock == 0);
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000203 currentBlock = Block::ID(insn.word(1));
204 blockStart = insn;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000205 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500206 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000207
Alexis Hetubbe92e92022-03-23 13:32:00 -0400208 // Termination instructions:
209 case spv::OpKill:
210 case spv::OpTerminateInvocation:
Nicolas Capens23ccff72022-04-05 13:00:22 -0400211 analysis.ContainsDiscard = true;
Alexis Hetubbe92e92022-03-23 13:32:00 -0400212 // [[fallthrough]]
213
214 case spv::OpUnreachable:
215
Nicolas Capens112faf42019-12-13 17:32:26 -0500216 // Branch Instructions (subset of Termination Instructions):
217 case spv::OpBranch:
218 case spv::OpBranchConditional:
219 case spv::OpSwitch:
220 case spv::OpReturn:
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000221 {
Nicolas Capensff9bb522021-11-08 21:29:29 -0500222 ASSERT(currentBlock != 0);
223 ASSERT(currentFunction != 0);
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000224
225 auto blockEnd = insn;
226 blockEnd++;
227 functions[currentFunction].blocks[currentBlock] = Block(blockStart, blockEnd);
228 currentBlock = Block::ID(0);
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000229 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500230 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000231
Alexis Hetu4d2f9f12022-02-22 17:16:13 -0500232 case spv::OpDemoteToHelperInvocation:
Nicolas Capens23ccff72022-04-05 13:00:22 -0400233 analysis.ContainsDiscard = true;
Alexis Hetu4d2f9f12022-02-22 17:16:13 -0500234 break;
235
Nicolas Capens112faf42019-12-13 17:32:26 -0500236 case spv::OpLoopMerge:
237 case spv::OpSelectionMerge:
238 break; // Nothing to do in analysis pass.
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000239
Nicolas Capens112faf42019-12-13 17:32:26 -0500240 case spv::OpTypeVoid:
241 case spv::OpTypeBool:
242 case spv::OpTypeInt:
243 case spv::OpTypeFloat:
244 case spv::OpTypeVector:
245 case spv::OpTypeMatrix:
246 case spv::OpTypeImage:
247 case spv::OpTypeSampler:
248 case spv::OpTypeSampledImage:
249 case spv::OpTypeArray:
250 case spv::OpTypeRuntimeArray:
251 case spv::OpTypeStruct:
252 case spv::OpTypePointer:
Alexis Hetuc582db22022-06-14 16:46:56 -0400253 case spv::OpTypeForwardPointer:
Nicolas Capens112faf42019-12-13 17:32:26 -0500254 case spv::OpTypeFunction:
255 DeclareType(insn);
256 break;
Nicolas Capens157ba262019-12-10 17:49:14 -0500257
Nicolas Capens112faf42019-12-13 17:32:26 -0500258 case spv::OpVariable:
Nicolas Capens157ba262019-12-10 17:49:14 -0500259 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000260 Type::ID typeId = insn.word(1);
261 Object::ID resultId = insn.word(2);
262 auto storageClass = static_cast<spv::StorageClass>(insn.word(3));
263
264 auto &object = defs[resultId];
Nicolas Capens157ba262019-12-10 17:49:14 -0500265 object.kind = Object::Kind::Pointer;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000266 object.definition = insn;
Nicolas Capens157ba262019-12-10 17:49:14 -0500267
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000268 ASSERT(getType(typeId).definition.opcode() == spv::OpTypePointer);
269 ASSERT(getType(typeId).storageClass == storageClass);
Nicolas Capens157ba262019-12-10 17:49:14 -0500270
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000271 switch(storageClass)
Nicolas Capens157ba262019-12-10 17:49:14 -0500272 {
Nicolas Capens112faf42019-12-13 17:32:26 -0500273 case spv::StorageClassInput:
274 case spv::StorageClassOutput:
Ben Clayton964b9e32021-06-25 09:00:22 +0100275 if(interfaceIds.count(resultId))
276 {
277 ProcessInterfaceVariable(object);
278 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500279 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000280
Nicolas Capens112faf42019-12-13 17:32:26 -0500281 case spv::StorageClassUniform:
282 case spv::StorageClassStorageBuffer:
Alexis Hetu71ec98e2022-06-14 16:58:44 -0400283 case spv::StorageClassPhysicalStorageBuffer:
Nicolas Capens112faf42019-12-13 17:32:26 -0500284 object.kind = Object::Kind::DescriptorSet;
285 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000286
Nicolas Capens112faf42019-12-13 17:32:26 -0500287 case spv::StorageClassPushConstant:
288 case spv::StorageClassPrivate:
289 case spv::StorageClassFunction:
290 case spv::StorageClassUniformConstant:
291 break; // Correctly handled.
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000292
Nicolas Capens112faf42019-12-13 17:32:26 -0500293 case spv::StorageClassWorkgroup:
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000294 {
295 auto &elTy = getType(getType(typeId).element);
Nicolas Capensff9f9b52020-04-14 00:46:38 -0400296 auto sizeInBytes = elTy.componentCount * static_cast<uint32_t>(sizeof(float));
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000297 workgroupMemory.allocate(resultId, sizeInBytes);
298 object.kind = Object::Kind::Pointer;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000299 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500300 break;
301 case spv::StorageClassAtomicCounter:
302 case spv::StorageClassImage:
303 UNSUPPORTED("StorageClass %d not yet supported", (int)storageClass);
304 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000305
Nicolas Capens112faf42019-12-13 17:32:26 -0500306 case spv::StorageClassCrossWorkgroup:
307 UNSUPPORTED("SPIR-V OpenCL Execution Model (StorageClassCrossWorkgroup)");
308 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000309
Nicolas Capens112faf42019-12-13 17:32:26 -0500310 case spv::StorageClassGeneric:
311 UNSUPPORTED("SPIR-V GenericPointer Capability (StorageClassGeneric)");
312 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000313
Nicolas Capens112faf42019-12-13 17:32:26 -0500314 default:
315 UNREACHABLE("Unexpected StorageClass %d", storageClass); // See Appendix A of the Vulkan spec.
316 break;
Nicolas Capens157ba262019-12-10 17:49:14 -0500317 }
318 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500319 break;
Nicolas Capens157ba262019-12-10 17:49:14 -0500320
Nicolas Capens112faf42019-12-13 17:32:26 -0500321 case spv::OpConstant:
322 case spv::OpSpecConstant:
323 CreateConstant(insn).constantValue[0] = insn.word(3);
324 break;
325 case spv::OpConstantFalse:
326 case spv::OpSpecConstantFalse:
327 CreateConstant(insn).constantValue[0] = 0; // Represent Boolean false as zero.
328 break;
329 case spv::OpConstantTrue:
330 case spv::OpSpecConstantTrue:
331 CreateConstant(insn).constantValue[0] = ~0u; // Represent Boolean true as all bits set.
332 break;
333 case spv::OpConstantNull:
334 case spv::OpUndef:
Nicolas Capens157ba262019-12-10 17:49:14 -0500335 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000336 // TODO: consider a real LLVM-level undef. For now, zero is a perfectly good value.
337 // OpConstantNull forms a constant of arbitrary type, all zeros.
338 auto &object = CreateConstant(insn);
Nicolas Capens72f089c2020-04-08 23:37:08 -0400339 auto &objectTy = getType(object);
Nicolas Capensff9f9b52020-04-14 00:46:38 -0400340 for(auto i = 0u; i < objectTy.componentCount; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -0500341 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000342 object.constantValue[i] = 0;
Nicolas Capens157ba262019-12-10 17:49:14 -0500343 }
344 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500345 break;
346 case spv::OpConstantComposite:
347 case spv::OpSpecConstantComposite:
Nicolas Capens157ba262019-12-10 17:49:14 -0500348 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000349 auto &object = CreateConstant(insn);
350 auto offset = 0u;
351 for(auto i = 0u; i < insn.wordCount() - 3; i++)
352 {
353 auto &constituent = getObject(insn.word(i + 3));
Nicolas Capens72f089c2020-04-08 23:37:08 -0400354 auto &constituentTy = getType(constituent);
Nicolas Capensff9f9b52020-04-14 00:46:38 -0400355 for(auto j = 0u; j < constituentTy.componentCount; j++)
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000356 {
357 object.constantValue[offset++] = constituent.constantValue[j];
358 }
359 }
360
361 auto objectId = Object::ID(insn.word(2));
362 auto decorationsIt = decorations.find(objectId);
363 if(decorationsIt != decorations.end() &&
364 decorationsIt->second.BuiltIn == spv::BuiltInWorkgroupSize)
365 {
366 // https://www.khronos.org/registry/vulkan/specs/1.1/html/vkspec.html#interfaces-builtin-variables :
367 // Decorating an object with the WorkgroupSize built-in
368 // decoration will make that object contain the dimensions
369 // of a local workgroup. If an object is decorated with the
370 // WorkgroupSize decoration, this must take precedence over
371 // any execution mode set for LocalSize.
372 // The object decorated with WorkgroupSize must be declared
373 // as a three-component vector of 32-bit integers.
Nicolas Capensff9f9b52020-04-14 00:46:38 -0400374 ASSERT(getType(object).componentCount == 3);
Nicolas Capens15941842021-08-13 15:24:28 -0400375 executionModes.WorkgroupSizeX = object.constantValue[0];
376 executionModes.WorkgroupSizeY = object.constantValue[1];
377 executionModes.WorkgroupSizeZ = object.constantValue[2];
Alexis Hetu09ed4582022-02-23 14:24:50 -0500378 executionModes.useWorkgroupSizeId = false;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000379 }
Nicolas Capens157ba262019-12-10 17:49:14 -0500380 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500381 break;
382 case spv::OpSpecConstantOp:
383 EvalSpecConstantOp(insn);
384 break;
Ben Clayton9b156612019-03-13 19:48:31 +0000385
Nicolas Capens112faf42019-12-13 17:32:26 -0500386 case spv::OpCapability:
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000387 {
388 auto capability = static_cast<spv::Capability>(insn.word(1));
389 switch(capability)
390 {
Nicolas Capens112faf42019-12-13 17:32:26 -0500391 case spv::CapabilityMatrix: capabilities.Matrix = true; break;
392 case spv::CapabilityShader: capabilities.Shader = true; break;
393 case spv::CapabilityStorageImageMultisample: capabilities.StorageImageMultisample = true; break;
394 case spv::CapabilityClipDistance: capabilities.ClipDistance = true; break;
395 case spv::CapabilityCullDistance: capabilities.CullDistance = true; break;
396 case spv::CapabilityImageCubeArray: capabilities.ImageCubeArray = true; break;
397 case spv::CapabilitySampleRateShading: capabilities.SampleRateShading = true; break;
398 case spv::CapabilityInputAttachment: capabilities.InputAttachment = true; break;
399 case spv::CapabilitySampled1D: capabilities.Sampled1D = true; break;
400 case spv::CapabilityImage1D: capabilities.Image1D = true; break;
401 case spv::CapabilitySampledBuffer: capabilities.SampledBuffer = true; break;
402 case spv::CapabilitySampledCubeArray: capabilities.SampledCubeArray = true; break;
403 case spv::CapabilityImageBuffer: capabilities.ImageBuffer = true; break;
404 case spv::CapabilityImageMSArray: capabilities.ImageMSArray = true; break;
405 case spv::CapabilityStorageImageExtendedFormats: capabilities.StorageImageExtendedFormats = true; break;
406 case spv::CapabilityImageQuery: capabilities.ImageQuery = true; break;
407 case spv::CapabilityDerivativeControl: capabilities.DerivativeControl = true; break;
sugoi1e3d910c2022-02-22 15:07:21 -0500408 case spv::CapabilityDotProductInputAll: capabilities.DotProductInputAll = true; break;
409 case spv::CapabilityDotProductInput4x8Bit: capabilities.DotProductInput4x8Bit = true; break;
410 case spv::CapabilityDotProductInput4x8BitPacked: capabilities.DotProductInput4x8BitPacked = true; break;
411 case spv::CapabilityDotProduct: capabilities.DotProduct = true; break;
Nicolas Capens112faf42019-12-13 17:32:26 -0500412 case spv::CapabilityInterpolationFunction: capabilities.InterpolationFunction = true; break;
Nicolas Capensf0e8ec22021-11-12 13:57:14 -0500413 case spv::CapabilityStorageImageWriteWithoutFormat: capabilities.StorageImageWriteWithoutFormat = true; break;
Nicolas Capens112faf42019-12-13 17:32:26 -0500414 case spv::CapabilityGroupNonUniform: capabilities.GroupNonUniform = true; break;
415 case spv::CapabilityGroupNonUniformVote: capabilities.GroupNonUniformVote = true; break;
416 case spv::CapabilityGroupNonUniformArithmetic: capabilities.GroupNonUniformArithmetic = true; break;
417 case spv::CapabilityGroupNonUniformBallot: capabilities.GroupNonUniformBallot = true; break;
418 case spv::CapabilityGroupNonUniformShuffle: capabilities.GroupNonUniformShuffle = true; break;
419 case spv::CapabilityGroupNonUniformShuffleRelative: capabilities.GroupNonUniformShuffleRelative = true; break;
Sean Risser1144d582022-06-23 13:53:11 -0400420 case spv::CapabilityGroupNonUniformQuad: capabilities.GroupNonUniformQuad = true; break;
Nicolas Capens112faf42019-12-13 17:32:26 -0500421 case spv::CapabilityDeviceGroup: capabilities.DeviceGroup = true; break;
422 case spv::CapabilityMultiView: capabilities.MultiView = true; break;
Sean Risserb6ddcf32022-07-06 15:30:41 -0400423 case spv::CapabilitySignedZeroInfNanPreserve: capabilities.SignedZeroInfNanPreserve = true; break;
Alexis Hetu4d2f9f12022-02-22 17:16:13 -0500424 case spv::CapabilityDemoteToHelperInvocation: capabilities.DemoteToHelperInvocation = true; break;
Nicolas Capens112faf42019-12-13 17:32:26 -0500425 case spv::CapabilityStencilExportEXT: capabilities.StencilExportEXT = true; break;
Nicolas Capens4c629802021-12-08 02:05:19 -0500426 case spv::CapabilityVulkanMemoryModel: capabilities.VulkanMemoryModel = true; break;
427 case spv::CapabilityVulkanMemoryModelDeviceScope: capabilities.VulkanMemoryModelDeviceScope = true; break;
Sean Risserda08cb22022-04-08 20:49:06 -0400428 case spv::CapabilityShaderNonUniform: capabilities.ShaderNonUniform = true; break;
429 case spv::CapabilityRuntimeDescriptorArray: capabilities.RuntimeDescriptorArray = true; break;
430 case spv::CapabilityStorageBufferArrayNonUniformIndexing: capabilities.StorageBufferArrayNonUniformIndexing = true; break;
Sean Rissera4c2e9b2022-05-03 14:47:41 -0400431 case spv::CapabilityStorageTexelBufferArrayNonUniformIndexing: capabilities.StorageTexelBufferArrayNonUniformIndexing = true; break;
Sean Rissere726b1e2022-07-13 15:26:50 -0400432 case spv::CapabilityUniformTexelBufferArrayNonUniformIndexing: capabilities.UniformTexelBufferArrayNonUniformIndexing = true; break;
433 case spv::CapabilityUniformTexelBufferArrayDynamicIndexing: capabilities.UniformTexelBufferArrayDynamicIndexing = true; break;
Sean Risser5cb6a632022-06-20 12:37:40 -0400434 case spv::CapabilityStorageTexelBufferArrayDynamicIndexing: capabilities.StorageTexelBufferArrayDynamicIndexing = true; break;
Sean Risser54bae6e2022-07-13 16:03:17 -0400435 case spv::CapabilityUniformBufferArrayNonUniformIndexing: capabilities.UniformBufferArrayNonUniformIndex = true; break;
Alexis Hetuda7b9bd2022-08-30 12:01:15 -0400436 case spv::CapabilitySampledImageArrayNonUniformIndexing: capabilities.SampledImageArrayNonUniformIndexing = true; break;
Alexis Hetu5f5e5132022-09-30 15:00:34 -0400437 case spv::CapabilityStorageImageArrayNonUniformIndexing: capabilities.StorageImageArrayNonUniformIndexing = true; break;
Alexis Hetuf8335442022-03-09 13:53:37 -0500438 case spv::CapabilityPhysicalStorageBufferAddresses: capabilities.PhysicalStorageBufferAddresses = true; break;
Nicolas Capens112faf42019-12-13 17:32:26 -0500439 default:
440 UNSUPPORTED("Unsupported capability %u", insn.word(1));
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000441 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500442
443 // Various capabilities will be declared, but none affect our code generation at this point.
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000444 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500445 break;
Ben Clayton9b156612019-03-13 19:48:31 +0000446
Nicolas Capens112faf42019-12-13 17:32:26 -0500447 case spv::OpMemoryModel:
Nicolas Capens4c629802021-12-08 02:05:19 -0500448 {
449 addressingModel = static_cast<spv::AddressingModel>(insn.word(1));
450 memoryModel = static_cast<spv::MemoryModel>(insn.word(2));
451 }
452 break;
Nicolas Capens157ba262019-12-10 17:49:14 -0500453
Nicolas Capens112faf42019-12-13 17:32:26 -0500454 case spv::OpFunction:
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000455 {
456 auto functionId = Function::ID(insn.word(2));
457 ASSERT_MSG(currentFunction == 0, "Functions %d and %d overlap", currentFunction.value(), functionId.value());
458 currentFunction = functionId;
459 auto &function = functions[functionId];
460 function.result = Type::ID(insn.word(1));
461 function.type = Type::ID(insn.word(4));
462 // Scan forward to find the function's label.
Ben Clayton7d098242020-03-13 13:07:12 +0000463 for(auto it = insn; it != end(); it++)
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000464 {
Ben Clayton7d098242020-03-13 13:07:12 +0000465 if(it.opcode() == spv::OpLabel)
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000466 {
Ben Clayton7d098242020-03-13 13:07:12 +0000467 function.entry = Block::ID(it.word(1));
468 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000469 }
470 }
471 ASSERT_MSG(function.entry != 0, "Function<%d> has no label", currentFunction.value());
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000472 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500473 break;
Nicolas Capens157ba262019-12-10 17:49:14 -0500474
Nicolas Capens112faf42019-12-13 17:32:26 -0500475 case spv::OpFunctionEnd:
476 currentFunction = 0;
477 break;
Nicolas Capens157ba262019-12-10 17:49:14 -0500478
Nicolas Capens112faf42019-12-13 17:32:26 -0500479 case spv::OpExtInstImport:
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000480 {
Ben Clayton683bad82020-02-10 23:57:09 +0000481 static constexpr std::pair<const char *, Extension::Name> extensionsByName[] = {
Ben Claytonf6a6a412020-01-09 16:43:37 +0000482 { "GLSL.std.450", Extension::GLSLstd450 },
sugoi1cd8e0282022-02-22 15:50:46 -0500483 { "NonSemantic.", Extension::NonSemanticInfo },
Ben Claytonf6a6a412020-01-09 16:43:37 +0000484 };
Ben Clayton683bad82020-02-10 23:57:09 +0000485 static constexpr auto extensionCount = sizeof(extensionsByName) / sizeof(extensionsByName[0]);
486
Ben Claytonb36dbbe2020-01-08 12:18:43 +0000487 auto id = Extension::ID(insn.word(1));
488 auto name = insn.string(2);
489 auto ext = Extension{ Extension::Unknown };
Ben Clayton683bad82020-02-10 23:57:09 +0000490 for(size_t i = 0; i < extensionCount; i++)
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000491 {
sugoi1cd8e0282022-02-22 15:50:46 -0500492 if(0 == strncmp(name, extensionsByName[i].first, strlen(extensionsByName[i].first)))
Ben Claytonb36dbbe2020-01-08 12:18:43 +0000493 {
Ben Clayton683bad82020-02-10 23:57:09 +0000494 ext = Extension{ extensionsByName[i].second };
Ben Claytonb36dbbe2020-01-08 12:18:43 +0000495 break;
496 }
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000497 }
Ben Claytonb36dbbe2020-01-08 12:18:43 +0000498 if(ext.name == Extension::Unknown)
499 {
500 UNSUPPORTED("SPIR-V Extension: %s", name);
501 break;
502 }
Ben Clayton8842c8f2020-01-13 16:57:48 +0000503 extensionsByID.emplace(id, ext);
504 extensionsImported.emplace(ext.name);
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000505 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500506 break;
507 case spv::OpName:
508 case spv::OpMemberName:
509 case spv::OpSource:
510 case spv::OpSourceContinued:
511 case spv::OpSourceExtension:
512 case spv::OpLine:
513 case spv::OpNoLine:
514 case spv::OpModuleProcessed:
515 // No semantic impact
516 break;
Ben Clayton9b156612019-03-13 19:48:31 +0000517
Nicolas Capens112faf42019-12-13 17:32:26 -0500518 case spv::OpString:
519 strings.emplace(insn.word(1), insn.string(2));
520 break;
Ben Clayton9c8823a2020-01-08 12:07:30 +0000521
Nicolas Capens112faf42019-12-13 17:32:26 -0500522 case spv::OpFunctionParameter:
523 // These should have all been removed by preprocessing passes. If we see them here,
524 // our assumptions are wrong and we will probably generate wrong code.
525 UNREACHABLE("%s should have already been lowered.", OpcodeName(opcode));
526 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000527
Nicolas Capens112faf42019-12-13 17:32:26 -0500528 case spv::OpFunctionCall:
529 // TODO(b/141246700): Add full support for spv::OpFunctionCall
530 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000531
Nicolas Capens112faf42019-12-13 17:32:26 -0500532 case spv::OpFConvert:
533 UNSUPPORTED("SPIR-V Float16 or Float64 Capability (OpFConvert)");
534 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000535
Nicolas Capens112faf42019-12-13 17:32:26 -0500536 case spv::OpSConvert:
537 UNSUPPORTED("SPIR-V Int16 or Int64 Capability (OpSConvert)");
538 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000539
Nicolas Capens112faf42019-12-13 17:32:26 -0500540 case spv::OpUConvert:
541 UNSUPPORTED("SPIR-V Int16 or Int64 Capability (OpUConvert)");
542 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000543
Nicolas Capens112faf42019-12-13 17:32:26 -0500544 case spv::OpLoad:
545 case spv::OpAccessChain:
546 case spv::OpInBoundsAccessChain:
Alexis Hetu47c22462022-06-06 18:00:16 -0400547 case spv::OpPtrAccessChain:
Nicolas Capens112faf42019-12-13 17:32:26 -0500548 case spv::OpSampledImage:
549 case spv::OpImage:
Alexis Hetu150bc8c2022-08-30 12:01:15 -0400550 case spv::OpCopyObject:
551 case spv::OpCopyLogical:
Nicolas Capens157ba262019-12-10 17:49:14 -0500552 {
553 // Propagate the descriptor decorations to the result.
554 Object::ID resultId = insn.word(2);
555 Object::ID pointerId = insn.word(3);
556 const auto &d = descriptorDecorations.find(pointerId);
557
558 if(d != descriptorDecorations.end())
559 {
560 descriptorDecorations[resultId] = d->second;
561 }
562
563 DefineResult(insn);
564
Alexis Hetu47c22462022-06-06 18:00:16 -0400565 if(opcode == spv::OpAccessChain || opcode == spv::OpInBoundsAccessChain || opcode == spv::OpPtrAccessChain)
Nicolas Capens157ba262019-12-10 17:49:14 -0500566 {
Alexis Hetu71ec98e2022-06-14 16:58:44 -0400567 int indexId = (insn.opcode() == spv::OpPtrAccessChain) ? 5 : 4;
Nicolas Capens157ba262019-12-10 17:49:14 -0500568 Decorations dd{};
Alexis Hetu71ec98e2022-06-14 16:58:44 -0400569 ApplyDecorationsForAccessChain(&dd, &descriptorDecorations[resultId], pointerId, Span(insn, indexId, insn.wordCount() - indexId));
Nicolas Capens157ba262019-12-10 17:49:14 -0500570 // Note: offset is the one thing that does *not* propagate, as the access chain accounts for it.
571 dd.HasOffset = false;
572 decorations[resultId].Apply(dd);
573 }
574 }
575 break;
Ben Clayton9b156612019-03-13 19:48:31 +0000576
Nicolas Capens112faf42019-12-13 17:32:26 -0500577 case spv::OpCompositeConstruct:
578 case spv::OpCompositeInsert:
579 case spv::OpCompositeExtract:
580 case spv::OpVectorShuffle:
581 case spv::OpVectorTimesScalar:
582 case spv::OpMatrixTimesScalar:
583 case spv::OpMatrixTimesVector:
584 case spv::OpVectorTimesMatrix:
585 case spv::OpMatrixTimesMatrix:
586 case spv::OpOuterProduct:
587 case spv::OpTranspose:
588 case spv::OpVectorExtractDynamic:
589 case spv::OpVectorInsertDynamic:
590 // Unary ops
591 case spv::OpNot:
592 case spv::OpBitFieldInsert:
593 case spv::OpBitFieldSExtract:
594 case spv::OpBitFieldUExtract:
595 case spv::OpBitReverse:
596 case spv::OpBitCount:
597 case spv::OpSNegate:
598 case spv::OpFNegate:
599 case spv::OpLogicalNot:
600 case spv::OpQuantizeToF16:
601 // Binary ops
602 case spv::OpIAdd:
603 case spv::OpISub:
604 case spv::OpIMul:
605 case spv::OpSDiv:
606 case spv::OpUDiv:
607 case spv::OpFAdd:
608 case spv::OpFSub:
609 case spv::OpFMul:
610 case spv::OpFDiv:
611 case spv::OpFMod:
612 case spv::OpFRem:
613 case spv::OpFOrdEqual:
614 case spv::OpFUnordEqual:
615 case spv::OpFOrdNotEqual:
616 case spv::OpFUnordNotEqual:
617 case spv::OpFOrdLessThan:
618 case spv::OpFUnordLessThan:
619 case spv::OpFOrdGreaterThan:
620 case spv::OpFUnordGreaterThan:
621 case spv::OpFOrdLessThanEqual:
622 case spv::OpFUnordLessThanEqual:
623 case spv::OpFOrdGreaterThanEqual:
624 case spv::OpFUnordGreaterThanEqual:
625 case spv::OpSMod:
626 case spv::OpSRem:
627 case spv::OpUMod:
628 case spv::OpIEqual:
629 case spv::OpINotEqual:
630 case spv::OpUGreaterThan:
631 case spv::OpSGreaterThan:
632 case spv::OpUGreaterThanEqual:
633 case spv::OpSGreaterThanEqual:
634 case spv::OpULessThan:
635 case spv::OpSLessThan:
636 case spv::OpULessThanEqual:
637 case spv::OpSLessThanEqual:
638 case spv::OpShiftRightLogical:
639 case spv::OpShiftRightArithmetic:
640 case spv::OpShiftLeftLogical:
641 case spv::OpBitwiseOr:
642 case spv::OpBitwiseXor:
643 case spv::OpBitwiseAnd:
644 case spv::OpLogicalOr:
645 case spv::OpLogicalAnd:
646 case spv::OpLogicalEqual:
647 case spv::OpLogicalNotEqual:
648 case spv::OpUMulExtended:
649 case spv::OpSMulExtended:
650 case spv::OpIAddCarry:
651 case spv::OpISubBorrow:
652 case spv::OpDot:
sugoi1e3d910c2022-02-22 15:07:21 -0500653 case spv::OpSDot:
654 case spv::OpUDot:
655 case spv::OpSUDot:
656 case spv::OpSDotAccSat:
657 case spv::OpUDotAccSat:
658 case spv::OpSUDotAccSat:
Nicolas Capens112faf42019-12-13 17:32:26 -0500659 case spv::OpConvertFToU:
660 case spv::OpConvertFToS:
661 case spv::OpConvertSToF:
662 case spv::OpConvertUToF:
663 case spv::OpBitcast:
664 case spv::OpSelect:
665 case spv::OpIsInf:
666 case spv::OpIsNan:
667 case spv::OpAny:
668 case spv::OpAll:
669 case spv::OpDPdx:
670 case spv::OpDPdxCoarse:
671 case spv::OpDPdy:
672 case spv::OpDPdyCoarse:
673 case spv::OpFwidth:
674 case spv::OpFwidthCoarse:
675 case spv::OpDPdxFine:
676 case spv::OpDPdyFine:
677 case spv::OpFwidthFine:
678 case spv::OpAtomicLoad:
679 case spv::OpAtomicIAdd:
680 case spv::OpAtomicISub:
681 case spv::OpAtomicSMin:
682 case spv::OpAtomicSMax:
683 case spv::OpAtomicUMin:
684 case spv::OpAtomicUMax:
685 case spv::OpAtomicAnd:
686 case spv::OpAtomicOr:
687 case spv::OpAtomicXor:
688 case spv::OpAtomicIIncrement:
689 case spv::OpAtomicIDecrement:
690 case spv::OpAtomicExchange:
691 case spv::OpAtomicCompareExchange:
692 case spv::OpPhi:
693 case spv::OpImageSampleImplicitLod:
694 case spv::OpImageSampleExplicitLod:
695 case spv::OpImageSampleDrefImplicitLod:
696 case spv::OpImageSampleDrefExplicitLod:
697 case spv::OpImageSampleProjImplicitLod:
698 case spv::OpImageSampleProjExplicitLod:
699 case spv::OpImageSampleProjDrefImplicitLod:
700 case spv::OpImageSampleProjDrefExplicitLod:
701 case spv::OpImageGather:
702 case spv::OpImageDrefGather:
703 case spv::OpImageFetch:
704 case spv::OpImageQuerySizeLod:
705 case spv::OpImageQuerySize:
706 case spv::OpImageQueryLod:
707 case spv::OpImageQueryLevels:
708 case spv::OpImageQuerySamples:
709 case spv::OpImageRead:
710 case spv::OpImageTexelPointer:
711 case spv::OpGroupNonUniformElect:
712 case spv::OpGroupNonUniformAll:
713 case spv::OpGroupNonUniformAny:
714 case spv::OpGroupNonUniformAllEqual:
715 case spv::OpGroupNonUniformBroadcast:
716 case spv::OpGroupNonUniformBroadcastFirst:
Sean Risser1144d582022-06-23 13:53:11 -0400717 case spv::OpGroupNonUniformQuadBroadcast:
718 case spv::OpGroupNonUniformQuadSwap:
Nicolas Capens112faf42019-12-13 17:32:26 -0500719 case spv::OpGroupNonUniformBallot:
720 case spv::OpGroupNonUniformInverseBallot:
721 case spv::OpGroupNonUniformBallotBitExtract:
722 case spv::OpGroupNonUniformBallotBitCount:
723 case spv::OpGroupNonUniformBallotFindLSB:
724 case spv::OpGroupNonUniformBallotFindMSB:
725 case spv::OpGroupNonUniformShuffle:
726 case spv::OpGroupNonUniformShuffleXor:
727 case spv::OpGroupNonUniformShuffleUp:
728 case spv::OpGroupNonUniformShuffleDown:
729 case spv::OpGroupNonUniformIAdd:
730 case spv::OpGroupNonUniformFAdd:
731 case spv::OpGroupNonUniformIMul:
732 case spv::OpGroupNonUniformFMul:
733 case spv::OpGroupNonUniformSMin:
734 case spv::OpGroupNonUniformUMin:
735 case spv::OpGroupNonUniformFMin:
736 case spv::OpGroupNonUniformSMax:
737 case spv::OpGroupNonUniformUMax:
738 case spv::OpGroupNonUniformFMax:
739 case spv::OpGroupNonUniformBitwiseAnd:
740 case spv::OpGroupNonUniformBitwiseOr:
741 case spv::OpGroupNonUniformBitwiseXor:
742 case spv::OpGroupNonUniformLogicalAnd:
743 case spv::OpGroupNonUniformLogicalOr:
744 case spv::OpGroupNonUniformLogicalXor:
Nicolas Capens112faf42019-12-13 17:32:26 -0500745 case spv::OpArrayLength:
Alexis Hetu4d2f9f12022-02-22 17:16:13 -0500746 case spv::OpIsHelperInvocationEXT:
Nicolas Capens112faf42019-12-13 17:32:26 -0500747 // Instructions that yield an intermediate value or divergent pointer
748 DefineResult(insn);
749 break;
750
751 case spv::OpExtInst:
752 switch(getExtension(insn.word(3)).name)
753 {
754 case Extension::GLSLstd450:
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000755 DefineResult(insn);
756 break;
sugoi1cd8e0282022-02-22 15:50:46 -0500757 case Extension::NonSemanticInfo:
758 // An extended set name which is prefixed with "NonSemantic." is
759 // guaranteed to contain only non-semantic instructions and all
760 // OpExtInst instructions referencing this set can be ignored.
761 break;
Nicolas Capens112faf42019-12-13 17:32:26 -0500762 default:
763 UNREACHABLE("Unexpected Extension name %d", int(getExtension(insn.word(3)).name));
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000764 break;
Nicolas Capens112faf42019-12-13 17:32:26 -0500765 }
766 break;
Nicolas Capens157ba262019-12-10 17:49:14 -0500767
Nicolas Capens112faf42019-12-13 17:32:26 -0500768 case spv::OpStore:
769 case spv::OpAtomicStore:
Nicolas Capens112faf42019-12-13 17:32:26 -0500770 case spv::OpCopyMemory:
771 case spv::OpMemoryBarrier:
772 // Don't need to do anything during analysis pass
773 break;
Nicolas Capens157ba262019-12-10 17:49:14 -0500774
Nicolas Capens6de4a962022-10-11 15:33:15 -0400775 case spv::OpImageWrite:
776 analysis.ContainsImageWrite = true;
777 break;
778
Nicolas Capens112faf42019-12-13 17:32:26 -0500779 case spv::OpControlBarrier:
Nicolas Capens15941842021-08-13 15:24:28 -0400780 analysis.ContainsControlBarriers = true;
Nicolas Capens112faf42019-12-13 17:32:26 -0500781 break;
782
783 case spv::OpExtension:
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000784 {
Nicolas Capens4c629802021-12-08 02:05:19 -0500785 const char *ext = insn.string(1);
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000786 // Part of core SPIR-V 1.3. Vulkan 1.1 implementations must also accept the pre-1.3
787 // extension per Appendix A, `Vulkan Environment for SPIR-V`.
788 if(!strcmp(ext, "SPV_KHR_storage_buffer_storage_class")) break;
789 if(!strcmp(ext, "SPV_KHR_shader_draw_parameters")) break;
790 if(!strcmp(ext, "SPV_KHR_16bit_storage")) break;
791 if(!strcmp(ext, "SPV_KHR_variable_pointers")) break;
792 if(!strcmp(ext, "SPV_KHR_device_group")) break;
793 if(!strcmp(ext, "SPV_KHR_multiview")) break;
Alexis Hetu4d2f9f12022-02-22 17:16:13 -0500794 if(!strcmp(ext, "SPV_EXT_demote_to_helper_invocation")) break;
Alexis Hetubbe92e92022-03-23 13:32:00 -0400795 if(!strcmp(ext, "SPV_KHR_terminate_invocation")) break;
Alexis Hetu1ee36c92020-02-20 14:07:26 -0500796 if(!strcmp(ext, "SPV_EXT_shader_stencil_export")) break;
Sean Risser0063eca2020-10-26 17:08:42 -0400797 if(!strcmp(ext, "SPV_KHR_float_controls")) break;
sugoi1e3d910c2022-02-22 15:07:21 -0500798 if(!strcmp(ext, "SPV_KHR_integer_dot_product")) break;
sugoi1cd8e0282022-02-22 15:50:46 -0500799 if(!strcmp(ext, "SPV_KHR_non_semantic_info")) break;
Alexis Hetuf8335442022-03-09 13:53:37 -0500800 if(!strcmp(ext, "SPV_KHR_physical_storage_buffer")) break;
Nicolas Capens4c629802021-12-08 02:05:19 -0500801 if(!strcmp(ext, "SPV_KHR_vulkan_memory_model")) break;
Nicolas Capens4fd9ef92022-01-14 16:11:27 -0500802 if(!strcmp(ext, "SPV_GOOGLE_decorate_string")) break;
Nicolas Capens534f10f2022-01-14 16:21:06 -0500803 if(!strcmp(ext, "SPV_GOOGLE_hlsl_functionality1")) break;
Nicolas Capens9b1a72a2022-01-14 16:34:01 -0500804 if(!strcmp(ext, "SPV_GOOGLE_user_type")) break;
Sean Risserda08cb22022-04-08 20:49:06 -0400805 if(!strcmp(ext, "SPV_EXT_descriptor_indexing")) break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000806 UNSUPPORTED("SPIR-V Extension: %s", ext);
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000807 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500808 break;
Ben Claytonc0cf68b2019-03-21 17:46:08 +0000809
Nicolas Capens112faf42019-12-13 17:32:26 -0500810 default:
811 UNSUPPORTED("%s", OpcodeName(opcode));
Nicolas Capens157ba262019-12-10 17:49:14 -0500812 }
Chris Forbesd5aed492019-02-02 15:18:52 -0800813 }
Chris Forbesc61271e2019-02-19 17:01:28 -0800814
Nicolas Capens157ba262019-12-10 17:49:14 -0500815 ASSERT_MSG(entryPoint != 0, "Entry point '%s' not found", entryPointName);
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500816 for(auto &it : functions)
Nicolas Capensfabdec52019-03-21 17:04:05 -0400817 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500818 it.second.AssignBlockFields();
Nicolas Capensfabdec52019-03-21 17:04:05 -0400819 }
Ben Claytonb0ca2a82020-01-08 13:00:57 +0000820
Ben Clayton0d6791c2020-04-22 21:55:27 +0100821#ifdef SPIRV_SHADER_CFG_GRAPHVIZ_DOT_FILEPATH
822 {
823 char path[1024];
824 snprintf(path, sizeof(path), SPIRV_SHADER_CFG_GRAPHVIZ_DOT_FILEPATH, codeSerialID);
825 WriteCFGGraphVizDotFile(path);
826 }
827#endif
Ben Claytonb0ca2a82020-01-08 13:00:57 +0000828}
829
Nicolas Capens71134742022-10-12 12:44:16 -0400830Spirv::~Spirv()
Ben Claytonb0ca2a82020-01-08 13:00:57 +0000831{
Nicolas Capens157ba262019-12-10 17:49:14 -0500832}
Nicolas Capensfabdec52019-03-21 17:04:05 -0400833
Nicolas Capens71134742022-10-12 12:44:16 -0400834void Spirv::DeclareType(InsnIterator insn)
Nicolas Capens157ba262019-12-10 17:49:14 -0500835{
836 Type::ID resultId = insn.word(1);
837
838 auto &type = types[resultId];
839 type.definition = insn;
Nicolas Capensff9f9b52020-04-14 00:46:38 -0400840 type.componentCount = ComputeTypeSize(insn);
Nicolas Capens157ba262019-12-10 17:49:14 -0500841
842 // A structure is a builtin block if it has a builtin
843 // member. All members of such a structure are builtins.
Alexis Hetuc582db22022-06-14 16:46:56 -0400844 spv::Op opcode = insn.opcode();
845 switch(opcode)
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000846 {
Nicolas Capens112faf42019-12-13 17:32:26 -0500847 case spv::OpTypeStruct:
Nicolas Capens157ba262019-12-10 17:49:14 -0500848 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000849 auto d = memberDecorations.find(resultId);
850 if(d != memberDecorations.end())
Nicolas Capens157ba262019-12-10 17:49:14 -0500851 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000852 for(auto &m : d->second)
Nicolas Capens157ba262019-12-10 17:49:14 -0500853 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000854 if(m.HasBuiltIn)
855 {
856 type.isBuiltInBlock = true;
857 break;
858 }
Nicolas Capens157ba262019-12-10 17:49:14 -0500859 }
860 }
861 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500862 break;
863 case spv::OpTypePointer:
Alexis Hetuc582db22022-06-14 16:46:56 -0400864 case spv::OpTypeForwardPointer:
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000865 {
Alexis Hetuc582db22022-06-14 16:46:56 -0400866 Type::ID elementTypeId = insn.word((opcode == spv::OpTypeForwardPointer) ? 1 : 3);
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000867 type.element = elementTypeId;
868 type.isBuiltInBlock = getType(elementTypeId).isBuiltInBlock;
869 type.storageClass = static_cast<spv::StorageClass>(insn.word(2));
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000870 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500871 break;
872 case spv::OpTypeVector:
873 case spv::OpTypeMatrix:
874 case spv::OpTypeArray:
875 case spv::OpTypeRuntimeArray:
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000876 {
877 Type::ID elementTypeId = insn.word(2);
878 type.element = elementTypeId;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000879 }
Nicolas Capens112faf42019-12-13 17:32:26 -0500880 break;
881 default:
882 break;
Nicolas Capens157ba262019-12-10 17:49:14 -0500883 }
884}
885
Nicolas Capens71134742022-10-12 12:44:16 -0400886Spirv::Object &Spirv::CreateConstant(InsnIterator insn)
Nicolas Capens157ba262019-12-10 17:49:14 -0500887{
888 Type::ID typeId = insn.word(1);
889 Object::ID resultId = insn.word(2);
890 auto &object = defs[resultId];
891 auto &objectTy = getType(typeId);
Nicolas Capens157ba262019-12-10 17:49:14 -0500892 object.kind = Object::Kind::Constant;
893 object.definition = insn;
Nicolas Capens2f4b6032020-04-09 02:01:50 -0400894 object.constantValue.resize(objectTy.componentCount);
Nicolas Capens72f089c2020-04-08 23:37:08 -0400895
Nicolas Capens157ba262019-12-10 17:49:14 -0500896 return object;
897}
898
Nicolas Capens71134742022-10-12 12:44:16 -0400899void Spirv::ProcessInterfaceVariable(Object &object)
Nicolas Capens157ba262019-12-10 17:49:14 -0500900{
Nicolas Capens72f089c2020-04-08 23:37:08 -0400901 auto &objectTy = getType(object);
Nicolas Capens157ba262019-12-10 17:49:14 -0500902 ASSERT(objectTy.storageClass == spv::StorageClassInput || objectTy.storageClass == spv::StorageClassOutput);
903
904 ASSERT(objectTy.opcode() == spv::OpTypePointer);
905 auto pointeeTy = getType(objectTy.element);
906
907 auto &builtinInterface = (objectTy.storageClass == spv::StorageClassInput) ? inputBuiltins : outputBuiltins;
908 auto &userDefinedInterface = (objectTy.storageClass == spv::StorageClassInput) ? inputs : outputs;
909
910 ASSERT(object.opcode() == spv::OpVariable);
911 Object::ID resultId = object.definition.word(2);
912
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500913 if(objectTy.isBuiltInBlock)
Nicolas Capens157ba262019-12-10 17:49:14 -0500914 {
Nicolas Capens71186752020-04-09 01:05:31 -0400915 // Walk the builtin block, registering each of its members separately.
Nicolas Capens157ba262019-12-10 17:49:14 -0500916 auto m = memberDecorations.find(objectTy.element);
Nicolas Capens71186752020-04-09 01:05:31 -0400917 ASSERT(m != memberDecorations.end()); // Otherwise we wouldn't have marked the type chain
Nicolas Capens157ba262019-12-10 17:49:14 -0500918 auto &structType = pointeeTy.definition;
Nicolas Capens71186752020-04-09 01:05:31 -0400919 auto memberIndex = 0u;
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000920 auto offset = 0u;
Nicolas Capens71186752020-04-09 01:05:31 -0400921
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500922 for(auto &member : m->second)
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000923 {
Nicolas Capens71186752020-04-09 01:05:31 -0400924 auto &memberType = getType(structType.word(2 + memberIndex));
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000925
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500926 if(member.HasBuiltIn)
Ben Clayton9b62c5e2019-03-08 09:32:34 +0000927 {
Nicolas Capensff9f9b52020-04-14 00:46:38 -0400928 builtinInterface[member.BuiltIn] = { resultId, offset, memberType.componentCount };
Ben Clayton9b62c5e2019-03-08 09:32:34 +0000929 }
Ben Claytonc0cf68b2019-03-21 17:46:08 +0000930
Nicolas Capensff9f9b52020-04-14 00:46:38 -0400931 offset += memberType.componentCount;
Nicolas Capens71186752020-04-09 01:05:31 -0400932 ++memberIndex;
Nicolas Capens157ba262019-12-10 17:49:14 -0500933 }
Nicolas Capens71186752020-04-09 01:05:31 -0400934
Nicolas Capens157ba262019-12-10 17:49:14 -0500935 return;
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000936 }
937
Nicolas Capens157ba262019-12-10 17:49:14 -0500938 auto d = decorations.find(resultId);
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500939 if(d != decorations.end() && d->second.HasBuiltIn)
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000940 {
Nicolas Capensff9f9b52020-04-14 00:46:38 -0400941 builtinInterface[d->second.BuiltIn] = { resultId, 0, pointeeTy.componentCount };
Nicolas Capens157ba262019-12-10 17:49:14 -0500942 }
943 else
944 {
945 object.kind = Object::Kind::InterfaceVariable;
946 VisitInterface(resultId,
Nicolas Capens7e1d67a2022-10-04 10:36:33 -0400947 [&userDefinedInterface](const Decorations &d, AttribType type) {
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000948 // 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 -0500949 int32_t scalarSlot = (d.Location << 2) | d.Component;
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000950 ASSERT(scalarSlot >= 0 &&
951 scalarSlot < static_cast<int32_t>(userDefinedInterface.size()));
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000952
Ben Claytonbc1c067be2019-12-17 20:37:37 +0000953 auto &slot = userDefinedInterface[scalarSlot];
954 slot.Type = type;
955 slot.Flat = d.Flat;
956 slot.NoPerspective = d.NoPerspective;
957 slot.Centroid = d.Centroid;
958 });
Nicolas Capens157ba262019-12-10 17:49:14 -0500959 }
960}
Ben Claytondfc0f3b2019-02-26 12:19:48 +0000961
Nicolas Capens71134742022-10-12 12:44:16 -0400962uint32_t Spirv::GetNumInputComponents(int32_t location) const
Alexis Hetu945f1442021-01-14 11:39:56 -0500963{
964 ASSERT(location >= 0);
965
966 // Verify how many component(s) per input
967 // 1 to 4, for float, vec2, vec3, vec4.
968 // Note that matrices are divided over multiple inputs
969 uint32_t num_components_per_input = 0;
970 for(; num_components_per_input < 4; ++num_components_per_input)
971 {
972 if(inputs[(location << 2) | num_components_per_input].Type == ATTRIBTYPE_UNUSED)
973 {
974 break;
975 }
976 }
977
978 return num_components_per_input;
979}
980
Nicolas Capens71134742022-10-12 12:44:16 -0400981uint32_t Spirv::GetPackedInterpolant(int32_t location) const
Alexis Hetu73a69402021-11-08 16:03:51 -0500982{
983 ASSERT(location >= 0);
984 const uint32_t maxInterpolant = (location << 2);
985
986 // Return the number of used components only at location
987 uint32_t packedInterpolant = 0;
988 for(uint32_t i = 0; i < maxInterpolant; ++i)
989 {
Nicolas Capens8dccb372021-11-11 14:24:34 -0500990 if(inputs[i].Type != ATTRIBTYPE_UNUSED)
Alexis Hetu73a69402021-11-08 16:03:51 -0500991 {
992 ++packedInterpolant;
993 }
994 }
995
996 return packedInterpolant;
997}
998
Nicolas Capens71134742022-10-12 12:44:16 -0400999void Spirv::ProcessExecutionMode(InsnIterator insn)
Nicolas Capens157ba262019-12-10 17:49:14 -05001000{
Nicolas Capens57eb48a2020-05-15 17:07:07 -04001001 Function::ID function = insn.word(1);
1002 if(function != entryPoint)
1003 {
1004 return;
1005 }
1006
Nicolas Capens157ba262019-12-10 17:49:14 -05001007 auto mode = static_cast<spv::ExecutionMode>(insn.word(2));
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001008 switch(mode)
Nicolas Capens157ba262019-12-10 17:49:14 -05001009 {
Nicolas Capens112faf42019-12-13 17:32:26 -05001010 case spv::ExecutionModeEarlyFragmentTests:
Nicolas Capens15941842021-08-13 15:24:28 -04001011 executionModes.EarlyFragmentTests = true;
Nicolas Capens112faf42019-12-13 17:32:26 -05001012 break;
1013 case spv::ExecutionModeDepthReplacing:
Nicolas Capens15941842021-08-13 15:24:28 -04001014 executionModes.DepthReplacing = true;
Nicolas Capens112faf42019-12-13 17:32:26 -05001015 break;
1016 case spv::ExecutionModeDepthGreater:
1017 // TODO(b/177915067): Can be used to optimize depth test, currently unused.
Nicolas Capens15941842021-08-13 15:24:28 -04001018 executionModes.DepthGreater = true;
Nicolas Capens112faf42019-12-13 17:32:26 -05001019 break;
1020 case spv::ExecutionModeDepthLess:
1021 // TODO(b/177915067): Can be used to optimize depth test, currently unused.
Nicolas Capens15941842021-08-13 15:24:28 -04001022 executionModes.DepthLess = true;
Nicolas Capens112faf42019-12-13 17:32:26 -05001023 break;
1024 case spv::ExecutionModeDepthUnchanged:
1025 // TODO(b/177915067): Can be used to optimize depth test, currently unused.
Nicolas Capens15941842021-08-13 15:24:28 -04001026 executionModes.DepthUnchanged = true;
Nicolas Capens112faf42019-12-13 17:32:26 -05001027 break;
Alexis Hetuf99e45c2022-09-01 10:46:13 -04001028 case spv::ExecutionModeStencilRefReplacingEXT:
1029 executionModes.StencilRefReplacing = true;
1030 break;
Nicolas Capens112faf42019-12-13 17:32:26 -05001031 case spv::ExecutionModeLocalSize:
Alexis Hetu09ed4582022-02-23 14:24:50 -05001032 case spv::ExecutionModeLocalSizeId:
Nicolas Capens15941842021-08-13 15:24:28 -04001033 executionModes.WorkgroupSizeX = insn.word(3);
1034 executionModes.WorkgroupSizeY = insn.word(4);
1035 executionModes.WorkgroupSizeZ = insn.word(5);
Alexis Hetu09ed4582022-02-23 14:24:50 -05001036 executionModes.useWorkgroupSizeId = (mode == spv::ExecutionModeLocalSizeId);
Nicolas Capens112faf42019-12-13 17:32:26 -05001037 break;
1038 case spv::ExecutionModeOriginUpperLeft:
1039 // This is always the case for a Vulkan shader. Do nothing.
1040 break;
Sean Risserb6ddcf32022-07-06 15:30:41 -04001041 case spv::ExecutionModeSignedZeroInfNanPreserve:
1042 // We currently don't perform any aggressive fast-math optimizations.
1043 break;
Nicolas Capens112faf42019-12-13 17:32:26 -05001044 default:
1045 UNREACHABLE("Execution mode: %d", int(mode));
Nicolas Capens157ba262019-12-10 17:49:14 -05001046 }
1047}
Ben Claytonc0cf68b2019-03-21 17:46:08 +00001048
Nicolas Capens71134742022-10-12 12:44:16 -04001049uint32_t Spirv::getWorkgroupSizeX() const
Alexis Hetu09ed4582022-02-23 14:24:50 -05001050{
1051 return executionModes.useWorkgroupSizeId ? getObject(executionModes.WorkgroupSizeX).constantValue[0] : executionModes.WorkgroupSizeX.value();
1052}
1053
Nicolas Capens71134742022-10-12 12:44:16 -04001054uint32_t Spirv::getWorkgroupSizeY() const
Alexis Hetu09ed4582022-02-23 14:24:50 -05001055{
1056 return executionModes.useWorkgroupSizeId ? getObject(executionModes.WorkgroupSizeY).constantValue[0] : executionModes.WorkgroupSizeY.value();
1057}
1058
Nicolas Capens71134742022-10-12 12:44:16 -04001059uint32_t Spirv::getWorkgroupSizeZ() const
Alexis Hetu09ed4582022-02-23 14:24:50 -05001060{
1061 return executionModes.useWorkgroupSizeId ? getObject(executionModes.WorkgroupSizeZ).constantValue[0] : executionModes.WorkgroupSizeZ.value();
1062}
1063
Nicolas Capens71134742022-10-12 12:44:16 -04001064uint32_t Spirv::ComputeTypeSize(InsnIterator insn)
Nicolas Capens157ba262019-12-10 17:49:14 -05001065{
1066 // Types are always built from the bottom up (with the exception of forward ptrs, which
1067 // don't appear in Vulkan shaders. Therefore, we can always assume our component parts have
1068 // already been described (and so their sizes determined)
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001069 switch(insn.opcode())
Nicolas Capens157ba262019-12-10 17:49:14 -05001070 {
Nicolas Capens112faf42019-12-13 17:32:26 -05001071 case spv::OpTypeVoid:
1072 case spv::OpTypeSampler:
1073 case spv::OpTypeImage:
1074 case spv::OpTypeSampledImage:
Alexis Hetuc582db22022-06-14 16:46:56 -04001075 case spv::OpTypeForwardPointer:
Nicolas Capens112faf42019-12-13 17:32:26 -05001076 case spv::OpTypeFunction:
1077 case spv::OpTypeRuntimeArray:
1078 // Objects that don't consume any space.
1079 // Descriptor-backed objects currently only need exist at compile-time.
1080 // Runtime arrays don't appear in places where their size would be interesting
1081 return 0;
Nicolas Capens157ba262019-12-10 17:49:14 -05001082
Nicolas Capens112faf42019-12-13 17:32:26 -05001083 case spv::OpTypeBool:
1084 case spv::OpTypeFloat:
1085 case spv::OpTypeInt:
1086 // All the fundamental types are 1 component. If we ever add support for 8/16/64-bit components,
1087 // we might need to change this, but only 32 bit components are required for Vulkan 1.1.
1088 return 1;
Nicolas Capens157ba262019-12-10 17:49:14 -05001089
Nicolas Capens112faf42019-12-13 17:32:26 -05001090 case spv::OpTypeVector:
1091 case spv::OpTypeMatrix:
1092 // Vectors and matrices both consume element count * element size.
1093 return getType(insn.word(2)).componentCount * insn.word(3);
Nicolas Capens157ba262019-12-10 17:49:14 -05001094
Nicolas Capens112faf42019-12-13 17:32:26 -05001095 case spv::OpTypeArray:
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001096 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001097 // Element count * element size. Array sizes come from constant ids.
1098 auto arraySize = GetConstScalarInt(insn.word(3));
Nicolas Capensff9f9b52020-04-14 00:46:38 -04001099 return getType(insn.word(2)).componentCount * arraySize;
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001100 }
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001101
Nicolas Capens112faf42019-12-13 17:32:26 -05001102 case spv::OpTypeStruct:
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001103 {
1104 uint32_t size = 0;
1105 for(uint32_t i = 2u; i < insn.wordCount(); i++)
1106 {
Nicolas Capensff9f9b52020-04-14 00:46:38 -04001107 size += getType(insn.word(i)).componentCount;
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001108 }
1109 return size;
1110 }
Nicolas Capens157ba262019-12-10 17:49:14 -05001111
Nicolas Capens112faf42019-12-13 17:32:26 -05001112 case spv::OpTypePointer:
1113 // Runtime representation of a pointer is a per-lane index.
1114 // Note: clients are expected to look through the pointer if they want the pointee size instead.
1115 return 1;
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001116
Nicolas Capens112faf42019-12-13 17:32:26 -05001117 default:
1118 UNREACHABLE("%s", OpcodeName(insn.opcode()));
1119 return 0;
Nicolas Capens157ba262019-12-10 17:49:14 -05001120 }
1121}
1122
Nicolas Capens71134742022-10-12 12:44:16 -04001123int Spirv::VisitInterfaceInner(Type::ID id, Decorations d, const InterfaceVisitor &f) const
Nicolas Capens157ba262019-12-10 17:49:14 -05001124{
1125 // Recursively walks variable definition and its type tree, taking into account
1126 // any explicit Location or Component decorations encountered; where explicit
1127 // Locations or Components are not specified, assigns them sequentially.
1128 // Collected decorations are carried down toward the leaves and across
1129 // siblings; Effect of decorations intentionally does not flow back up the tree.
1130 //
1131 // F is a functor to be called with the effective decoration set for every component.
1132 //
1133 // Returns the next available location, and calls f().
1134
1135 // This covers the rules in Vulkan 1.1 spec, 14.1.4 Location Assignment.
1136
1137 ApplyDecorationsForId(&d, id);
1138
Shahbaz Youssefi4dbbcd02022-09-13 22:23:30 -04001139 const auto &obj = getType(id);
Nicolas Capens157ba262019-12-10 17:49:14 -05001140 switch(obj.opcode())
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001141 {
Nicolas Capens112faf42019-12-13 17:32:26 -05001142 case spv::OpTypePointer:
1143 return VisitInterfaceInner(obj.definition.word(3), d, f);
1144 case spv::OpTypeMatrix:
1145 for(auto i = 0u; i < obj.definition.word(3); i++, d.Location++)
1146 {
1147 // consumes same components of N consecutive locations
1148 VisitInterfaceInner(obj.definition.word(2), d, f);
1149 }
1150 return d.Location;
1151 case spv::OpTypeVector:
1152 for(auto i = 0u; i < obj.definition.word(3); i++, d.Component++)
1153 {
1154 // consumes N consecutive components in the same location
1155 VisitInterfaceInner(obj.definition.word(2), d, f);
1156 }
1157 return d.Location + 1;
1158 case spv::OpTypeFloat:
1159 f(d, ATTRIBTYPE_FLOAT);
1160 return d.Location + 1;
1161 case spv::OpTypeInt:
1162 f(d, obj.definition.word(3) ? ATTRIBTYPE_INT : ATTRIBTYPE_UINT);
1163 return d.Location + 1;
1164 case spv::OpTypeBool:
1165 f(d, ATTRIBTYPE_UINT);
1166 return d.Location + 1;
1167 case spv::OpTypeStruct:
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001168 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001169 // iterate over members, which may themselves have Location/Component decorations
1170 for(auto i = 0u; i < obj.definition.wordCount() - 2; i++)
1171 {
Alexis Hetub6540802020-08-11 18:12:03 -04001172 Decorations dMember = d;
1173 ApplyDecorationsForIdMember(&dMember, id, i);
1174 d.Location = VisitInterfaceInner(obj.definition.word(i + 2), dMember, f);
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001175 d.Component = 0; // Implicit locations always have component=0
1176 }
1177 return d.Location;
Nicolas Capens157ba262019-12-10 17:49:14 -05001178 }
Nicolas Capens112faf42019-12-13 17:32:26 -05001179 case spv::OpTypeArray:
Nicolas Capens157ba262019-12-10 17:49:14 -05001180 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001181 auto arraySize = GetConstScalarInt(obj.definition.word(3));
1182 for(auto i = 0u; i < arraySize; i++)
1183 {
1184 d.Location = VisitInterfaceInner(obj.definition.word(2), d, f);
1185 }
1186 return d.Location;
Nicolas Capens157ba262019-12-10 17:49:14 -05001187 }
Nicolas Capens112faf42019-12-13 17:32:26 -05001188 default:
1189 // Intentionally partial; most opcodes do not participate in type hierarchies
1190 return 0;
Nicolas Capens157ba262019-12-10 17:49:14 -05001191 }
1192}
1193
Nicolas Capens71134742022-10-12 12:44:16 -04001194void Spirv::VisitInterface(Object::ID id, const InterfaceVisitor &f) const
Nicolas Capens157ba262019-12-10 17:49:14 -05001195{
1196 // Walk a variable definition and call f for each component in it.
Nicolas Capensd6806b32022-03-02 10:16:31 -05001197 Decorations d = GetDecorationsForId(id);
Nicolas Capens157ba262019-12-10 17:49:14 -05001198
1199 auto def = getObject(id).definition;
1200 ASSERT(def.opcode() == spv::OpVariable);
1201 VisitInterfaceInner(def.word(1), d, f);
1202}
1203
Nicolas Capens71134742022-10-12 12:44:16 -04001204void Spirv::ApplyDecorationsForAccessChain(Decorations *d, DescriptorDecorations *dd, Object::ID baseId, const Span &indexIds) const
Nicolas Capens157ba262019-12-10 17:49:14 -05001205{
1206 ApplyDecorationsForId(d, baseId);
1207 auto &baseObject = getObject(baseId);
Nicolas Capens72f089c2020-04-08 23:37:08 -04001208 ApplyDecorationsForId(d, baseObject.typeId());
1209 auto typeId = getType(baseObject).element;
Nicolas Capens157ba262019-12-10 17:49:14 -05001210
Nicolas Capens0b2a7682022-04-04 00:43:17 -04001211 for(uint32_t i = 0; i < indexIds.size(); i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05001212 {
1213 ApplyDecorationsForId(d, typeId);
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001214 auto &type = getType(typeId);
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001215 switch(type.opcode())
Nicolas Capens157ba262019-12-10 17:49:14 -05001216 {
Nicolas Capens112faf42019-12-13 17:32:26 -05001217 case spv::OpTypeStruct:
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001218 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001219 int memberIndex = GetConstScalarInt(indexIds[i]);
1220 ApplyDecorationsForIdMember(d, typeId, memberIndex);
1221 typeId = type.definition.word(2u + memberIndex);
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001222 }
Nicolas Capens112faf42019-12-13 17:32:26 -05001223 break;
1224 case spv::OpTypeArray:
1225 case spv::OpTypeRuntimeArray:
1226 if(dd->InputAttachmentIndex >= 0)
1227 {
1228 dd->InputAttachmentIndex += GetConstScalarInt(indexIds[i]);
1229 }
1230 typeId = type.element;
1231 break;
1232 case spv::OpTypeVector:
1233 typeId = type.element;
1234 break;
1235 case spv::OpTypeMatrix:
1236 typeId = type.element;
1237 d->InsideMatrix = true;
1238 break;
1239 default:
1240 UNREACHABLE("%s", OpcodeName(type.definition.opcode()));
Nicolas Capens157ba262019-12-10 17:49:14 -05001241 }
1242 }
1243}
1244
Nicolas Capens1ab775a2022-10-12 15:27:02 -04001245SIMD::Pointer SpirvEmitter::WalkExplicitLayoutAccessChain(Object::ID baseId, Object::ID elementId, const Span &indexIds, bool nonUniform) const
Nicolas Capens157ba262019-12-10 17:49:14 -05001246{
1247 // Produce a offset into external memory in sizeof(float) units
1248
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04001249 auto &baseObject = shader.getObject(baseId);
1250 Type::ID typeId = shader.getType(baseObject).element;
1251 Decorations d = shader.GetDecorationsForId(baseObject.typeId());
Sean Risserda08cb22022-04-08 20:49:06 -04001252 SIMD::Int arrayIndex = 0;
Nicolas Capens157ba262019-12-10 17:49:14 -05001253
Nicolas Capens0b2a7682022-04-04 00:43:17 -04001254 uint32_t start = 0;
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001255 if(baseObject.kind == Object::Kind::DescriptorSet)
Nicolas Capens157ba262019-12-10 17:49:14 -05001256 {
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04001257 auto type = shader.getType(typeId).definition.opcode();
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001258 if(type == spv::OpTypeArray || type == spv::OpTypeRuntimeArray)
Nicolas Capens157ba262019-12-10 17:49:14 -05001259 {
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04001260 auto &obj = shader.getObject(indexIds[0]);
Nicolas Capens479d1432020-01-31 11:19:21 -05001261 ASSERT(obj.kind == Object::Kind::Constant || obj.kind == Object::Kind::Intermediate);
1262 if(obj.kind == Object::Kind::Constant)
1263 {
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04001264 arrayIndex = shader.GetConstScalarInt(indexIds[0]);
Nicolas Capens479d1432020-01-31 11:19:21 -05001265 }
1266 else
1267 {
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04001268 nonUniform |= shader.GetDecorationsForId(indexIds[0]).NonUniform;
1269 arrayIndex = getIntermediate(indexIds[0]).Int(0);
Nicolas Capens479d1432020-01-31 11:19:21 -05001270 }
Nicolas Capens157ba262019-12-10 17:49:14 -05001271
Nicolas Capens0b2a7682022-04-04 00:43:17 -04001272 start = 1;
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04001273 typeId = shader.getType(typeId).element;
Nicolas Capens157ba262019-12-10 17:49:14 -05001274 }
1275 }
1276
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04001277 auto ptr = GetPointerToData(baseId, arrayIndex, nonUniform);
1278 OffsetToElement(ptr, elementId, d.ArrayStride);
Nicolas Capens157ba262019-12-10 17:49:14 -05001279
1280 int constantOffset = 0;
1281
Nicolas Capens0b2a7682022-04-04 00:43:17 -04001282 for(uint32_t i = start; i < indexIds.size(); i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05001283 {
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04001284 auto &type = shader.getType(typeId);
1285 shader.ApplyDecorationsForId(&d, typeId);
Nicolas Capens157ba262019-12-10 17:49:14 -05001286
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001287 switch(type.definition.opcode())
Nicolas Capens157ba262019-12-10 17:49:14 -05001288 {
Nicolas Capens112faf42019-12-13 17:32:26 -05001289 case spv::OpTypeStruct:
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001290 {
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04001291 int memberIndex = shader.GetConstScalarInt(indexIds[i]);
1292 shader.ApplyDecorationsForIdMember(&d, typeId, memberIndex);
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001293 ASSERT(d.HasOffset);
1294 constantOffset += d.Offset;
1295 typeId = type.definition.word(2u + memberIndex);
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001296 }
Nicolas Capens112faf42019-12-13 17:32:26 -05001297 break;
1298 case spv::OpTypeArray:
1299 case spv::OpTypeRuntimeArray:
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001300 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001301 // TODO: b/127950082: Check bounds.
1302 ASSERT(d.HasArrayStride);
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04001303 auto &obj = shader.getObject(indexIds[i]);
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001304 if(obj.kind == Object::Kind::Constant)
1305 {
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04001306 constantOffset += d.ArrayStride * shader.GetConstScalarInt(indexIds[i]);
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001307 }
1308 else
1309 {
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04001310 ptr += SIMD::Int(d.ArrayStride) * getIntermediate(indexIds[i]).Int(0);
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001311 }
1312 typeId = type.element;
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001313 }
Nicolas Capens112faf42019-12-13 17:32:26 -05001314 break;
1315 case spv::OpTypeMatrix:
Chris Forbes17813932019-04-18 11:45:54 -07001316 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001317 // TODO: b/127950082: Check bounds.
1318 ASSERT(d.HasMatrixStride);
1319 d.InsideMatrix = true;
1320 auto columnStride = (d.HasRowMajor && d.RowMajor) ? static_cast<int32_t>(sizeof(float)) : d.MatrixStride;
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04001321 auto &obj = shader.getObject(indexIds[i]);
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001322 if(obj.kind == Object::Kind::Constant)
1323 {
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04001324 constantOffset += columnStride * shader.GetConstScalarInt(indexIds[i]);
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001325 }
1326 else
1327 {
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04001328 ptr += SIMD::Int(columnStride) * getIntermediate(indexIds[i]).Int(0);
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001329 }
1330 typeId = type.element;
Chris Forbes17813932019-04-18 11:45:54 -07001331 }
Nicolas Capens112faf42019-12-13 17:32:26 -05001332 break;
1333 case spv::OpTypeVector:
Chris Forbesa16238d2019-04-18 16:31:54 -07001334 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001335 auto elemStride = (d.InsideMatrix && d.HasRowMajor && d.RowMajor) ? d.MatrixStride : static_cast<int32_t>(sizeof(float));
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04001336 auto &obj = shader.getObject(indexIds[i]);
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001337 if(obj.kind == Object::Kind::Constant)
1338 {
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04001339 constantOffset += elemStride * shader.GetConstScalarInt(indexIds[i]);
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001340 }
1341 else
1342 {
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04001343 ptr += SIMD::Int(elemStride) * getIntermediate(indexIds[i]).Int(0);
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001344 }
1345 typeId = type.element;
Chris Forbesa16238d2019-04-18 16:31:54 -07001346 }
Nicolas Capens112faf42019-12-13 17:32:26 -05001347 break;
1348 default:
Nicolas Capensfdf41472022-09-26 00:40:11 -04001349 UNREACHABLE("%s", shader.OpcodeName(type.definition.opcode()));
Ben Clayton60f15ec2019-05-09 17:50:01 +01001350 }
1351 }
1352
Nicolas Capens157ba262019-12-10 17:49:14 -05001353 ptr += constantOffset;
1354 return ptr;
1355}
Ben Clayton59cd59b2019-06-25 19:07:48 +01001356
Nicolas Capens1ab775a2022-10-12 15:27:02 -04001357SIMD::Pointer SpirvEmitter::WalkAccessChain(Object::ID baseId, Object::ID elementId, const Span &indexIds, bool nonUniform) const
Nicolas Capens157ba262019-12-10 17:49:14 -05001358{
1359 // TODO: avoid doing per-lane work in some cases if we can?
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04001360 auto &baseObject = shader.getObject(baseId);
1361 Type::ID typeId = shader.getType(baseObject).element;
1362 Decorations d = shader.GetDecorationsForId(baseObject.typeId());
1363 auto storageClass = shader.getType(baseObject).storageClass;
Nicolas Capens94c73622022-06-06 13:05:38 -04001364 bool interleavedByLane = IsStorageInterleavedByLane(storageClass);
Nicolas Capens157ba262019-12-10 17:49:14 -05001365
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04001366 auto ptr = getPointer(baseId);
1367 OffsetToElement(ptr, elementId, d.ArrayStride);
Nicolas Capens157ba262019-12-10 17:49:14 -05001368
1369 int constantOffset = 0;
1370
Nicolas Capens0b2a7682022-04-04 00:43:17 -04001371 for(uint32_t i = 0; i < indexIds.size(); i++)
Ben Clayton76e9bc02019-02-26 15:02:18 +00001372 {
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04001373 auto &type = shader.getType(typeId);
Nicolas Capens157ba262019-12-10 17:49:14 -05001374 switch(type.opcode())
1375 {
Nicolas Capens112faf42019-12-13 17:32:26 -05001376 case spv::OpTypeStruct:
Nicolas Capens157ba262019-12-10 17:49:14 -05001377 {
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04001378 int memberIndex = shader.GetConstScalarInt(indexIds[i]);
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001379 int offsetIntoStruct = 0;
1380 for(auto j = 0; j < memberIndex; j++)
Nicolas Capens157ba262019-12-10 17:49:14 -05001381 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001382 auto memberType = type.definition.word(2u + j);
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04001383 offsetIntoStruct += shader.getType(memberType).componentCount * sizeof(float);
Nicolas Capens157ba262019-12-10 17:49:14 -05001384 }
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001385 constantOffset += offsetIntoStruct;
1386 typeId = type.definition.word(2u + memberIndex);
Nicolas Capens157ba262019-12-10 17:49:14 -05001387 }
Nicolas Capens112faf42019-12-13 17:32:26 -05001388 break;
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001389
Nicolas Capens112faf42019-12-13 17:32:26 -05001390 case spv::OpTypeVector:
1391 case spv::OpTypeMatrix:
1392 case spv::OpTypeArray:
1393 case spv::OpTypeRuntimeArray:
Nicolas Capens157ba262019-12-10 17:49:14 -05001394 {
Nicolas Capens479d1432020-01-31 11:19:21 -05001395 // TODO(b/127950082): Check bounds.
Nicolas Capens94c73622022-06-06 13:05:38 -04001396 if(storageClass == spv::StorageClassUniformConstant)
Nicolas Capens157ba262019-12-10 17:49:14 -05001397 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001398 // indexing into an array of descriptors.
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04001399 auto d = shader.descriptorDecorations.at(baseId);
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001400 ASSERT(d.DescriptorSet >= 0);
1401 ASSERT(d.Binding >= 0);
Nicolas Capensc7d5ec32020-04-22 01:11:37 -04001402 uint32_t descriptorSize = routine->pipelineLayout->getDescriptorSize(d.DescriptorSet, d.Binding);
Nicolas Capens479d1432020-01-31 11:19:21 -05001403
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04001404 auto &obj = shader.getObject(indexIds[i]);
Nicolas Capens479d1432020-01-31 11:19:21 -05001405 if(obj.kind == Object::Kind::Constant)
1406 {
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04001407 ptr += descriptorSize * shader.GetConstScalarInt(indexIds[i]);
Nicolas Capens479d1432020-01-31 11:19:21 -05001408 }
1409 else
1410 {
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04001411 nonUniform |= shader.GetDecorationsForId(indexIds[i]).NonUniform;
1412 SIMD::Int intermediate = getIntermediate(indexIds[i]).Int(0);
Sean Rissera4c2e9b2022-05-03 14:47:41 -04001413 if(nonUniform)
1414 {
1415 // NonUniform array data can deal with pointers not bound by a 32-bit address
1416 // space, so we need to ensure we're using an array pointer, and not a base+offset
1417 // pointer.
Nicolas Capens942c6392022-06-30 00:20:40 -04001418 std::vector<Pointer<Byte>> pointers(SIMD::Width);
Sean Rissera4c2e9b2022-05-03 14:47:41 -04001419 for(int i = 0; i < SIMD::Width; i++)
1420 {
1421 pointers[i] = ptr.getPointerForLane(i);
1422 }
1423 ptr = SIMD::Pointer(pointers);
1424 ptr += descriptorSize * intermediate;
1425 }
1426 else
1427 {
1428 ptr += descriptorSize * Extract(intermediate, 0);
1429 }
Nicolas Capens479d1432020-01-31 11:19:21 -05001430 }
Nicolas Capens157ba262019-12-10 17:49:14 -05001431 }
1432 else
1433 {
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04001434 auto stride = shader.getType(type.element).componentCount * static_cast<uint32_t>(sizeof(float));
Nicolas Capens94c73622022-06-06 13:05:38 -04001435
1436 if(interleavedByLane)
1437 {
1438 stride *= SIMD::Width;
1439 }
1440
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04001441 if(shader.getObject(indexIds[i]).kind == Object::Kind::Constant)
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001442 {
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04001443 ptr += stride * shader.GetConstScalarInt(indexIds[i]);
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001444 }
1445 else
1446 {
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04001447 ptr += SIMD::Int(stride) * getIntermediate(indexIds[i]).Int(0);
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001448 }
Nicolas Capens157ba262019-12-10 17:49:14 -05001449 }
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001450 typeId = type.element;
Nicolas Capens157ba262019-12-10 17:49:14 -05001451 }
Nicolas Capens112faf42019-12-13 17:32:26 -05001452 break;
Nicolas Capens157ba262019-12-10 17:49:14 -05001453
Nicolas Capens112faf42019-12-13 17:32:26 -05001454 default:
Nicolas Capensfdf41472022-09-26 00:40:11 -04001455 UNREACHABLE("%s", shader.OpcodeName(type.opcode()));
Nicolas Capens157ba262019-12-10 17:49:14 -05001456 }
Ben Clayton76e9bc02019-02-26 15:02:18 +00001457 }
1458
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001459 if(constantOffset != 0)
Ben Clayton30ee92e2019-08-13 14:21:44 +01001460 {
Nicolas Capens94c73622022-06-06 13:05:38 -04001461 if(interleavedByLane)
1462 {
1463 constantOffset *= SIMD::Width;
1464 }
1465
Nicolas Capens157ba262019-12-10 17:49:14 -05001466 ptr += constantOffset;
1467 }
Nicolas Capens94c73622022-06-06 13:05:38 -04001468
Nicolas Capens157ba262019-12-10 17:49:14 -05001469 return ptr;
1470}
Ben Clayton30ee92e2019-08-13 14:21:44 +01001471
Nicolas Capens71134742022-10-12 12:44:16 -04001472uint32_t Spirv::WalkLiteralAccessChain(Type::ID typeId, const Span &indexes) const
Nicolas Capens157ba262019-12-10 17:49:14 -05001473{
1474 uint32_t componentOffset = 0;
Ben Clayton30ee92e2019-08-13 14:21:44 +01001475
Nicolas Capens0b2a7682022-04-04 00:43:17 -04001476 for(uint32_t i = 0; i < indexes.size(); i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05001477 {
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001478 auto &type = getType(typeId);
Nicolas Capens157ba262019-12-10 17:49:14 -05001479 switch(type.opcode())
Ben Clayton30ee92e2019-08-13 14:21:44 +01001480 {
Nicolas Capens112faf42019-12-13 17:32:26 -05001481 case spv::OpTypeStruct:
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001482 {
1483 int memberIndex = indexes[i];
1484 int offsetIntoStruct = 0;
1485 for(auto j = 0; j < memberIndex; j++)
1486 {
1487 auto memberType = type.definition.word(2u + j);
Nicolas Capensff9f9b52020-04-14 00:46:38 -04001488 offsetIntoStruct += getType(memberType).componentCount;
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001489 }
1490 componentOffset += offsetIntoStruct;
1491 typeId = type.definition.word(2u + memberIndex);
Nicolas Capens157ba262019-12-10 17:49:14 -05001492 }
Nicolas Capens112faf42019-12-13 17:32:26 -05001493 break;
Ben Clayton30ee92e2019-08-13 14:21:44 +01001494
Nicolas Capens112faf42019-12-13 17:32:26 -05001495 case spv::OpTypeVector:
1496 case spv::OpTypeMatrix:
1497 case spv::OpTypeArray:
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001498 {
1499 auto elementType = type.definition.word(2);
Nicolas Capensff9f9b52020-04-14 00:46:38 -04001500 auto stride = getType(elementType).componentCount;
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001501 componentOffset += stride * indexes[i];
1502 typeId = elementType;
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001503 }
Nicolas Capens112faf42019-12-13 17:32:26 -05001504 break;
Ben Clayton30ee92e2019-08-13 14:21:44 +01001505
Nicolas Capens112faf42019-12-13 17:32:26 -05001506 default:
1507 UNREACHABLE("%s", OpcodeName(type.opcode()));
Nicolas Capens157ba262019-12-10 17:49:14 -05001508 }
1509 }
Ben Clayton30ee92e2019-08-13 14:21:44 +01001510
Nicolas Capens157ba262019-12-10 17:49:14 -05001511 return componentOffset;
1512}
Ben Clayton30ee92e2019-08-13 14:21:44 +01001513
Nicolas Capens71134742022-10-12 12:44:16 -04001514void Spirv::Decorations::Apply(spv::Decoration decoration, uint32_t arg)
Nicolas Capens157ba262019-12-10 17:49:14 -05001515{
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001516 switch(decoration)
Nicolas Capens157ba262019-12-10 17:49:14 -05001517 {
Nicolas Capens112faf42019-12-13 17:32:26 -05001518 case spv::DecorationLocation:
1519 HasLocation = true;
1520 Location = static_cast<int32_t>(arg);
1521 break;
1522 case spv::DecorationComponent:
1523 HasComponent = true;
1524 Component = arg;
1525 break;
1526 case spv::DecorationBuiltIn:
1527 HasBuiltIn = true;
1528 BuiltIn = static_cast<spv::BuiltIn>(arg);
1529 break;
1530 case spv::DecorationFlat:
1531 Flat = true;
1532 break;
1533 case spv::DecorationNoPerspective:
1534 NoPerspective = true;
1535 break;
1536 case spv::DecorationCentroid:
1537 Centroid = true;
1538 break;
1539 case spv::DecorationBlock:
1540 Block = true;
1541 break;
1542 case spv::DecorationBufferBlock:
1543 BufferBlock = true;
1544 break;
1545 case spv::DecorationOffset:
1546 HasOffset = true;
1547 Offset = static_cast<int32_t>(arg);
1548 break;
1549 case spv::DecorationArrayStride:
1550 HasArrayStride = true;
1551 ArrayStride = static_cast<int32_t>(arg);
1552 break;
1553 case spv::DecorationMatrixStride:
1554 HasMatrixStride = true;
1555 MatrixStride = static_cast<int32_t>(arg);
1556 break;
1557 case spv::DecorationRelaxedPrecision:
1558 RelaxedPrecision = true;
1559 break;
1560 case spv::DecorationRowMajor:
1561 HasRowMajor = true;
1562 RowMajor = true;
1563 break;
1564 case spv::DecorationColMajor:
1565 HasRowMajor = true;
1566 RowMajor = false;
Sean Risserda08cb22022-04-08 20:49:06 -04001567 break;
1568 case spv::DecorationNonUniform:
1569 NonUniform = true;
1570 break;
Nicolas Capens112faf42019-12-13 17:32:26 -05001571 default:
1572 // Intentionally partial, there are many decorations we just don't care about.
1573 break;
Ben Clayton30ee92e2019-08-13 14:21:44 +01001574 }
Chris Forbesc25b8072018-12-10 15:10:39 -08001575}
Nicolas Capens157ba262019-12-10 17:49:14 -05001576
Nicolas Capens71134742022-10-12 12:44:16 -04001577void Spirv::Decorations::Apply(const Decorations &src)
Nicolas Capens157ba262019-12-10 17:49:14 -05001578{
1579 // Apply a decoration group to this set of decorations
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001580 if(src.HasBuiltIn)
Nicolas Capens157ba262019-12-10 17:49:14 -05001581 {
1582 HasBuiltIn = true;
1583 BuiltIn = src.BuiltIn;
1584 }
1585
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001586 if(src.HasLocation)
Nicolas Capens157ba262019-12-10 17:49:14 -05001587 {
1588 HasLocation = true;
1589 Location = src.Location;
1590 }
1591
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001592 if(src.HasComponent)
Nicolas Capens157ba262019-12-10 17:49:14 -05001593 {
1594 HasComponent = true;
1595 Component = src.Component;
1596 }
1597
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001598 if(src.HasOffset)
Nicolas Capens157ba262019-12-10 17:49:14 -05001599 {
1600 HasOffset = true;
1601 Offset = src.Offset;
1602 }
1603
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001604 if(src.HasArrayStride)
Nicolas Capens157ba262019-12-10 17:49:14 -05001605 {
1606 HasArrayStride = true;
1607 ArrayStride = src.ArrayStride;
1608 }
1609
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001610 if(src.HasMatrixStride)
Nicolas Capens157ba262019-12-10 17:49:14 -05001611 {
1612 HasMatrixStride = true;
1613 MatrixStride = src.MatrixStride;
1614 }
1615
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001616 if(src.HasRowMajor)
Nicolas Capens157ba262019-12-10 17:49:14 -05001617 {
1618 HasRowMajor = true;
1619 RowMajor = src.RowMajor;
1620 }
1621
1622 Flat |= src.Flat;
1623 NoPerspective |= src.NoPerspective;
1624 Centroid |= src.Centroid;
1625 Block |= src.Block;
1626 BufferBlock |= src.BufferBlock;
1627 RelaxedPrecision |= src.RelaxedPrecision;
1628 InsideMatrix |= src.InsideMatrix;
Sean Risserda08cb22022-04-08 20:49:06 -04001629 NonUniform |= src.NonUniform;
Nicolas Capens157ba262019-12-10 17:49:14 -05001630}
1631
Nicolas Capens71134742022-10-12 12:44:16 -04001632void Spirv::DescriptorDecorations::Apply(const sw::Spirv::DescriptorDecorations &src)
Nicolas Capens157ba262019-12-10 17:49:14 -05001633{
1634 if(src.DescriptorSet >= 0)
1635 {
1636 DescriptorSet = src.DescriptorSet;
1637 }
1638
1639 if(src.Binding >= 0)
1640 {
1641 Binding = src.Binding;
1642 }
1643
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001644 if(src.InputAttachmentIndex >= 0)
Nicolas Capens157ba262019-12-10 17:49:14 -05001645 {
1646 InputAttachmentIndex = src.InputAttachmentIndex;
1647 }
1648}
1649
Nicolas Capens71134742022-10-12 12:44:16 -04001650Spirv::Decorations Spirv::GetDecorationsForId(TypeOrObjectID id) const
Nicolas Capensd6806b32022-03-02 10:16:31 -05001651{
1652 Decorations d;
1653 ApplyDecorationsForId(&d, id);
1654
1655 return d;
1656}
1657
Nicolas Capens71134742022-10-12 12:44:16 -04001658void Spirv::ApplyDecorationsForId(Decorations *d, TypeOrObjectID id) const
Nicolas Capens157ba262019-12-10 17:49:14 -05001659{
1660 auto it = decorations.find(id);
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001661 if(it != decorations.end())
Nicolas Capensd6806b32022-03-02 10:16:31 -05001662 {
Nicolas Capens157ba262019-12-10 17:49:14 -05001663 d->Apply(it->second);
Nicolas Capensd6806b32022-03-02 10:16:31 -05001664 }
Nicolas Capens157ba262019-12-10 17:49:14 -05001665}
1666
Nicolas Capens71134742022-10-12 12:44:16 -04001667void Spirv::ApplyDecorationsForIdMember(Decorations *d, Type::ID id, uint32_t member) const
Nicolas Capens157ba262019-12-10 17:49:14 -05001668{
1669 auto it = memberDecorations.find(id);
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001670 if(it != memberDecorations.end() && member < it->second.size())
Nicolas Capens157ba262019-12-10 17:49:14 -05001671 {
1672 d->Apply(it->second[member]);
1673 }
1674}
1675
Nicolas Capens71134742022-10-12 12:44:16 -04001676void Spirv::DefineResult(const InsnIterator &insn)
Nicolas Capens157ba262019-12-10 17:49:14 -05001677{
1678 Type::ID typeId = insn.word(1);
1679 Object::ID resultId = insn.word(2);
1680 auto &object = defs[resultId];
Nicolas Capens157ba262019-12-10 17:49:14 -05001681
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001682 switch(getType(typeId).opcode())
Nicolas Capens157ba262019-12-10 17:49:14 -05001683 {
Alexis Hetu7c6c7b72022-09-01 17:37:49 -04001684 case spv::OpTypeSampledImage:
1685 object.kind = Object::Kind::SampledImage;
1686 break;
1687
Nicolas Capens112faf42019-12-13 17:32:26 -05001688 case spv::OpTypePointer:
1689 case spv::OpTypeImage:
Nicolas Capens112faf42019-12-13 17:32:26 -05001690 case spv::OpTypeSampler:
1691 object.kind = Object::Kind::Pointer;
1692 break;
Nicolas Capens157ba262019-12-10 17:49:14 -05001693
Nicolas Capens112faf42019-12-13 17:32:26 -05001694 default:
1695 object.kind = Object::Kind::Intermediate;
Nicolas Capens157ba262019-12-10 17:49:14 -05001696 }
1697
1698 object.definition = insn;
1699}
1700
Nicolas Capens6beafb42022-10-12 16:11:39 -04001701OutOfBoundsBehavior SpirvShader::getOutOfBoundsBehavior(Object::ID pointerId, const vk::PipelineLayout *pipelineLayout) const
Nicolas Capens157ba262019-12-10 17:49:14 -05001702{
Alexis Hetu8941bde2021-11-17 17:45:40 -05001703 auto it = descriptorDecorations.find(pointerId);
1704 if(it != descriptorDecorations.end())
1705 {
1706 const auto &d = it->second;
1707 if((d.DescriptorSet >= 0) && (d.Binding >= 0))
1708 {
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04001709 auto descriptorType = pipelineLayout->getDescriptorType(d.DescriptorSet, d.Binding);
Alexis Hetu8941bde2021-11-17 17:45:40 -05001710 if(descriptorType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT)
1711 {
1712 return OutOfBoundsBehavior::UndefinedBehavior;
1713 }
1714 }
1715 }
1716
1717 auto &pointer = getObject(pointerId);
1718 auto &pointerTy = getType(pointer);
1719 switch(pointerTy.storageClass)
Nicolas Capens157ba262019-12-10 17:49:14 -05001720 {
Nicolas Capens112faf42019-12-13 17:32:26 -05001721 case spv::StorageClassUniform:
1722 case spv::StorageClassStorageBuffer:
1723 // Buffer resource access. robustBufferAccess feature applies.
1724 return robustBufferAccess ? OutOfBoundsBehavior::RobustBufferAccess
1725 : OutOfBoundsBehavior::UndefinedBehavior;
1726
Alexis Hetu71ec98e2022-06-14 16:58:44 -04001727 case spv::StorageClassPhysicalStorageBuffer:
1728 return OutOfBoundsBehavior::UndefinedBehavior;
1729
Nicolas Capens112faf42019-12-13 17:32:26 -05001730 case spv::StorageClassImage:
1731 // VK_EXT_image_robustness requires nullifying out-of-bounds accesses.
1732 // TODO(b/162327166): Only perform bounds checks when VK_EXT_image_robustness is enabled.
1733 return OutOfBoundsBehavior::Nullify;
1734
1735 case spv::StorageClassInput:
1736 if(executionModel == spv::ExecutionModelVertex)
1737 {
1738 // Vertex attributes follow robustBufferAccess rules.
Nicolas Capens157ba262019-12-10 17:49:14 -05001739 return robustBufferAccess ? OutOfBoundsBehavior::RobustBufferAccess
1740 : OutOfBoundsBehavior::UndefinedBehavior;
Nicolas Capens112faf42019-12-13 17:32:26 -05001741 }
1742 // Fall through to default case.
1743 default:
Nicolas Capense4b77942021-08-03 17:09:41 -04001744 // TODO(b/192310780): StorageClassFunction out-of-bounds accesses are undefined behavior.
Nicolas Capens112faf42019-12-13 17:32:26 -05001745 // TODO(b/137183137): Optimize if the pointer resulted from OpInBoundsAccessChain.
1746 // TODO(b/131224163): Optimize cases statically known to be within bounds.
1747 return OutOfBoundsBehavior::UndefinedValue;
Nicolas Capens157ba262019-12-10 17:49:14 -05001748 }
1749
1750 return OutOfBoundsBehavior::Nullify;
1751}
1752
1753// emit-time
1754
Nicolas Capens6beafb42022-10-12 16:11:39 -04001755void SpirvShader::emitProlog(SpirvRoutine *routine) const
Nicolas Capens157ba262019-12-10 17:49:14 -05001756{
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001757 for(auto insn : *this)
Nicolas Capens157ba262019-12-10 17:49:14 -05001758 {
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001759 switch(insn.opcode())
Nicolas Capens157ba262019-12-10 17:49:14 -05001760 {
Nicolas Capens112faf42019-12-13 17:32:26 -05001761 case spv::OpVariable:
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001762 {
Nicolas Capens71186752020-04-09 01:05:31 -04001763 auto resultPointerType = getType(insn.resultTypeId());
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001764 auto pointeeType = getType(resultPointerType.element);
Nicolas Capens157ba262019-12-10 17:49:14 -05001765
Nicolas Capens7ef39492022-10-05 13:31:56 -04001766 if(pointeeType.componentCount > 0)
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001767 {
Nicolas Capensff9f9b52020-04-14 00:46:38 -04001768 routine->createVariable(insn.resultId(), pointeeType.componentCount);
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001769 }
Ben Claytonbc1c067be2019-12-17 20:37:37 +00001770 }
Nicolas Capens112faf42019-12-13 17:32:26 -05001771 break;
1772
Nicolas Capensf0e8ec22021-11-12 13:57:14 -05001773 case spv::OpImageSampleImplicitLod:
1774 case spv::OpImageSampleExplicitLod:
1775 case spv::OpImageSampleDrefImplicitLod:
1776 case spv::OpImageSampleDrefExplicitLod:
1777 case spv::OpImageSampleProjImplicitLod:
1778 case spv::OpImageSampleProjExplicitLod:
1779 case spv::OpImageSampleProjDrefImplicitLod:
1780 case spv::OpImageSampleProjDrefExplicitLod:
Nicolas Capens112faf42019-12-13 17:32:26 -05001781 case spv::OpImageFetch:
1782 case spv::OpImageGather:
Nicolas Capensf0e8ec22021-11-12 13:57:14 -05001783 case spv::OpImageDrefGather:
1784 case spv::OpImageWrite:
Nicolas Capens112faf42019-12-13 17:32:26 -05001785 case spv::OpImageQueryLod:
Nicolas Capens96b34f72021-11-09 00:41:40 -05001786 {
1787 // The 'inline' sampler caches must be created in the prolog to initialize the tags.
1788 uint32_t instructionPosition = insn.distanceFrom(this->begin());
1789 routine->samplerCache.emplace(instructionPosition, SpirvRoutine::SamplerCache{});
1790 }
Nicolas Capens112faf42019-12-13 17:32:26 -05001791 break;
Nicolas Capens157ba262019-12-10 17:49:14 -05001792
Nicolas Capens112faf42019-12-13 17:32:26 -05001793 default:
1794 // Nothing else produces interface variables, so can all be safely ignored.
1795 break;
Nicolas Capens157ba262019-12-10 17:49:14 -05001796 }
1797 }
1798}
1799
Nicolas Capens6beafb42022-10-12 16:11:39 -04001800void SpirvShader::emit(SpirvRoutine *routine, const RValue<SIMD::Int> &activeLaneMask, const RValue<SIMD::Int> &storesAndAtomicsMask, const vk::DescriptorSet::Bindings &descriptorSets, unsigned int multiSampleCount) const
Nicolas Capens157ba262019-12-10 17:49:14 -05001801{
Nicolas Capens1ab775a2022-10-12 15:27:02 -04001802 SpirvEmitter::emit(*this, routine, entryPoint, activeLaneMask, storesAndAtomicsMask, descriptorSets, multiSampleCount);
Nicolas Capens7ef39492022-10-05 13:31:56 -04001803}
1804
Nicolas Capens71134742022-10-12 12:44:16 -04001805SpirvShader::SpirvShader(VkShaderStageFlagBits stage,
1806 const char *entryPointName,
1807 const SpirvBinary &insns,
1808 const vk::RenderPass *renderPass,
1809 uint32_t subpassIndex,
1810 bool robustBufferAccess)
Nicolas Capens6beafb42022-10-12 16:11:39 -04001811 : Spirv(stage, entryPointName, insns)
1812 , robustBufferAccess(robustBufferAccess)
Nicolas Capens71134742022-10-12 12:44:16 -04001813{
Nicolas Capens6beafb42022-10-12 16:11:39 -04001814 if(renderPass)
1815 {
1816 // capture formats of any input attachments present
1817 auto subpass = renderPass->getSubpass(subpassIndex);
1818 inputAttachmentFormats.reserve(subpass.inputAttachmentCount);
1819 for(auto i = 0u; i < subpass.inputAttachmentCount; i++)
1820 {
1821 auto attachmentIndex = subpass.pInputAttachments[i].attachment;
1822 inputAttachmentFormats.push_back(attachmentIndex != VK_ATTACHMENT_UNUSED
1823 ? renderPass->getAttachment(attachmentIndex).format
1824 : VK_FORMAT_UNDEFINED);
1825 }
1826 }
Nicolas Capens71134742022-10-12 12:44:16 -04001827}
1828
1829SpirvShader::~SpirvShader()
1830{
1831}
1832
Nicolas Capens6beafb42022-10-12 16:11:39 -04001833SpirvEmitter::SpirvEmitter(const SpirvShader &shader,
Nicolas Capens1ab775a2022-10-12 15:27:02 -04001834 SpirvRoutine *routine,
Nicolas Capens71134742022-10-12 12:44:16 -04001835 Spirv::Function::ID entryPoint,
Nicolas Capens1ab775a2022-10-12 15:27:02 -04001836 RValue<SIMD::Int> activeLaneMask,
1837 RValue<SIMD::Int> storesAndAtomicsMask,
1838 const vk::DescriptorSet::Bindings &descriptorSets,
1839 unsigned int multiSampleCount)
Nicolas Capens7ef39492022-10-05 13:31:56 -04001840 : shader(shader)
1841 , routine(routine)
1842 , function(entryPoint)
1843 , activeLaneMaskValue(activeLaneMask.value())
1844 , storesAndAtomicsMaskValue(storesAndAtomicsMask.value())
1845 , descriptorSets(descriptorSets)
1846 , multiSampleCount(multiSampleCount)
1847{
1848}
1849
Nicolas Capens6beafb42022-10-12 16:11:39 -04001850void SpirvEmitter::emit(const SpirvShader &shader,
Nicolas Capens1ab775a2022-10-12 15:27:02 -04001851 SpirvRoutine *routine,
Nicolas Capens71134742022-10-12 12:44:16 -04001852 Spirv::Function::ID entryPoint,
Nicolas Capens1ab775a2022-10-12 15:27:02 -04001853 RValue<SIMD::Int> activeLaneMask,
1854 RValue<SIMD::Int> storesAndAtomicsMask,
1855 const vk::DescriptorSet::Bindings &descriptorSets,
1856 unsigned int multiSampleCount)
Nicolas Capens7ef39492022-10-05 13:31:56 -04001857{
Nicolas Capens1ab775a2022-10-12 15:27:02 -04001858 SpirvEmitter state(shader, routine, entryPoint, activeLaneMask, storesAndAtomicsMask, descriptorSets, multiSampleCount);
Nicolas Capens7ef39492022-10-05 13:31:56 -04001859
1860 // Create phi variables
1861 for(auto insn : shader)
1862 {
1863 if(insn.opcode() == spv::OpPhi)
1864 {
1865 auto type = shader.getType(insn.resultTypeId());
Nicolas Capensb5074c82022-10-06 22:22:02 -04001866 state.phis.emplace(insn.resultId(), std::vector<SIMD::Float>(type.componentCount));
Nicolas Capens7ef39492022-10-05 13:31:56 -04001867 }
1868 }
Nicolas Capens157ba262019-12-10 17:49:14 -05001869
1870 // Emit everything up to the first label
1871 // TODO: Separate out dispatch of block from non-block instructions?
Nicolas Capens7ef39492022-10-05 13:31:56 -04001872 for(auto insn : shader)
Nicolas Capens157ba262019-12-10 17:49:14 -05001873 {
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001874 if(insn.opcode() == spv::OpLabel)
Nicolas Capens157ba262019-12-10 17:49:14 -05001875 {
1876 break;
1877 }
Nicolas Capens7ef39492022-10-05 13:31:56 -04001878
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04001879 state.EmitInstruction(insn);
Nicolas Capens157ba262019-12-10 17:49:14 -05001880 }
1881
1882 // Emit all the blocks starting from entryPoint.
Nicolas Capens7ef39492022-10-05 13:31:56 -04001883 state.EmitBlocks(shader.getFunction(entryPoint).entry);
Nicolas Capens157ba262019-12-10 17:49:14 -05001884}
1885
Nicolas Capens1ab775a2022-10-12 15:27:02 -04001886void SpirvEmitter::EmitInstructions(InsnIterator begin, InsnIterator end)
Nicolas Capens157ba262019-12-10 17:49:14 -05001887{
Nicolas Capens81bc9d92019-12-16 15:05:57 -05001888 for(auto insn = begin; insn != end; insn++)
Nicolas Capens157ba262019-12-10 17:49:14 -05001889 {
Nicolas Capensad9acf22022-10-12 15:19:01 -04001890 EmitInstruction(insn);
1891
1892 if(shader.IsTerminator(insn.opcode()))
Nicolas Capens157ba262019-12-10 17:49:14 -05001893 {
Nicolas Capens112faf42019-12-13 17:32:26 -05001894 break;
Nicolas Capens157ba262019-12-10 17:49:14 -05001895 }
1896 }
1897}
1898
Nicolas Capens1ab775a2022-10-12 15:27:02 -04001899void SpirvEmitter::EmitInstruction(InsnIterator insn)
Nicolas Capens157ba262019-12-10 17:49:14 -05001900{
1901 auto opcode = insn.opcode();
1902
Ben Claytonfc951cd2019-05-15 17:16:56 +01001903#if SPIRV_SHADER_ENABLE_DBG
1904 {
1905 auto text = spvtools::spvInstructionBinaryToText(
Sean Risser019feda2020-11-09 14:19:27 -05001906 vk::SPIRV_VERSION,
Nicolas Capens0b2a7682022-04-04 00:43:17 -04001907 insn.data(),
Ben Claytonfc951cd2019-05-15 17:16:56 +01001908 insn.wordCount(),
1909 insns.data(),
1910 insns.size(),
1911 SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
1912 SPIRV_SHADER_DBG("{0}", text);
1913 }
1914#endif // ENABLE_DBG_MSGS
1915
Nicolas Capensad9acf22022-10-12 15:19:01 -04001916 if(shader.IsTerminator(opcode))
Nicolas Capens157ba262019-12-10 17:49:14 -05001917 {
Nicolas Capensad9acf22022-10-12 15:19:01 -04001918 switch(opcode)
1919 {
1920 case spv::OpBranch:
1921 return EmitBranch(insn);
Nicolas Capens157ba262019-12-10 17:49:14 -05001922
Nicolas Capensad9acf22022-10-12 15:19:01 -04001923 case spv::OpBranchConditional:
1924 return EmitBranchConditional(insn);
Ben Claytonb0ca2a82020-01-08 13:00:57 +00001925
Nicolas Capensad9acf22022-10-12 15:19:01 -04001926 case spv::OpSwitch:
1927 return EmitSwitch(insn);
Nicolas Capens157ba262019-12-10 17:49:14 -05001928
Nicolas Capensad9acf22022-10-12 15:19:01 -04001929 case spv::OpUnreachable:
1930 return EmitUnreachable(insn);
Nicolas Capens157ba262019-12-10 17:49:14 -05001931
Nicolas Capensad9acf22022-10-12 15:19:01 -04001932 case spv::OpReturn:
1933 return EmitReturn(insn);
Nicolas Capens157ba262019-12-10 17:49:14 -05001934
Nicolas Capensad9acf22022-10-12 15:19:01 -04001935 case spv::OpKill:
1936 case spv::OpTerminateInvocation:
1937 return EmitTerminateInvocation(insn);
Nicolas Capens157ba262019-12-10 17:49:14 -05001938
Nicolas Capensad9acf22022-10-12 15:19:01 -04001939 default:
1940 UNREACHABLE("Unknown terminal instruction %s", shader.OpcodeName(opcode));
1941 break;
1942 }
Nicolas Capens157ba262019-12-10 17:49:14 -05001943 }
Nicolas Capensad9acf22022-10-12 15:19:01 -04001944 else // Non-terminal instructions
1945 {
1946 switch(opcode)
1947 {
1948 case spv::OpTypeVoid:
1949 case spv::OpTypeInt:
1950 case spv::OpTypeFloat:
1951 case spv::OpTypeBool:
1952 case spv::OpTypeVector:
1953 case spv::OpTypeArray:
1954 case spv::OpTypeRuntimeArray:
1955 case spv::OpTypeMatrix:
1956 case spv::OpTypeStruct:
1957 case spv::OpTypePointer:
1958 case spv::OpTypeForwardPointer:
1959 case spv::OpTypeFunction:
1960 case spv::OpTypeImage:
1961 case spv::OpTypeSampledImage:
1962 case spv::OpTypeSampler:
1963 case spv::OpExecutionMode:
1964 case spv::OpExecutionModeId:
1965 case spv::OpMemoryModel:
1966 case spv::OpFunction:
1967 case spv::OpFunctionEnd:
1968 case spv::OpConstant:
1969 case spv::OpConstantNull:
1970 case spv::OpConstantTrue:
1971 case spv::OpConstantFalse:
1972 case spv::OpConstantComposite:
1973 case spv::OpSpecConstant:
1974 case spv::OpSpecConstantTrue:
1975 case spv::OpSpecConstantFalse:
1976 case spv::OpSpecConstantComposite:
1977 case spv::OpSpecConstantOp:
1978 case spv::OpUndef:
1979 case spv::OpExtension:
1980 case spv::OpCapability:
1981 case spv::OpEntryPoint:
1982 case spv::OpExtInstImport:
1983 case spv::OpDecorate:
1984 case spv::OpMemberDecorate:
1985 case spv::OpGroupDecorate:
1986 case spv::OpGroupMemberDecorate:
1987 case spv::OpDecorationGroup:
1988 case spv::OpDecorateId:
1989 case spv::OpDecorateString:
1990 case spv::OpMemberDecorateString:
1991 case spv::OpName:
1992 case spv::OpMemberName:
1993 case spv::OpSource:
1994 case spv::OpSourceContinued:
1995 case spv::OpSourceExtension:
1996 case spv::OpNoLine:
1997 case spv::OpModuleProcessed:
1998 case spv::OpString:
1999 // Nothing to do at emit time. These are either fully handled at analysis time,
2000 // or don't require any work at all.
2001 return;
Nicolas Capens157ba262019-12-10 17:49:14 -05002002
Nicolas Capensad9acf22022-10-12 15:19:01 -04002003 case spv::OpLine:
2004 return; // TODO(b/251802301)
2005
2006 case spv::OpLabel:
2007 return;
2008
2009 case spv::OpVariable:
2010 return EmitVariable(insn);
2011
2012 case spv::OpLoad:
2013 case spv::OpAtomicLoad:
2014 return EmitLoad(insn);
2015
2016 case spv::OpStore:
2017 case spv::OpAtomicStore:
2018 return EmitStore(insn);
2019
2020 case spv::OpAtomicIAdd:
2021 case spv::OpAtomicISub:
2022 case spv::OpAtomicSMin:
2023 case spv::OpAtomicSMax:
2024 case spv::OpAtomicUMin:
2025 case spv::OpAtomicUMax:
2026 case spv::OpAtomicAnd:
2027 case spv::OpAtomicOr:
2028 case spv::OpAtomicXor:
2029 case spv::OpAtomicIIncrement:
2030 case spv::OpAtomicIDecrement:
2031 case spv::OpAtomicExchange:
2032 return EmitAtomicOp(insn);
2033
2034 case spv::OpAtomicCompareExchange:
2035 return EmitAtomicCompareExchange(insn);
2036
2037 case spv::OpAccessChain:
2038 case spv::OpInBoundsAccessChain:
2039 case spv::OpPtrAccessChain:
2040 return EmitAccessChain(insn);
2041
2042 case spv::OpCompositeConstruct:
2043 return EmitCompositeConstruct(insn);
2044
2045 case spv::OpCompositeInsert:
2046 return EmitCompositeInsert(insn);
2047
2048 case spv::OpCompositeExtract:
2049 return EmitCompositeExtract(insn);
2050
2051 case spv::OpVectorShuffle:
2052 return EmitVectorShuffle(insn);
2053
2054 case spv::OpVectorExtractDynamic:
2055 return EmitVectorExtractDynamic(insn);
2056
2057 case spv::OpVectorInsertDynamic:
2058 return EmitVectorInsertDynamic(insn);
2059
2060 case spv::OpVectorTimesScalar:
2061 case spv::OpMatrixTimesScalar:
2062 return EmitVectorTimesScalar(insn);
2063
2064 case spv::OpMatrixTimesVector:
2065 return EmitMatrixTimesVector(insn);
2066
2067 case spv::OpVectorTimesMatrix:
2068 return EmitVectorTimesMatrix(insn);
2069
2070 case spv::OpMatrixTimesMatrix:
2071 return EmitMatrixTimesMatrix(insn);
2072
2073 case spv::OpOuterProduct:
2074 return EmitOuterProduct(insn);
2075
2076 case spv::OpTranspose:
2077 return EmitTranspose(insn);
2078
2079 case spv::OpNot:
2080 case spv::OpBitFieldInsert:
2081 case spv::OpBitFieldSExtract:
2082 case spv::OpBitFieldUExtract:
2083 case spv::OpBitReverse:
2084 case spv::OpBitCount:
2085 case spv::OpSNegate:
2086 case spv::OpFNegate:
2087 case spv::OpLogicalNot:
2088 case spv::OpConvertFToU:
2089 case spv::OpConvertFToS:
2090 case spv::OpConvertSToF:
2091 case spv::OpConvertUToF:
2092 case spv::OpBitcast:
2093 case spv::OpIsInf:
2094 case spv::OpIsNan:
2095 case spv::OpDPdx:
2096 case spv::OpDPdxCoarse:
2097 case spv::OpDPdy:
2098 case spv::OpDPdyCoarse:
2099 case spv::OpFwidth:
2100 case spv::OpFwidthCoarse:
2101 case spv::OpDPdxFine:
2102 case spv::OpDPdyFine:
2103 case spv::OpFwidthFine:
2104 case spv::OpQuantizeToF16:
2105 return EmitUnaryOp(insn);
2106
2107 case spv::OpIAdd:
2108 case spv::OpISub:
2109 case spv::OpIMul:
2110 case spv::OpSDiv:
2111 case spv::OpUDiv:
2112 case spv::OpFAdd:
2113 case spv::OpFSub:
2114 case spv::OpFMul:
2115 case spv::OpFDiv:
2116 case spv::OpFMod:
2117 case spv::OpFRem:
2118 case spv::OpFOrdEqual:
2119 case spv::OpFUnordEqual:
2120 case spv::OpFOrdNotEqual:
2121 case spv::OpFUnordNotEqual:
2122 case spv::OpFOrdLessThan:
2123 case spv::OpFUnordLessThan:
2124 case spv::OpFOrdGreaterThan:
2125 case spv::OpFUnordGreaterThan:
2126 case spv::OpFOrdLessThanEqual:
2127 case spv::OpFUnordLessThanEqual:
2128 case spv::OpFOrdGreaterThanEqual:
2129 case spv::OpFUnordGreaterThanEqual:
2130 case spv::OpSMod:
2131 case spv::OpSRem:
2132 case spv::OpUMod:
2133 case spv::OpIEqual:
2134 case spv::OpINotEqual:
2135 case spv::OpUGreaterThan:
2136 case spv::OpSGreaterThan:
2137 case spv::OpUGreaterThanEqual:
2138 case spv::OpSGreaterThanEqual:
2139 case spv::OpULessThan:
2140 case spv::OpSLessThan:
2141 case spv::OpULessThanEqual:
2142 case spv::OpSLessThanEqual:
2143 case spv::OpShiftRightLogical:
2144 case spv::OpShiftRightArithmetic:
2145 case spv::OpShiftLeftLogical:
2146 case spv::OpBitwiseOr:
2147 case spv::OpBitwiseXor:
2148 case spv::OpBitwiseAnd:
2149 case spv::OpLogicalOr:
2150 case spv::OpLogicalAnd:
2151 case spv::OpLogicalEqual:
2152 case spv::OpLogicalNotEqual:
2153 case spv::OpUMulExtended:
2154 case spv::OpSMulExtended:
2155 case spv::OpIAddCarry:
2156 case spv::OpISubBorrow:
2157 return EmitBinaryOp(insn);
2158
2159 case spv::OpDot:
2160 case spv::OpSDot:
2161 case spv::OpUDot:
2162 case spv::OpSUDot:
2163 case spv::OpSDotAccSat:
2164 case spv::OpUDotAccSat:
2165 case spv::OpSUDotAccSat:
2166 return EmitDot(insn);
2167
2168 case spv::OpSelect:
2169 return EmitSelect(insn);
2170
2171 case spv::OpExtInst:
2172 return EmitExtendedInstruction(insn);
2173
2174 case spv::OpAny:
2175 return EmitAny(insn);
2176
2177 case spv::OpAll:
2178 return EmitAll(insn);
2179
2180 case spv::OpPhi:
2181 return EmitPhi(insn);
2182
2183 case spv::OpSelectionMerge:
2184 case spv::OpLoopMerge:
2185 return;
2186
2187 case spv::OpFunctionCall:
2188 return EmitFunctionCall(insn);
2189
2190 case spv::OpDemoteToHelperInvocation:
2191 return EmitDemoteToHelperInvocation(insn);
2192
2193 case spv::OpIsHelperInvocationEXT:
2194 return EmitIsHelperInvocation(insn);
2195
2196 case spv::OpImageSampleImplicitLod:
2197 case spv::OpImageSampleExplicitLod:
2198 case spv::OpImageSampleDrefImplicitLod:
2199 case spv::OpImageSampleDrefExplicitLod:
2200 case spv::OpImageSampleProjImplicitLod:
2201 case spv::OpImageSampleProjExplicitLod:
2202 case spv::OpImageSampleProjDrefImplicitLod:
2203 case spv::OpImageSampleProjDrefExplicitLod:
2204 case spv::OpImageGather:
2205 case spv::OpImageDrefGather:
2206 case spv::OpImageFetch:
2207 case spv::OpImageQueryLod:
2208 return EmitImageSample(ImageInstruction(insn, shader, *this));
2209
2210 case spv::OpImageQuerySizeLod:
2211 return EmitImageQuerySizeLod(insn);
2212
2213 case spv::OpImageQuerySize:
2214 return EmitImageQuerySize(insn);
2215
2216 case spv::OpImageQueryLevels:
2217 return EmitImageQueryLevels(insn);
2218
2219 case spv::OpImageQuerySamples:
2220 return EmitImageQuerySamples(insn);
2221
2222 case spv::OpImageRead:
2223 return EmitImageRead(ImageInstruction(insn, shader, *this));
2224
2225 case spv::OpImageWrite:
2226 return EmitImageWrite(ImageInstruction(insn, shader, *this));
2227
2228 case spv::OpImageTexelPointer:
2229 return EmitImageTexelPointer(ImageInstruction(insn, shader, *this));
2230
2231 case spv::OpSampledImage:
2232 return EmitSampledImage(insn);
2233
2234 case spv::OpImage:
2235 return EmitImage(insn);
2236
2237 case spv::OpCopyObject:
2238 case spv::OpCopyLogical:
2239 return EmitCopyObject(insn);
2240
2241 case spv::OpCopyMemory:
2242 return EmitCopyMemory(insn);
2243
2244 case spv::OpControlBarrier:
2245 return EmitControlBarrier(insn);
2246
2247 case spv::OpMemoryBarrier:
2248 return EmitMemoryBarrier(insn);
2249
2250 case spv::OpGroupNonUniformElect:
2251 case spv::OpGroupNonUniformAll:
2252 case spv::OpGroupNonUniformAny:
2253 case spv::OpGroupNonUniformAllEqual:
2254 case spv::OpGroupNonUniformBroadcast:
2255 case spv::OpGroupNonUniformBroadcastFirst:
2256 case spv::OpGroupNonUniformQuadBroadcast:
2257 case spv::OpGroupNonUniformQuadSwap:
2258 case spv::OpGroupNonUniformBallot:
2259 case spv::OpGroupNonUniformInverseBallot:
2260 case spv::OpGroupNonUniformBallotBitExtract:
2261 case spv::OpGroupNonUniformBallotBitCount:
2262 case spv::OpGroupNonUniformBallotFindLSB:
2263 case spv::OpGroupNonUniformBallotFindMSB:
2264 case spv::OpGroupNonUniformShuffle:
2265 case spv::OpGroupNonUniformShuffleXor:
2266 case spv::OpGroupNonUniformShuffleUp:
2267 case spv::OpGroupNonUniformShuffleDown:
2268 case spv::OpGroupNonUniformIAdd:
2269 case spv::OpGroupNonUniformFAdd:
2270 case spv::OpGroupNonUniformIMul:
2271 case spv::OpGroupNonUniformFMul:
2272 case spv::OpGroupNonUniformSMin:
2273 case spv::OpGroupNonUniformUMin:
2274 case spv::OpGroupNonUniformFMin:
2275 case spv::OpGroupNonUniformSMax:
2276 case spv::OpGroupNonUniformUMax:
2277 case spv::OpGroupNonUniformFMax:
2278 case spv::OpGroupNonUniformBitwiseAnd:
2279 case spv::OpGroupNonUniformBitwiseOr:
2280 case spv::OpGroupNonUniformBitwiseXor:
2281 case spv::OpGroupNonUniformLogicalAnd:
2282 case spv::OpGroupNonUniformLogicalOr:
2283 case spv::OpGroupNonUniformLogicalXor:
2284 return EmitGroupNonUniform(insn);
2285
2286 case spv::OpArrayLength:
2287 return EmitArrayLength(insn);
2288
2289 default:
2290 UNREACHABLE("Unknown non-terminal instruction %s", shader.OpcodeName(opcode));
2291 break;
2292 }
2293 }
Nicolas Capens157ba262019-12-10 17:49:14 -05002294}
2295
Nicolas Capens1ab775a2022-10-12 15:27:02 -04002296void SpirvEmitter::EmitAccessChain(InsnIterator insn)
Nicolas Capens157ba262019-12-10 17:49:14 -05002297{
2298 Type::ID typeId = insn.word(1);
2299 Object::ID resultId = insn.word(2);
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04002300 bool nonUniform = shader.GetDecorationsForId(resultId).NonUniform;
Nicolas Capens157ba262019-12-10 17:49:14 -05002301 Object::ID baseId = insn.word(3);
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04002302 auto &type = shader.getType(typeId);
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002303 ASSERT(type.componentCount == 1);
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04002304 ASSERT(shader.getObject(resultId).kind == Object::Kind::Pointer);
Nicolas Capens157ba262019-12-10 17:49:14 -05002305
Alexis Hetu47c22462022-06-06 18:00:16 -04002306 Object::ID elementId = (insn.opcode() == spv::OpPtrAccessChain) ? insn.word(4) : 0;
2307 int indexId = (insn.opcode() == spv::OpPtrAccessChain) ? 5 : 4;
Sean Rissera4c2e9b2022-05-03 14:47:41 -04002308 // TODO(b/236280746): Eliminate lookahead by optimizing inside SIMD::Pointer.
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04002309 for(auto it = insn; it != shader.end(); it++)
Sean Rissera4c2e9b2022-05-03 14:47:41 -04002310 {
2311 if(it.opcode() == spv::OpLoad)
2312 {
2313 Object::ID pointerId = it.word(3);
2314 if(pointerId.value() == resultId.value())
2315 {
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04002316 nonUniform |= shader.GetDecorationsForId(it.word(2)).NonUniform;
Sean Rissera4c2e9b2022-05-03 14:47:41 -04002317 break;
2318 }
2319 }
2320 }
Alexis Hetu47c22462022-06-06 18:00:16 -04002321
Nicolas Capense6a31532022-11-28 11:35:43 -05002322 if(Spirv::IsExplicitLayout(type.storageClass))
Nicolas Capens157ba262019-12-10 17:49:14 -05002323 {
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04002324 auto ptr = WalkExplicitLayoutAccessChain(baseId, elementId, Span(insn, indexId, insn.wordCount() - indexId), nonUniform);
2325 createPointer(resultId, ptr);
Nicolas Capens157ba262019-12-10 17:49:14 -05002326 }
2327 else
2328 {
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04002329 auto ptr = WalkAccessChain(baseId, elementId, Span(insn, indexId, insn.wordCount() - indexId), nonUniform);
2330 createPointer(resultId, ptr);
Nicolas Capens157ba262019-12-10 17:49:14 -05002331 }
Nicolas Capens157ba262019-12-10 17:49:14 -05002332}
2333
Nicolas Capens1ab775a2022-10-12 15:27:02 -04002334void SpirvEmitter::EmitCompositeConstruct(InsnIterator insn)
Nicolas Capens157ba262019-12-10 17:49:14 -05002335{
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04002336 auto &type = shader.getType(insn.resultTypeId());
2337 auto &dst = createIntermediate(insn.resultId(), type.componentCount);
Nicolas Capens157ba262019-12-10 17:49:14 -05002338 auto offset = 0u;
2339
Nicolas Capens81bc9d92019-12-16 15:05:57 -05002340 for(auto i = 0u; i < insn.wordCount() - 3; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002341 {
2342 Object::ID srcObjectId = insn.word(3u + i);
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04002343 auto &srcObject = shader.getObject(srcObjectId);
2344 auto &srcObjectTy = shader.getType(srcObject);
2345 Operand srcObjectAccess(shader, *this, srcObjectId);
Nicolas Capens157ba262019-12-10 17:49:14 -05002346
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002347 for(auto j = 0u; j < srcObjectTy.componentCount; j++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002348 {
2349 dst.move(offset++, srcObjectAccess.Float(j));
2350 }
2351 }
Nicolas Capens157ba262019-12-10 17:49:14 -05002352}
2353
Nicolas Capens1ab775a2022-10-12 15:27:02 -04002354void SpirvEmitter::EmitCompositeInsert(InsnIterator insn)
Nicolas Capens157ba262019-12-10 17:49:14 -05002355{
2356 Type::ID resultTypeId = insn.word(1);
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04002357 auto &type = shader.getType(resultTypeId);
2358 auto &dst = createIntermediate(insn.resultId(), type.componentCount);
2359 auto &newPartObject = shader.getObject(insn.word(3));
2360 auto &newPartObjectTy = shader.getType(newPartObject);
2361 auto firstNewComponent = shader.WalkLiteralAccessChain(resultTypeId, Span(insn, 5, insn.wordCount() - 5));
Nicolas Capens157ba262019-12-10 17:49:14 -05002362
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04002363 Operand srcObjectAccess(shader, *this, insn.word(4));
2364 Operand newPartObjectAccess(shader, *this, insn.word(3));
Nicolas Capens157ba262019-12-10 17:49:14 -05002365
2366 // old components before
Nicolas Capens81bc9d92019-12-16 15:05:57 -05002367 for(auto i = 0u; i < firstNewComponent; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002368 {
2369 dst.move(i, srcObjectAccess.Float(i));
2370 }
2371 // new part
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002372 for(auto i = 0u; i < newPartObjectTy.componentCount; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002373 {
2374 dst.move(firstNewComponent + i, newPartObjectAccess.Float(i));
2375 }
2376 // old components after
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002377 for(auto i = firstNewComponent + newPartObjectTy.componentCount; i < type.componentCount; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002378 {
2379 dst.move(i, srcObjectAccess.Float(i));
2380 }
Nicolas Capens157ba262019-12-10 17:49:14 -05002381}
2382
Nicolas Capens1ab775a2022-10-12 15:27:02 -04002383void SpirvEmitter::EmitCompositeExtract(InsnIterator insn)
Nicolas Capens157ba262019-12-10 17:49:14 -05002384{
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04002385 auto &type = shader.getType(insn.resultTypeId());
2386 auto &dst = createIntermediate(insn.resultId(), type.componentCount);
2387 auto &compositeObject = shader.getObject(insn.word(3));
Nicolas Capens157ba262019-12-10 17:49:14 -05002388 Type::ID compositeTypeId = compositeObject.definition.word(1);
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04002389 auto firstComponent = shader.WalkLiteralAccessChain(compositeTypeId, Span(insn, 4, insn.wordCount() - 4));
Nicolas Capens157ba262019-12-10 17:49:14 -05002390
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04002391 Operand compositeObjectAccess(shader, *this, insn.word(3));
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002392 for(auto i = 0u; i < type.componentCount; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002393 {
2394 dst.move(i, compositeObjectAccess.Float(firstComponent + i));
2395 }
Nicolas Capens157ba262019-12-10 17:49:14 -05002396}
2397
Nicolas Capens1ab775a2022-10-12 15:27:02 -04002398void SpirvEmitter::EmitVectorShuffle(InsnIterator insn)
Nicolas Capens157ba262019-12-10 17:49:14 -05002399{
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04002400 // Note: number of components in result, first vector, and second vector are all independent.
2401 uint32_t resultSize = shader.getType(insn.resultTypeId()).componentCount;
2402 uint32_t firstVectorSize = shader.getObjectType(insn.word(3)).componentCount;
Nicolas Capens157ba262019-12-10 17:49:14 -05002403
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04002404 auto &result = createIntermediate(insn.resultId(), resultSize);
2405 Operand firstVector(shader, *this, insn.word(3));
2406 Operand secondVector(shader, *this, insn.word(4));
Nicolas Capens157ba262019-12-10 17:49:14 -05002407
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04002408 for(uint32_t i = 0u; i < resultSize; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002409 {
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04002410 uint32_t selector = insn.word(5 + i);
2411 if(selector == 0xFFFFFFFF) // Undefined value.
Nicolas Capens157ba262019-12-10 17:49:14 -05002412 {
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04002413 result.move(i, SIMD::Float());
Nicolas Capens157ba262019-12-10 17:49:14 -05002414 }
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04002415 else if(selector < firstVectorSize)
Nicolas Capens157ba262019-12-10 17:49:14 -05002416 {
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04002417 result.move(i, firstVector.Float(selector));
Nicolas Capens157ba262019-12-10 17:49:14 -05002418 }
2419 else
2420 {
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04002421 result.move(i, secondVector.Float(selector - firstVectorSize));
Nicolas Capens157ba262019-12-10 17:49:14 -05002422 }
2423 }
Nicolas Capens157ba262019-12-10 17:49:14 -05002424}
2425
Nicolas Capens1ab775a2022-10-12 15:27:02 -04002426void SpirvEmitter::EmitVectorExtractDynamic(InsnIterator insn)
Nicolas Capens157ba262019-12-10 17:49:14 -05002427{
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04002428 auto &type = shader.getType(insn.resultTypeId());
2429 auto &dst = createIntermediate(insn.resultId(), type.componentCount);
2430 auto &srcType = shader.getObjectType(insn.word(3));
Nicolas Capens157ba262019-12-10 17:49:14 -05002431
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04002432 Operand src(shader, *this, insn.word(3));
2433 Operand index(shader, *this, insn.word(4));
Nicolas Capens157ba262019-12-10 17:49:14 -05002434
2435 SIMD::UInt v = SIMD::UInt(0);
2436
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002437 for(auto i = 0u; i < srcType.componentCount; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002438 {
2439 v |= CmpEQ(index.UInt(0), SIMD::UInt(i)) & src.UInt(i);
2440 }
2441
2442 dst.move(0, v);
Nicolas Capens157ba262019-12-10 17:49:14 -05002443}
2444
Nicolas Capens1ab775a2022-10-12 15:27:02 -04002445void SpirvEmitter::EmitVectorInsertDynamic(InsnIterator insn)
Nicolas Capens157ba262019-12-10 17:49:14 -05002446{
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04002447 auto &type = shader.getType(insn.resultTypeId());
2448 auto &dst = createIntermediate(insn.resultId(), type.componentCount);
Nicolas Capens157ba262019-12-10 17:49:14 -05002449
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04002450 Operand src(shader, *this, insn.word(3));
2451 Operand component(shader, *this, insn.word(4));
2452 Operand index(shader, *this, insn.word(5));
Nicolas Capens157ba262019-12-10 17:49:14 -05002453
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002454 for(auto i = 0u; i < type.componentCount; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002455 {
2456 SIMD::UInt mask = CmpEQ(SIMD::UInt(i), index.UInt(0));
2457 dst.move(i, (src.UInt(i) & ~mask) | (component.UInt(0) & mask));
2458 }
Nicolas Capens157ba262019-12-10 17:49:14 -05002459}
2460
Nicolas Capens1ab775a2022-10-12 15:27:02 -04002461void SpirvEmitter::EmitSelect(InsnIterator insn)
Nicolas Capens157ba262019-12-10 17:49:14 -05002462{
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04002463 auto &type = shader.getType(insn.resultTypeId());
2464 auto result = shader.getObject(insn.resultId());
2465 auto cond = Operand(shader, *this, insn.word(3));
Nicolas Capens2f4b6032020-04-09 02:01:50 -04002466 auto condIsScalar = (cond.componentCount == 1);
Nicolas Capens157ba262019-12-10 17:49:14 -05002467
Nicolas Capensfdf41472022-09-26 00:40:11 -04002468 if(result.kind == Object::Kind::Pointer)
Nicolas Capens157ba262019-12-10 17:49:14 -05002469 {
Nicolas Capensfdf41472022-09-26 00:40:11 -04002470 ASSERT(condIsScalar);
2471 ASSERT(type.storageClass == spv::StorageClassPhysicalStorageBuffer);
2472
2473 auto &lhs = getPointer(insn.word(4));
2474 auto &rhs = getPointer(insn.word(5));
2475 createPointer(insn.resultId(), SIMD::Pointer::IfThenElse(cond.Int(0), lhs, rhs));
2476
2477 SPIRV_SHADER_DBG("{0}: {1}", insn.word(3), cond);
2478 SPIRV_SHADER_DBG("{0}: {1}", insn.word(4), lhs);
2479 SPIRV_SHADER_DBG("{0}: {1}", insn.word(5), rhs);
2480 }
2481 else
2482 {
2483 auto lhs = Operand(shader, *this, insn.word(4));
2484 auto rhs = Operand(shader, *this, insn.word(5));
2485 auto &dst = createIntermediate(insn.resultId(), type.componentCount);
2486
2487 for(auto i = 0u; i < type.componentCount; i++)
Alexis Hetuf1a62bb2022-06-07 12:29:37 -04002488 {
Nicolas Capensfdf41472022-09-26 00:40:11 -04002489 auto sel = cond.Int(condIsScalar ? 0 : i);
2490 dst.move(i, (sel & lhs.Int(i)) | (~sel & rhs.Int(i))); // TODO: IfThenElse()
Alexis Hetuf1a62bb2022-06-07 12:29:37 -04002491 }
Alexis Hetuec31f542022-06-22 16:47:48 -04002492
Nicolas Capensfdf41472022-09-26 00:40:11 -04002493 SPIRV_SHADER_DBG("{0}: {1}", insn.word(2), dst);
2494 SPIRV_SHADER_DBG("{0}: {1}", insn.word(3), cond);
2495 SPIRV_SHADER_DBG("{0}: {1}", insn.word(4), lhs);
2496 SPIRV_SHADER_DBG("{0}: {1}", insn.word(5), rhs);
Nicolas Capens157ba262019-12-10 17:49:14 -05002497 }
Nicolas Capens157ba262019-12-10 17:49:14 -05002498}
2499
Nicolas Capens1ab775a2022-10-12 15:27:02 -04002500void SpirvEmitter::EmitAny(InsnIterator insn)
Nicolas Capens157ba262019-12-10 17:49:14 -05002501{
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04002502 auto &type = shader.getType(insn.resultTypeId());
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002503 ASSERT(type.componentCount == 1);
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04002504 auto &dst = createIntermediate(insn.resultId(), type.componentCount);
2505 auto &srcType = shader.getObjectType(insn.word(3));
2506 auto src = Operand(shader, *this, insn.word(3));
Nicolas Capens157ba262019-12-10 17:49:14 -05002507
2508 SIMD::UInt result = src.UInt(0);
2509
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002510 for(auto i = 1u; i < srcType.componentCount; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002511 {
2512 result |= src.UInt(i);
2513 }
2514
2515 dst.move(0, result);
Nicolas Capens157ba262019-12-10 17:49:14 -05002516}
2517
Nicolas Capens1ab775a2022-10-12 15:27:02 -04002518void SpirvEmitter::EmitAll(InsnIterator insn)
Nicolas Capens157ba262019-12-10 17:49:14 -05002519{
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04002520 auto &type = shader.getType(insn.resultTypeId());
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002521 ASSERT(type.componentCount == 1);
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04002522 auto &dst = createIntermediate(insn.resultId(), type.componentCount);
2523 auto &srcType = shader.getObjectType(insn.word(3));
2524 auto src = Operand(shader, *this, insn.word(3));
Nicolas Capens157ba262019-12-10 17:49:14 -05002525
2526 SIMD::UInt result = src.UInt(0);
2527
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04002528 for(uint32_t i = 1; i < srcType.componentCount; i++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002529 {
2530 result &= src.UInt(i);
2531 }
2532
2533 dst.move(0, result);
Nicolas Capens157ba262019-12-10 17:49:14 -05002534}
2535
Nicolas Capens1ab775a2022-10-12 15:27:02 -04002536void SpirvEmitter::EmitAtomicOp(InsnIterator insn)
Nicolas Capens157ba262019-12-10 17:49:14 -05002537{
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04002538 auto &resultType = shader.getType(Type::ID(insn.word(1)));
Nicolas Capens157ba262019-12-10 17:49:14 -05002539 Object::ID resultId = insn.word(2);
Nicolas Capens7c84c9e2020-07-24 22:13:44 -04002540 Object::ID pointerId = insn.word(3);
Nicolas Capens157ba262019-12-10 17:49:14 -05002541 Object::ID semanticsId = insn.word(5);
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04002542 auto memorySemantics = static_cast<spv::MemorySemanticsMask>(shader.getObject(semanticsId).constantValue[0]);
Nicolas Capensfdf41472022-09-26 00:40:11 -04002543 auto memoryOrder = shader.MemoryOrder(memorySemantics);
Nicolas Capens157ba262019-12-10 17:49:14 -05002544 // Where no value is provided (increment/decrement) use an implicit value of 1.
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04002545 auto value = (insn.wordCount() == 7) ? Operand(shader, *this, insn.word(6)).UInt(0) : RValue<SIMD::UInt>(1);
2546 auto &dst = createIntermediate(resultId, resultType.componentCount);
2547 auto ptr = getPointer(pointerId);
Nicolas Capens157ba262019-12-10 17:49:14 -05002548
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04002549 SIMD::Int mask = activeLaneMask() & storesAndAtomicsMask();
Nicolas Capens7c84c9e2020-07-24 22:13:44 -04002550
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04002551 if((shader.getObject(pointerId).opcode() == spv::OpImageTexelPointer) && ptr.isBasePlusOffset)
Nicolas Capens7c84c9e2020-07-24 22:13:44 -04002552 {
2553 mask &= ptr.isInBounds(sizeof(int32_t), OutOfBoundsBehavior::Nullify);
2554 }
2555
2556 SIMD::UInt result(0);
Nicolas Capens81bc9d92019-12-16 15:05:57 -05002557 for(int j = 0; j < SIMD::Width; j++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002558 {
2559 If(Extract(mask, j) != 0)
2560 {
Nicolas Capens157ba262019-12-10 17:49:14 -05002561 auto laneValue = Extract(value, j);
2562 UInt v;
Nicolas Capens81bc9d92019-12-16 15:05:57 -05002563 switch(insn.opcode())
Nicolas Capens157ba262019-12-10 17:49:14 -05002564 {
Nicolas Capens112faf42019-12-13 17:32:26 -05002565 case spv::OpAtomicIAdd:
2566 case spv::OpAtomicIIncrement:
Sean Risseree0d0b42022-04-20 16:27:26 -04002567 v = AddAtomic(Pointer<UInt>(ptr.getPointerForLane(j)), laneValue, memoryOrder);
Nicolas Capens112faf42019-12-13 17:32:26 -05002568 break;
2569 case spv::OpAtomicISub:
2570 case spv::OpAtomicIDecrement:
Sean Risseree0d0b42022-04-20 16:27:26 -04002571 v = SubAtomic(Pointer<UInt>(ptr.getPointerForLane(j)), laneValue, memoryOrder);
Nicolas Capens112faf42019-12-13 17:32:26 -05002572 break;
2573 case spv::OpAtomicAnd:
Sean Risseree0d0b42022-04-20 16:27:26 -04002574 v = AndAtomic(Pointer<UInt>(ptr.getPointerForLane(j)), laneValue, memoryOrder);
Nicolas Capens112faf42019-12-13 17:32:26 -05002575 break;
2576 case spv::OpAtomicOr:
Sean Risseree0d0b42022-04-20 16:27:26 -04002577 v = OrAtomic(Pointer<UInt>(ptr.getPointerForLane(j)), laneValue, memoryOrder);
Nicolas Capens112faf42019-12-13 17:32:26 -05002578 break;
2579 case spv::OpAtomicXor:
Sean Risseree0d0b42022-04-20 16:27:26 -04002580 v = XorAtomic(Pointer<UInt>(ptr.getPointerForLane(j)), laneValue, memoryOrder);
Nicolas Capens112faf42019-12-13 17:32:26 -05002581 break;
2582 case spv::OpAtomicSMin:
Sean Risseree0d0b42022-04-20 16:27:26 -04002583 v = As<UInt>(MinAtomic(Pointer<Int>(ptr.getPointerForLane(j)), As<Int>(laneValue), memoryOrder));
Nicolas Capens112faf42019-12-13 17:32:26 -05002584 break;
2585 case spv::OpAtomicSMax:
Sean Risseree0d0b42022-04-20 16:27:26 -04002586 v = As<UInt>(MaxAtomic(Pointer<Int>(ptr.getPointerForLane(j)), As<Int>(laneValue), memoryOrder));
Nicolas Capens112faf42019-12-13 17:32:26 -05002587 break;
2588 case spv::OpAtomicUMin:
Sean Risseree0d0b42022-04-20 16:27:26 -04002589 v = MinAtomic(Pointer<UInt>(ptr.getPointerForLane(j)), laneValue, memoryOrder);
Nicolas Capens112faf42019-12-13 17:32:26 -05002590 break;
2591 case spv::OpAtomicUMax:
Sean Risseree0d0b42022-04-20 16:27:26 -04002592 v = MaxAtomic(Pointer<UInt>(ptr.getPointerForLane(j)), laneValue, memoryOrder);
Nicolas Capens112faf42019-12-13 17:32:26 -05002593 break;
2594 case spv::OpAtomicExchange:
Sean Risseree0d0b42022-04-20 16:27:26 -04002595 v = ExchangeAtomic(Pointer<UInt>(ptr.getPointerForLane(j)), laneValue, memoryOrder);
Nicolas Capens112faf42019-12-13 17:32:26 -05002596 break;
2597 default:
Nicolas Capensfdf41472022-09-26 00:40:11 -04002598 UNREACHABLE("%s", shader.OpcodeName(insn.opcode()));
Nicolas Capens112faf42019-12-13 17:32:26 -05002599 break;
Nicolas Capens157ba262019-12-10 17:49:14 -05002600 }
Nicolas Capens7c84c9e2020-07-24 22:13:44 -04002601 result = Insert(result, v, j);
Nicolas Capens157ba262019-12-10 17:49:14 -05002602 }
2603 }
2604
Nicolas Capens7c84c9e2020-07-24 22:13:44 -04002605 dst.move(0, result);
Nicolas Capens157ba262019-12-10 17:49:14 -05002606}
2607
Nicolas Capens1ab775a2022-10-12 15:27:02 -04002608void SpirvEmitter::EmitAtomicCompareExchange(InsnIterator insn)
Nicolas Capens157ba262019-12-10 17:49:14 -05002609{
2610 // Separate from EmitAtomicOp due to different instruction encoding
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04002611 auto &resultType = shader.getType(Type::ID(insn.word(1)));
Nicolas Capens157ba262019-12-10 17:49:14 -05002612 Object::ID resultId = insn.word(2);
2613
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04002614 auto memorySemanticsEqual = static_cast<spv::MemorySemanticsMask>(shader.getObject(insn.word(5)).constantValue[0]);
Nicolas Capensfdf41472022-09-26 00:40:11 -04002615 auto memoryOrderEqual = shader.MemoryOrder(memorySemanticsEqual);
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04002616 auto memorySemanticsUnequal = static_cast<spv::MemorySemanticsMask>(shader.getObject(insn.word(6)).constantValue[0]);
Nicolas Capensfdf41472022-09-26 00:40:11 -04002617 auto memoryOrderUnequal = shader.MemoryOrder(memorySemanticsUnequal);
Nicolas Capens157ba262019-12-10 17:49:14 -05002618
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04002619 auto value = Operand(shader, *this, insn.word(7));
2620 auto comparator = Operand(shader, *this, insn.word(8));
2621 auto &dst = createIntermediate(resultId, resultType.componentCount);
2622 auto ptr = getPointer(insn.word(3));
Nicolas Capens157ba262019-12-10 17:49:14 -05002623
2624 SIMD::UInt x(0);
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04002625 auto mask = activeLaneMask() & storesAndAtomicsMask();
Nicolas Capens81bc9d92019-12-16 15:05:57 -05002626 for(int j = 0; j < SIMD::Width; j++)
Nicolas Capens157ba262019-12-10 17:49:14 -05002627 {
2628 If(Extract(mask, j) != 0)
2629 {
Nicolas Capens157ba262019-12-10 17:49:14 -05002630 auto laneValue = Extract(value.UInt(0), j);
2631 auto laneComparator = Extract(comparator.UInt(0), j);
Sean Risseree0d0b42022-04-20 16:27:26 -04002632 UInt v = CompareExchangeAtomic(Pointer<UInt>(ptr.getPointerForLane(j)), laneValue, laneComparator, memoryOrderEqual, memoryOrderUnequal);
Nicolas Capens157ba262019-12-10 17:49:14 -05002633 x = Insert(x, v, j);
2634 }
2635 }
2636
2637 dst.move(0, x);
Nicolas Capens157ba262019-12-10 17:49:14 -05002638}
2639
Nicolas Capens1ab775a2022-10-12 15:27:02 -04002640void SpirvEmitter::EmitCopyObject(InsnIterator insn)
Nicolas Capens157ba262019-12-10 17:49:14 -05002641{
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04002642 auto src = Operand(shader, *this, insn.word(3));
Alexis Hetu150bc8c2022-08-30 12:01:15 -04002643 if(src.isPointer())
Nicolas Capens157ba262019-12-10 17:49:14 -05002644 {
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04002645 createPointer(insn.resultId(), src.Pointer());
Alexis Hetu150bc8c2022-08-30 12:01:15 -04002646 }
Alexis Hetu7c6c7b72022-09-01 17:37:49 -04002647 else if(src.isSampledImage())
2648 {
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04002649 createSampledImage(insn.resultId(), src.SampledImage());
Alexis Hetu7c6c7b72022-09-01 17:37:49 -04002650 }
Alexis Hetu150bc8c2022-08-30 12:01:15 -04002651 else
2652 {
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04002653 auto type = shader.getType(insn.resultTypeId());
2654 auto &dst = createIntermediate(insn.resultId(), type.componentCount);
Alexis Hetu150bc8c2022-08-30 12:01:15 -04002655 for(uint32_t i = 0; i < type.componentCount; i++)
2656 {
2657 dst.move(i, src.Int(i));
2658 }
Nicolas Capens157ba262019-12-10 17:49:14 -05002659 }
Nicolas Capens157ba262019-12-10 17:49:14 -05002660}
2661
Nicolas Capens1ab775a2022-10-12 15:27:02 -04002662void SpirvEmitter::EmitArrayLength(InsnIterator insn)
Nicolas Capens157ba262019-12-10 17:49:14 -05002663{
Nicolas Capens157ba262019-12-10 17:49:14 -05002664 auto structPtrId = Object::ID(insn.word(3));
2665 auto arrayFieldIdx = insn.word(4);
2666
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04002667 auto &resultType = shader.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 Capense1b8cbd2022-09-12 09:13:06 -04002671 auto &structPtrTy = shader.getObjectType(structPtrId);
2672 auto &structTy = shader.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 Capense1b8cbd2022-09-12 09:13:06 -04002675 auto &result = createIntermediate(insn.resultId(), 1);
2676 auto structBase = GetPointerToData(structPtrId, 0, false);
Nicolas Capens157ba262019-12-10 17:49:14 -05002677
Alexis Hetu74d3f372020-02-14 15:32:37 -05002678 Decorations structDecorations = {};
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04002679 shader.ApplyDecorationsForIdMember(&structDecorations, structPtrTy.element, arrayFieldIdx);
Alexis Hetu74d3f372020-02-14 15:32:37 -05002680 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 Capense1b8cbd2022-09-12 09:13:06 -04002685 Decorations arrayDecorations = shader.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));
Nicolas Capens157ba262019-12-10 17:49:14 -05002690}
2691
Nicolas Capens1ab775a2022-10-12 15:27:02 -04002692void SpirvEmitter::EmitExtendedInstruction(InsnIterator insn)
Ben Claytonb36dbbe2020-01-08 12:18:43 +00002693{
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04002694 auto ext = shader.getExtension(insn.word(3));
Ben Claytonb36dbbe2020-01-08 12:18:43 +00002695 switch(ext.name)
2696 {
Nicolas Capens71134742022-10-12 12:44:16 -04002697 case Spirv::Extension::GLSLstd450:
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04002698 return EmitExtGLSLstd450(insn);
Nicolas Capens71134742022-10-12 12:44:16 -04002699 case Spirv::Extension::NonSemanticInfo:
sugoi1cd8e0282022-02-22 15:50:46 -05002700 // An extended set name which is prefixed with "NonSemantic." is
2701 // guaranteed to contain only non-semantic instructions and all
2702 // OpExtInst instructions referencing this set can be ignored.
2703 break;
Nicolas Capens112faf42019-12-13 17:32:26 -05002704 default:
2705 UNREACHABLE("Unknown Extension::Name<%d>", int(ext.name));
Ben Claytonb36dbbe2020-01-08 12:18:43 +00002706 }
Ben Claytonb36dbbe2020-01-08 12:18:43 +00002707}
2708
Nicolas Capens71134742022-10-12 12:44:16 -04002709uint32_t Spirv::GetConstScalarInt(Object::ID id) const
Nicolas Capens157ba262019-12-10 17:49:14 -05002710{
2711 auto &scopeObj = getObject(id);
2712 ASSERT(scopeObj.kind == Object::Kind::Constant);
Nicolas Capensff9f9b52020-04-14 00:46:38 -04002713 ASSERT(getType(scopeObj).componentCount == 1);
Nicolas Capensad9acf22022-10-12 15:19:01 -04002714
Nicolas Capens157ba262019-12-10 17:49:14 -05002715 return scopeObj.constantValue[0];
2716}
2717
Nicolas Capens6beafb42022-10-12 16:11:39 -04002718void SpirvShader::emitEpilog(SpirvRoutine *routine) const
Nicolas Capens157ba262019-12-10 17:49:14 -05002719{
Nicolas Capens81bc9d92019-12-16 15:05:57 -05002720 for(auto insn : *this)
Nicolas Capens157ba262019-12-10 17:49:14 -05002721 {
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04002722 if(insn.opcode() == spv::OpVariable)
Nicolas Capens157ba262019-12-10 17:49:14 -05002723 {
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04002724 auto &object = getObject(insn.resultId());
2725 auto &objectTy = getType(object);
2726
2727 if(object.kind == Object::Kind::InterfaceVariable && objectTy.storageClass == spv::StorageClassOutput)
Nicolas Capens157ba262019-12-10 17:49:14 -05002728 {
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04002729 auto &dst = routine->getVariable(insn.resultId());
2730 int offset = 0;
2731
2732 VisitInterface(insn.resultId(),
2733 [&](const Decorations &d, AttribType type) {
2734 auto scalarSlot = d.Location << 2 | d.Component;
2735 routine->outputs[scalarSlot] = dst[offset++];
2736 });
Nicolas Capens157ba262019-12-10 17:49:14 -05002737 }
Nicolas Capens157ba262019-12-10 17:49:14 -05002738 }
2739 }
Alexis Hetu09df3eb2021-01-14 10:46:33 -05002740}
Nicolas Capens157ba262019-12-10 17:49:14 -05002741
Nicolas Capens71134742022-10-12 12:44:16 -04002742VkShaderStageFlagBits Spirv::executionModelToStage(spv::ExecutionModel model)
Nicolas Capens157ba262019-12-10 17:49:14 -05002743{
Nicolas Capens81bc9d92019-12-16 15:05:57 -05002744 switch(model)
Nicolas Capens157ba262019-12-10 17:49:14 -05002745 {
Nicolas Capens112faf42019-12-13 17:32:26 -05002746 case spv::ExecutionModelVertex: return VK_SHADER_STAGE_VERTEX_BIT;
2747 // case spv::ExecutionModelTessellationControl: return VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
2748 // case spv::ExecutionModelTessellationEvaluation: return VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
2749 // case spv::ExecutionModelGeometry: return VK_SHADER_STAGE_GEOMETRY_BIT;
2750 case spv::ExecutionModelFragment: return VK_SHADER_STAGE_FRAGMENT_BIT;
2751 case spv::ExecutionModelGLCompute: return VK_SHADER_STAGE_COMPUTE_BIT;
2752 // case spv::ExecutionModelKernel: return VkShaderStageFlagBits(0); // Not supported by vulkan.
2753 // case spv::ExecutionModelTaskNV: return VK_SHADER_STAGE_TASK_BIT_NV;
2754 // case spv::ExecutionModelMeshNV: return VK_SHADER_STAGE_MESH_BIT_NV;
2755 // case spv::ExecutionModelRayGenerationNV: return VK_SHADER_STAGE_RAYGEN_BIT_NV;
2756 // case spv::ExecutionModelIntersectionNV: return VK_SHADER_STAGE_INTERSECTION_BIT_NV;
2757 // case spv::ExecutionModelAnyHitNV: return VK_SHADER_STAGE_ANY_HIT_BIT_NV;
2758 // case spv::ExecutionModelClosestHitNV: return VK_SHADER_STAGE_CLOSEST_HIT_BIT_NV;
2759 // case spv::ExecutionModelMissNV: return VK_SHADER_STAGE_MISS_BIT_NV;
2760 // case spv::ExecutionModelCallableNV: return VK_SHADER_STAGE_CALLABLE_BIT_NV;
2761 default:
2762 UNSUPPORTED("ExecutionModel: %d", int(model));
2763 return VkShaderStageFlagBits(0);
Nicolas Capens157ba262019-12-10 17:49:14 -05002764 }
2765}
2766
Nicolas Capens71134742022-10-12 12:44:16 -04002767SpirvEmitter::Operand::Operand(const Spirv &shader, const SpirvEmitter &state, Object::ID objectId)
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04002768 : Operand(state, shader.getObject(objectId))
Ben Claytonbc1c067be2019-12-17 20:37:37 +00002769{}
Nicolas Capens157ba262019-12-10 17:49:14 -05002770
Nicolas Capens1ab775a2022-10-12 15:27:02 -04002771SpirvEmitter::Operand::Operand(const SpirvEmitter &state, const Object &object)
Nicolas Capensfdf41472022-09-26 00:40:11 -04002772 : constant(object.kind == Object::Kind::Constant ? object.constantValue.data() : nullptr)
2773 , intermediate(object.kind == Object::Kind::Intermediate ? &state.getIntermediate(object.id()) : nullptr)
2774 , pointer(object.kind == Object::Kind::Pointer ? &state.getPointer(object.id()) : nullptr)
2775 , sampledImage(object.kind == Object::Kind::SampledImage ? &state.getSampledImage(object.id()) : nullptr)
Nicolas Capens2f4b6032020-04-09 02:01:50 -04002776 , componentCount(intermediate ? intermediate->componentCount : object.constantValue.size())
2777{
Alexis Hetu7c6c7b72022-09-01 17:37:49 -04002778 ASSERT(intermediate || constant || pointer || sampledImage);
Nicolas Capens2f4b6032020-04-09 02:01:50 -04002779}
2780
Nicolas Capens1ab775a2022-10-12 15:27:02 -04002781SpirvEmitter::Operand::Operand(const Intermediate &value)
Nicolas Capense1b8cbd2022-09-12 09:13:06 -04002782 : intermediate(&value)
Nicolas Capens20220a02020-04-09 02:48:16 -04002783 , componentCount(value.componentCount)
2784{
2785}
2786
Nicolas Capens71134742022-10-12 12:44:16 -04002787bool Spirv::Object::isConstantZero() const
Nicolas Capens3c0e0582020-08-26 11:04:37 -04002788{
Nicolas Capens8dccb372021-11-11 14:24:34 -05002789 if(kind != Kind::Constant)
Nicolas Capens3c0e0582020-08-26 11:04:37 -04002790 {
2791 return false;
2792 }
2793
Nicolas Capens8dccb372021-11-11 14:24:34 -05002794 for(uint32_t i = 0; i < constantValue.size(); i++)
Nicolas Capens3c0e0582020-08-26 11:04:37 -04002795 {
Nicolas Capens8dccb372021-11-11 14:24:34 -05002796 if(constantValue[i] != 0)
Nicolas Capens3c0e0582020-08-26 11:04:37 -04002797 {
2798 return false;
2799 }
2800 }
2801
2802 return true;
2803}
2804
Nicolas Capens3d7faaa2022-10-04 14:48:57 -04002805SpirvRoutine::SpirvRoutine(const vk::PipelineLayout *pipelineLayout)
Ben Claytonbc1c067be2019-12-17 20:37:37 +00002806 : pipelineLayout(pipelineLayout)
Nicolas Capens157ba262019-12-10 17:49:14 -05002807{
2808}
2809
Nicolas Capens3d7faaa2022-10-04 14:48:57 -04002810void SpirvRoutine::setImmutableInputBuiltins(const SpirvShader *shader)
Nicolas Capens157ba262019-12-10 17:49:14 -05002811{
Nicolas Capens71134742022-10-12 12:44:16 -04002812 setInputBuiltin(shader, spv::BuiltInSubgroupLocalInvocationId, [&](const Spirv::BuiltinMapping &builtin, Array<SIMD::Float> &value) {
Nicolas Capens157ba262019-12-10 17:49:14 -05002813 ASSERT(builtin.SizeInComponents == 1);
2814 value[builtin.FirstComponent] = As<SIMD::Float>(SIMD::Int(0, 1, 2, 3));
2815 });
2816
Nicolas Capens71134742022-10-12 12:44:16 -04002817 setInputBuiltin(shader, spv::BuiltInSubgroupEqMask, [&](const Spirv::BuiltinMapping &builtin, Array<SIMD::Float> &value) {
Nicolas Capens157ba262019-12-10 17:49:14 -05002818 ASSERT(builtin.SizeInComponents == 4);
2819 value[builtin.FirstComponent + 0] = As<SIMD::Float>(SIMD::Int(1, 2, 4, 8));
2820 value[builtin.FirstComponent + 1] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2821 value[builtin.FirstComponent + 2] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2822 value[builtin.FirstComponent + 3] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2823 });
2824
Nicolas Capens71134742022-10-12 12:44:16 -04002825 setInputBuiltin(shader, spv::BuiltInSubgroupGeMask, [&](const Spirv::BuiltinMapping &builtin, Array<SIMD::Float> &value) {
Nicolas Capens157ba262019-12-10 17:49:14 -05002826 ASSERT(builtin.SizeInComponents == 4);
2827 value[builtin.FirstComponent + 0] = As<SIMD::Float>(SIMD::Int(15, 14, 12, 8));
2828 value[builtin.FirstComponent + 1] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2829 value[builtin.FirstComponent + 2] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2830 value[builtin.FirstComponent + 3] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2831 });
2832
Nicolas Capens71134742022-10-12 12:44:16 -04002833 setInputBuiltin(shader, spv::BuiltInSubgroupGtMask, [&](const Spirv::BuiltinMapping &builtin, Array<SIMD::Float> &value) {
Nicolas Capens157ba262019-12-10 17:49:14 -05002834 ASSERT(builtin.SizeInComponents == 4);
2835 value[builtin.FirstComponent + 0] = As<SIMD::Float>(SIMD::Int(14, 12, 8, 0));
2836 value[builtin.FirstComponent + 1] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2837 value[builtin.FirstComponent + 2] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2838 value[builtin.FirstComponent + 3] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2839 });
2840
Nicolas Capens71134742022-10-12 12:44:16 -04002841 setInputBuiltin(shader, spv::BuiltInSubgroupLeMask, [&](const Spirv::BuiltinMapping &builtin, Array<SIMD::Float> &value) {
Nicolas Capens157ba262019-12-10 17:49:14 -05002842 ASSERT(builtin.SizeInComponents == 4);
2843 value[builtin.FirstComponent + 0] = As<SIMD::Float>(SIMD::Int(1, 3, 7, 15));
2844 value[builtin.FirstComponent + 1] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2845 value[builtin.FirstComponent + 2] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2846 value[builtin.FirstComponent + 3] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2847 });
2848
Nicolas Capens71134742022-10-12 12:44:16 -04002849 setInputBuiltin(shader, spv::BuiltInSubgroupLtMask, [&](const Spirv::BuiltinMapping &builtin, Array<SIMD::Float> &value) {
Nicolas Capens157ba262019-12-10 17:49:14 -05002850 ASSERT(builtin.SizeInComponents == 4);
2851 value[builtin.FirstComponent + 0] = As<SIMD::Float>(SIMD::Int(0, 1, 3, 7));
2852 value[builtin.FirstComponent + 1] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2853 value[builtin.FirstComponent + 2] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2854 value[builtin.FirstComponent + 3] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2855 });
2856
Nicolas Capens71134742022-10-12 12:44:16 -04002857 setInputBuiltin(shader, spv::BuiltInDeviceIndex, [&](const Spirv::BuiltinMapping &builtin, Array<SIMD::Float> &value) {
Nicolas Capens157ba262019-12-10 17:49:14 -05002858 ASSERT(builtin.SizeInComponents == 1);
2859 // Only a single physical device is supported.
2860 value[builtin.FirstComponent] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2861 });
2862}
2863
2864} // namespace sw