xref: /aosp_15_r20/external/swiftshader/src/Pipeline/SpirvShader.cpp (revision 03ce13f70fcc45d86ee91b7ee4cab1936a95046e)
1 // 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 
15 #include "SpirvShader.hpp"
16 
17 #include "SpirvProfiler.hpp"
18 #include "SpirvShaderDebug.hpp"
19 
20 #include "Device/Context.hpp"
21 #include "System/Debug.hpp"
22 #include "Vulkan/VkPipelineLayout.hpp"
23 #include "Vulkan/VkRenderPass.hpp"
24 
25 #include "marl/defer.h"
26 
27 #include <spirv/unified1/spirv.hpp>
28 
29 namespace sw {
30 
Spirv(VkShaderStageFlagBits pipelineStage,const char * entryPointName,const SpirvBinary & insns)31 Spirv::Spirv(
32     VkShaderStageFlagBits pipelineStage,
33     const char *entryPointName,
34     const SpirvBinary &insns)
35     : insns{ insns }
36     , inputs{ MAX_INTERFACE_COMPONENTS }
37     , outputs{ MAX_INTERFACE_COMPONENTS }
38 {
39 	ASSERT(insns.size() > 0);
40 
41 	// The identifiers of all OpVariables that define the entry point's IO variables.
42 	std::unordered_set<Object::ID> interfaceIds;
43 
44 	Function::ID currentFunction;
45 	Block::ID currentBlock;
46 	InsnIterator blockStart;
47 
48 	for(auto insn : *this)
49 	{
50 		spv::Op opcode = insn.opcode();
51 
52 		switch(opcode)
53 		{
54 		case spv::OpEntryPoint:
55 			{
56 				spv::ExecutionModel executionModel = spv::ExecutionModel(insn.word(1));
57 				Function::ID entryPoint = Function::ID(insn.word(2));
58 				const char *name = insn.string(3);
59 				VkShaderStageFlagBits stage = executionModelToStage(executionModel);
60 
61 				if(stage == pipelineStage && strcmp(name, entryPointName) == 0)
62 				{
63 					ASSERT_MSG(this->entryPoint == 0, "Duplicate entry point with name '%s' and stage %d", name, int(stage));
64 					this->entryPoint = entryPoint;
65 					this->executionModel = executionModel;
66 
67 					auto interfaceIdsOffset = 3 + insn.stringSizeInWords(3);
68 					for(uint32_t i = interfaceIdsOffset; i < insn.wordCount(); i++)
69 					{
70 						interfaceIds.emplace(insn.word(i));
71 					}
72 				}
73 			}
74 			break;
75 
76 		case spv::OpExecutionMode:
77 		case spv::OpExecutionModeId:
78 			ProcessExecutionMode(insn);
79 			break;
80 
81 		case spv::OpDecorate:
82 			{
83 				TypeOrObjectID targetId = insn.word(1);
84 				auto decoration = static_cast<spv::Decoration>(insn.word(2));
85 				uint32_t value = insn.wordCount() > 3 ? insn.word(3) : 0;
86 
87 				decorations[targetId].Apply(decoration, value);
88 
89 				switch(decoration)
90 				{
91 				case spv::DecorationDescriptorSet:
92 					descriptorDecorations[targetId].DescriptorSet = value;
93 					break;
94 				case spv::DecorationBinding:
95 					descriptorDecorations[targetId].Binding = value;
96 					break;
97 				case spv::DecorationInputAttachmentIndex:
98 					descriptorDecorations[targetId].InputAttachmentIndex = value;
99 					break;
100 				case spv::DecorationSample:
101 					analysis.ContainsSampleQualifier = true;
102 					break;
103 				default:
104 					// Only handling descriptor decorations here.
105 					break;
106 				}
107 
108 				if(decoration == spv::DecorationCentroid)
109 				{
110 					analysis.NeedsCentroid = true;
111 				}
112 			}
113 			break;
114 
115 		case spv::OpMemberDecorate:
116 			{
117 				Type::ID targetId = insn.word(1);
118 				auto memberIndex = insn.word(2);
119 				auto decoration = static_cast<spv::Decoration>(insn.word(3));
120 				uint32_t value = insn.wordCount() > 4 ? insn.word(4) : 0;
121 
122 				auto &d = memberDecorations[targetId];
123 				if(memberIndex >= d.size())
124 					d.resize(memberIndex + 1);  // on demand; exact size would require another pass...
125 
126 				d[memberIndex].Apply(decoration, value);
127 
128 				if(decoration == spv::DecorationCentroid)
129 				{
130 					analysis.NeedsCentroid = true;
131 				}
132 			}
133 			break;
134 
135 		case spv::OpDecorateId:
136 			{
137 				auto decoration = static_cast<spv::Decoration>(insn.word(2));
138 
139 				// Currently OpDecorateId only supports UniformId, which provides information for
140 				// potential optimizations that we don't perform, and CounterBuffer, which is used
141 				// by HLSL to build the graphics pipeline with shader reflection. At the driver level,
142 				// the CounterBuffer decoration does nothing, so we can safely ignore both decorations.
143 				ASSERT(decoration == spv::DecorationUniformId || decoration == spv::DecorationCounterBuffer);
144 			}
145 			break;
146 
147 		case spv::OpDecorateString:
148 			{
149 				auto decoration = static_cast<spv::Decoration>(insn.word(2));
150 
151 				// We assume these are for HLSL semantics, ignore them (b/214576937).
152 				ASSERT(decoration == spv::DecorationUserSemantic || decoration == spv::DecorationUserTypeGOOGLE);
153 			}
154 			break;
155 
156 		case spv::OpMemberDecorateString:
157 			{
158 				auto decoration = static_cast<spv::Decoration>(insn.word(3));
159 
160 				// We assume these are for HLSL semantics, ignore them (b/214576937).
161 				ASSERT(decoration == spv::DecorationUserSemantic || decoration == spv::DecorationUserTypeGOOGLE);
162 			}
163 			break;
164 
165 		case spv::OpDecorationGroup:
166 			// Nothing to do here. We don't need to record the definition of the group; we'll just have
167 			// the bundle of decorations float around. If we were to ever walk the decorations directly,
168 			// we might think about introducing this as a real Object.
169 			break;
170 
171 		case spv::OpGroupDecorate:
172 			{
173 				uint32_t group = insn.word(1);
174 				const auto &groupDecorations = decorations[group];
175 				const auto &descriptorGroupDecorations = descriptorDecorations[group];
176 				for(auto i = 2u; i < insn.wordCount(); i++)
177 				{
178 					// Remaining operands are targets to apply the group to.
179 					uint32_t target = insn.word(i);
180 					decorations[target].Apply(groupDecorations);
181 					descriptorDecorations[target].Apply(descriptorGroupDecorations);
182 				}
183 			}
184 			break;
185 
186 		case spv::OpGroupMemberDecorate:
187 			{
188 				const auto &srcDecorations = decorations[insn.word(1)];
189 				for(auto i = 2u; i < insn.wordCount(); i += 2)
190 				{
191 					// remaining operands are pairs of <id>, literal for members to apply to.
192 					auto &d = memberDecorations[insn.word(i)];
193 					auto memberIndex = insn.word(i + 1);
194 					if(memberIndex >= d.size())
195 						d.resize(memberIndex + 1);  // on demand resize, see above...
196 					d[memberIndex].Apply(srcDecorations);
197 				}
198 			}
199 			break;
200 
201 		case spv::OpLabel:
202 			{
203 				ASSERT(currentBlock == 0);
204 				currentBlock = Block::ID(insn.word(1));
205 				blockStart = insn;
206 			}
207 			break;
208 
209 		// Termination instructions:
210 		case spv::OpKill:
211 		case spv::OpTerminateInvocation:
212 			analysis.ContainsDiscard = true;
213 			// [[fallthrough]]
214 
215 		case spv::OpUnreachable:
216 
217 		// Branch Instructions (subset of Termination Instructions):
218 		case spv::OpBranch:
219 		case spv::OpBranchConditional:
220 		case spv::OpSwitch:
221 		case spv::OpReturn:
222 			{
223 				ASSERT(currentBlock != 0);
224 				ASSERT(currentFunction != 0);
225 
226 				auto blockEnd = insn;
227 				blockEnd++;
228 				functions[currentFunction].blocks[currentBlock] = Block(blockStart, blockEnd);
229 				currentBlock = Block::ID(0);
230 			}
231 			break;
232 
233 		case spv::OpDemoteToHelperInvocation:
234 			analysis.ContainsDiscard = true;
235 			break;
236 
237 		case spv::OpLoopMerge:
238 		case spv::OpSelectionMerge:
239 			break;  // Nothing to do in analysis pass.
240 
241 		case spv::OpTypeVoid:
242 		case spv::OpTypeBool:
243 		case spv::OpTypeInt:
244 		case spv::OpTypeFloat:
245 		case spv::OpTypeVector:
246 		case spv::OpTypeMatrix:
247 		case spv::OpTypeImage:
248 		case spv::OpTypeSampler:
249 		case spv::OpTypeSampledImage:
250 		case spv::OpTypeArray:
251 		case spv::OpTypeRuntimeArray:
252 		case spv::OpTypeStruct:
253 		case spv::OpTypePointer:
254 		case spv::OpTypeForwardPointer:
255 		case spv::OpTypeFunction:
256 			DeclareType(insn);
257 			break;
258 
259 		case spv::OpVariable:
260 			{
261 				Type::ID typeId = insn.word(1);
262 				Object::ID resultId = insn.word(2);
263 				auto storageClass = static_cast<spv::StorageClass>(insn.word(3));
264 
265 				auto &object = defs[resultId];
266 				object.kind = Object::Kind::Pointer;
267 				object.definition = insn;
268 
269 				ASSERT(getType(typeId).definition.opcode() == spv::OpTypePointer);
270 				ASSERT(getType(typeId).storageClass == storageClass);
271 
272 				switch(storageClass)
273 				{
274 				case spv::StorageClassInput:
275 				case spv::StorageClassOutput:
276 					if(interfaceIds.count(resultId))
277 					{
278 						ProcessInterfaceVariable(object);
279 					}
280 					break;
281 
282 				case spv::StorageClassUniform:
283 				case spv::StorageClassStorageBuffer:
284 				case spv::StorageClassPhysicalStorageBuffer:
285 					object.kind = Object::Kind::DescriptorSet;
286 					break;
287 
288 				case spv::StorageClassPushConstant:
289 				case spv::StorageClassPrivate:
290 				case spv::StorageClassFunction:
291 				case spv::StorageClassUniformConstant:
292 					break;  // Correctly handled.
293 
294 				case spv::StorageClassWorkgroup:
295 					{
296 						auto &elTy = getType(getType(typeId).element);
297 						auto sizeInBytes = elTy.componentCount * static_cast<uint32_t>(sizeof(float));
298 						workgroupMemory.allocate(resultId, sizeInBytes);
299 						object.kind = Object::Kind::Pointer;
300 					}
301 					break;
302 				case spv::StorageClassAtomicCounter:
303 				case spv::StorageClassImage:
304 					UNSUPPORTED("StorageClass %d not yet supported", (int)storageClass);
305 					break;
306 
307 				case spv::StorageClassCrossWorkgroup:
308 					UNSUPPORTED("SPIR-V OpenCL Execution Model (StorageClassCrossWorkgroup)");
309 					break;
310 
311 				case spv::StorageClassGeneric:
312 					UNSUPPORTED("SPIR-V GenericPointer Capability (StorageClassGeneric)");
313 					break;
314 
315 				default:
316 					UNREACHABLE("Unexpected StorageClass %d", storageClass);  // See Appendix A of the Vulkan spec.
317 					break;
318 				}
319 			}
320 			break;
321 
322 		case spv::OpConstant:
323 		case spv::OpSpecConstant:
324 			CreateConstant(insn).constantValue[0] = insn.word(3);
325 			break;
326 		case spv::OpConstantFalse:
327 		case spv::OpSpecConstantFalse:
328 			CreateConstant(insn).constantValue[0] = 0;  // Represent Boolean false as zero.
329 			break;
330 		case spv::OpConstantTrue:
331 		case spv::OpSpecConstantTrue:
332 			CreateConstant(insn).constantValue[0] = ~0u;  // Represent Boolean true as all bits set.
333 			break;
334 		case spv::OpConstantNull:
335 		case spv::OpUndef:
336 			{
337 				// TODO: consider a real LLVM-level undef. For now, zero is a perfectly good value.
338 				// OpConstantNull forms a constant of arbitrary type, all zeros.
339 				auto &object = CreateConstant(insn);
340 				auto &objectTy = getType(object);
341 				for(auto i = 0u; i < objectTy.componentCount; i++)
342 				{
343 					object.constantValue[i] = 0;
344 				}
345 			}
346 			break;
347 		case spv::OpConstantComposite:
348 		case spv::OpSpecConstantComposite:
349 			{
350 				auto &object = CreateConstant(insn);
351 				auto offset = 0u;
352 				for(auto i = 0u; i < insn.wordCount() - 3; i++)
353 				{
354 					auto &constituent = getObject(insn.word(i + 3));
355 					auto &constituentTy = getType(constituent);
356 					for(auto j = 0u; j < constituentTy.componentCount; j++)
357 					{
358 						object.constantValue[offset++] = constituent.constantValue[j];
359 					}
360 				}
361 
362 				auto objectId = Object::ID(insn.word(2));
363 				auto decorationsIt = decorations.find(objectId);
364 				if(decorationsIt != decorations.end() &&
365 				   decorationsIt->second.BuiltIn == spv::BuiltInWorkgroupSize)
366 				{
367 					// https://www.khronos.org/registry/vulkan/specs/1.1/html/vkspec.html#interfaces-builtin-variables :
368 					// Decorating an object with the WorkgroupSize built-in
369 					// decoration will make that object contain the dimensions
370 					// of a local workgroup. If an object is decorated with the
371 					// WorkgroupSize decoration, this must take precedence over
372 					// any execution mode set for LocalSize.
373 					// The object decorated with WorkgroupSize must be declared
374 					// as a three-component vector of 32-bit integers.
375 					ASSERT(getType(object).componentCount == 3);
376 					executionModes.WorkgroupSizeX = object.constantValue[0];
377 					executionModes.WorkgroupSizeY = object.constantValue[1];
378 					executionModes.WorkgroupSizeZ = object.constantValue[2];
379 					executionModes.useWorkgroupSizeId = false;
380 				}
381 			}
382 			break;
383 		case spv::OpSpecConstantOp:
384 			EvalSpecConstantOp(insn);
385 			break;
386 
387 		case spv::OpCapability:
388 			{
389 				auto capability = static_cast<spv::Capability>(insn.word(1));
390 				switch(capability)
391 				{
392 				case spv::CapabilityMatrix: capabilities.Matrix = true; break;
393 				case spv::CapabilityShader: capabilities.Shader = true; break;
394 				case spv::CapabilityStorageImageMultisample: capabilities.StorageImageMultisample = true; break;
395 				case spv::CapabilityClipDistance: capabilities.ClipDistance = true; break;
396 				case spv::CapabilityCullDistance: capabilities.CullDistance = true; break;
397 				case spv::CapabilityImageCubeArray: capabilities.ImageCubeArray = true; break;
398 				case spv::CapabilitySampleRateShading: capabilities.SampleRateShading = true; break;
399 				case spv::CapabilityInputAttachment: capabilities.InputAttachment = true; break;
400 				case spv::CapabilitySampled1D: capabilities.Sampled1D = true; break;
401 				case spv::CapabilityImage1D: capabilities.Image1D = true; break;
402 				case spv::CapabilitySampledBuffer: capabilities.SampledBuffer = true; break;
403 				case spv::CapabilitySampledCubeArray: capabilities.SampledCubeArray = true; break;
404 				case spv::CapabilityImageBuffer: capabilities.ImageBuffer = true; break;
405 				case spv::CapabilityImageMSArray: capabilities.ImageMSArray = true; break;
406 				case spv::CapabilityStorageImageExtendedFormats: capabilities.StorageImageExtendedFormats = true; break;
407 				case spv::CapabilityImageQuery: capabilities.ImageQuery = true; break;
408 				case spv::CapabilityDerivativeControl: capabilities.DerivativeControl = true; break;
409 				case spv::CapabilityDotProductInputAll: capabilities.DotProductInputAll = true; break;
410 				case spv::CapabilityDotProductInput4x8Bit: capabilities.DotProductInput4x8Bit = true; break;
411 				case spv::CapabilityDotProductInput4x8BitPacked: capabilities.DotProductInput4x8BitPacked = true; break;
412 				case spv::CapabilityDotProduct: capabilities.DotProduct = true; break;
413 				case spv::CapabilityInterpolationFunction: capabilities.InterpolationFunction = true; break;
414 				case spv::CapabilityStorageImageWriteWithoutFormat: capabilities.StorageImageWriteWithoutFormat = true; break;
415 				case spv::CapabilityGroupNonUniform: capabilities.GroupNonUniform = true; break;
416 				case spv::CapabilityGroupNonUniformVote: capabilities.GroupNonUniformVote = true; break;
417 				case spv::CapabilityGroupNonUniformArithmetic: capabilities.GroupNonUniformArithmetic = true; break;
418 				case spv::CapabilityGroupNonUniformBallot: capabilities.GroupNonUniformBallot = true; break;
419 				case spv::CapabilityGroupNonUniformShuffle: capabilities.GroupNonUniformShuffle = true; break;
420 				case spv::CapabilityGroupNonUniformShuffleRelative: capabilities.GroupNonUniformShuffleRelative = true; break;
421 				case spv::CapabilityGroupNonUniformQuad: capabilities.GroupNonUniformQuad = true; break;
422 				case spv::CapabilityDeviceGroup: capabilities.DeviceGroup = true; break;
423 				case spv::CapabilityMultiView: capabilities.MultiView = true; break;
424 				case spv::CapabilitySignedZeroInfNanPreserve: capabilities.SignedZeroInfNanPreserve = true; break;
425 				case spv::CapabilityDemoteToHelperInvocation: capabilities.DemoteToHelperInvocation = true; break;
426 				case spv::CapabilityStencilExportEXT: capabilities.StencilExportEXT = true; break;
427 				case spv::CapabilityVulkanMemoryModel: capabilities.VulkanMemoryModel = true; break;
428 				case spv::CapabilityVulkanMemoryModelDeviceScope: capabilities.VulkanMemoryModelDeviceScope = true; break;
429 				case spv::CapabilityShaderNonUniform: capabilities.ShaderNonUniform = true; break;
430 				case spv::CapabilityRuntimeDescriptorArray: capabilities.RuntimeDescriptorArray = true; break;
431 				case spv::CapabilityStorageBufferArrayNonUniformIndexing: capabilities.StorageBufferArrayNonUniformIndexing = true; break;
432 				case spv::CapabilityStorageTexelBufferArrayNonUniformIndexing: capabilities.StorageTexelBufferArrayNonUniformIndexing = true; break;
433 				case spv::CapabilityUniformTexelBufferArrayNonUniformIndexing: capabilities.UniformTexelBufferArrayNonUniformIndexing = true; break;
434 				case spv::CapabilityUniformTexelBufferArrayDynamicIndexing: capabilities.UniformTexelBufferArrayDynamicIndexing = true; break;
435 				case spv::CapabilityStorageTexelBufferArrayDynamicIndexing: capabilities.StorageTexelBufferArrayDynamicIndexing = true; break;
436 				case spv::CapabilityUniformBufferArrayNonUniformIndexing: capabilities.UniformBufferArrayNonUniformIndex = true; break;
437 				case spv::CapabilitySampledImageArrayNonUniformIndexing: capabilities.SampledImageArrayNonUniformIndexing = true; break;
438 				case spv::CapabilityStorageImageArrayNonUniformIndexing: capabilities.StorageImageArrayNonUniformIndexing = true; break;
439 				case spv::CapabilityPhysicalStorageBufferAddresses: capabilities.PhysicalStorageBufferAddresses = true; break;
440 				default:
441 					UNSUPPORTED("Unsupported capability %u", insn.word(1));
442 				}
443 
444 				// Various capabilities will be declared, but none affect our code generation at this point.
445 			}
446 			break;
447 
448 		case spv::OpMemoryModel:
449 			{
450 				addressingModel = static_cast<spv::AddressingModel>(insn.word(1));
451 				memoryModel = static_cast<spv::MemoryModel>(insn.word(2));
452 			}
453 			break;
454 
455 		case spv::OpFunction:
456 			{
457 				auto functionId = Function::ID(insn.word(2));
458 				ASSERT_MSG(currentFunction == 0, "Functions %d and %d overlap", currentFunction.value(), functionId.value());
459 				currentFunction = functionId;
460 				auto &function = functions[functionId];
461 				function.result = Type::ID(insn.word(1));
462 				function.type = Type::ID(insn.word(4));
463 				// Scan forward to find the function's label.
464 				for(auto it = insn; it != end(); it++)
465 				{
466 					if(it.opcode() == spv::OpLabel)
467 					{
468 						function.entry = Block::ID(it.word(1));
469 						break;
470 					}
471 				}
472 				ASSERT_MSG(function.entry != 0, "Function<%d> has no label", currentFunction.value());
473 			}
474 			break;
475 
476 		case spv::OpFunctionEnd:
477 			currentFunction = 0;
478 			break;
479 
480 		case spv::OpExtInstImport:
481 			{
482 				static constexpr std::pair<const char *, Extension::Name> extensionsByName[] = {
483 					{ "GLSL.std.450", Extension::GLSLstd450 },
484 					{ "NonSemantic.", Extension::NonSemanticInfo },
485 				};
486 				static constexpr auto extensionCount = sizeof(extensionsByName) / sizeof(extensionsByName[0]);
487 
488 				auto id = Extension::ID(insn.word(1));
489 				auto name = insn.string(2);
490 				auto ext = Extension{ Extension::Unknown };
491 				for(size_t i = 0; i < extensionCount; i++)
492 				{
493 					if(0 == strncmp(name, extensionsByName[i].first, strlen(extensionsByName[i].first)))
494 					{
495 						ext = Extension{ extensionsByName[i].second };
496 						break;
497 					}
498 				}
499 				if(ext.name == Extension::Unknown)
500 				{
501 					UNSUPPORTED("SPIR-V Extension: %s", name);
502 					break;
503 				}
504 				extensionsByID.emplace(id, ext);
505 				extensionsImported.emplace(ext.name);
506 			}
507 			break;
508 		case spv::OpName:
509 		case spv::OpMemberName:
510 		case spv::OpSource:
511 		case spv::OpSourceContinued:
512 		case spv::OpSourceExtension:
513 		case spv::OpLine:
514 		case spv::OpNoLine:
515 		case spv::OpModuleProcessed:
516 			// No semantic impact
517 			break;
518 
519 		case spv::OpString:
520 			strings.emplace(insn.word(1), insn.string(2));
521 			break;
522 
523 		case spv::OpFunctionParameter:
524 			// These should have all been removed by preprocessing passes. If we see them here,
525 			// our assumptions are wrong and we will probably generate wrong code.
526 			UNREACHABLE("%s should have already been lowered.", OpcodeName(opcode));
527 			break;
528 
529 		case spv::OpFunctionCall:
530 			// TODO(b/141246700): Add full support for spv::OpFunctionCall
531 			break;
532 
533 		case spv::OpFConvert:
534 			UNSUPPORTED("SPIR-V Float16 or Float64 Capability (OpFConvert)");
535 			break;
536 
537 		case spv::OpSConvert:
538 			UNSUPPORTED("SPIR-V Int16 or Int64 Capability (OpSConvert)");
539 			break;
540 
541 		case spv::OpUConvert:
542 			UNSUPPORTED("SPIR-V Int16 or Int64 Capability (OpUConvert)");
543 			break;
544 
545 		case spv::OpLoad:
546 		case spv::OpAccessChain:
547 		case spv::OpInBoundsAccessChain:
548 		case spv::OpPtrAccessChain:
549 		case spv::OpSampledImage:
550 		case spv::OpImage:
551 		case spv::OpCopyObject:
552 		case spv::OpCopyLogical:
553 			{
554 				// Propagate the descriptor decorations to the result.
555 				Object::ID resultId = insn.word(2);
556 				Object::ID pointerId = insn.word(3);
557 				const auto &d = descriptorDecorations.find(pointerId);
558 
559 				if(d != descriptorDecorations.end())
560 				{
561 					descriptorDecorations[resultId] = d->second;
562 				}
563 
564 				DefineResult(insn);
565 
566 				if(opcode == spv::OpAccessChain || opcode == spv::OpInBoundsAccessChain || opcode == spv::OpPtrAccessChain)
567 				{
568 					int indexId = (insn.opcode() == spv::OpPtrAccessChain) ? 5 : 4;
569 					Decorations dd{};
570 					ApplyDecorationsForAccessChain(&dd, &descriptorDecorations[resultId], pointerId, Span(insn, indexId, insn.wordCount() - indexId));
571 					// Note: offset is the one thing that does *not* propagate, as the access chain accounts for it.
572 					dd.HasOffset = false;
573 					decorations[resultId].Apply(dd);
574 				}
575 			}
576 			break;
577 
578 		case spv::OpCompositeConstruct:
579 		case spv::OpCompositeInsert:
580 		case spv::OpCompositeExtract:
581 		case spv::OpVectorShuffle:
582 		case spv::OpVectorTimesScalar:
583 		case spv::OpMatrixTimesScalar:
584 		case spv::OpMatrixTimesVector:
585 		case spv::OpVectorTimesMatrix:
586 		case spv::OpMatrixTimesMatrix:
587 		case spv::OpOuterProduct:
588 		case spv::OpTranspose:
589 		case spv::OpVectorExtractDynamic:
590 		case spv::OpVectorInsertDynamic:
591 		// Unary ops
592 		case spv::OpNot:
593 		case spv::OpBitFieldInsert:
594 		case spv::OpBitFieldSExtract:
595 		case spv::OpBitFieldUExtract:
596 		case spv::OpBitReverse:
597 		case spv::OpBitCount:
598 		case spv::OpSNegate:
599 		case spv::OpFNegate:
600 		case spv::OpLogicalNot:
601 		case spv::OpQuantizeToF16:
602 		// Binary ops
603 		case spv::OpIAdd:
604 		case spv::OpISub:
605 		case spv::OpIMul:
606 		case spv::OpSDiv:
607 		case spv::OpUDiv:
608 		case spv::OpFAdd:
609 		case spv::OpFSub:
610 		case spv::OpFMul:
611 		case spv::OpFDiv:
612 		case spv::OpFMod:
613 		case spv::OpFRem:
614 		case spv::OpFOrdEqual:
615 		case spv::OpFUnordEqual:
616 		case spv::OpFOrdNotEqual:
617 		case spv::OpFUnordNotEqual:
618 		case spv::OpFOrdLessThan:
619 		case spv::OpFUnordLessThan:
620 		case spv::OpFOrdGreaterThan:
621 		case spv::OpFUnordGreaterThan:
622 		case spv::OpFOrdLessThanEqual:
623 		case spv::OpFUnordLessThanEqual:
624 		case spv::OpFOrdGreaterThanEqual:
625 		case spv::OpFUnordGreaterThanEqual:
626 		case spv::OpSMod:
627 		case spv::OpSRem:
628 		case spv::OpUMod:
629 		case spv::OpIEqual:
630 		case spv::OpINotEqual:
631 		case spv::OpUGreaterThan:
632 		case spv::OpSGreaterThan:
633 		case spv::OpUGreaterThanEqual:
634 		case spv::OpSGreaterThanEqual:
635 		case spv::OpULessThan:
636 		case spv::OpSLessThan:
637 		case spv::OpULessThanEqual:
638 		case spv::OpSLessThanEqual:
639 		case spv::OpShiftRightLogical:
640 		case spv::OpShiftRightArithmetic:
641 		case spv::OpShiftLeftLogical:
642 		case spv::OpBitwiseOr:
643 		case spv::OpBitwiseXor:
644 		case spv::OpBitwiseAnd:
645 		case spv::OpLogicalOr:
646 		case spv::OpLogicalAnd:
647 		case spv::OpLogicalEqual:
648 		case spv::OpLogicalNotEqual:
649 		case spv::OpUMulExtended:
650 		case spv::OpSMulExtended:
651 		case spv::OpIAddCarry:
652 		case spv::OpISubBorrow:
653 		case spv::OpDot:
654 		case spv::OpSDot:
655 		case spv::OpUDot:
656 		case spv::OpSUDot:
657 		case spv::OpSDotAccSat:
658 		case spv::OpUDotAccSat:
659 		case spv::OpSUDotAccSat:
660 		case spv::OpConvertFToU:
661 		case spv::OpConvertFToS:
662 		case spv::OpConvertSToF:
663 		case spv::OpConvertUToF:
664 		case spv::OpBitcast:
665 		case spv::OpSelect:
666 		case spv::OpIsInf:
667 		case spv::OpIsNan:
668 		case spv::OpAny:
669 		case spv::OpAll:
670 		case spv::OpDPdx:
671 		case spv::OpDPdxCoarse:
672 		case spv::OpDPdy:
673 		case spv::OpDPdyCoarse:
674 		case spv::OpFwidth:
675 		case spv::OpFwidthCoarse:
676 		case spv::OpDPdxFine:
677 		case spv::OpDPdyFine:
678 		case spv::OpFwidthFine:
679 		case spv::OpAtomicLoad:
680 		case spv::OpAtomicIAdd:
681 		case spv::OpAtomicISub:
682 		case spv::OpAtomicSMin:
683 		case spv::OpAtomicSMax:
684 		case spv::OpAtomicUMin:
685 		case spv::OpAtomicUMax:
686 		case spv::OpAtomicAnd:
687 		case spv::OpAtomicOr:
688 		case spv::OpAtomicXor:
689 		case spv::OpAtomicIIncrement:
690 		case spv::OpAtomicIDecrement:
691 		case spv::OpAtomicExchange:
692 		case spv::OpAtomicCompareExchange:
693 		case spv::OpPhi:
694 		case spv::OpImageSampleImplicitLod:
695 		case spv::OpImageSampleExplicitLod:
696 		case spv::OpImageSampleDrefImplicitLod:
697 		case spv::OpImageSampleDrefExplicitLod:
698 		case spv::OpImageSampleProjImplicitLod:
699 		case spv::OpImageSampleProjExplicitLod:
700 		case spv::OpImageSampleProjDrefImplicitLod:
701 		case spv::OpImageSampleProjDrefExplicitLod:
702 		case spv::OpImageGather:
703 		case spv::OpImageDrefGather:
704 		case spv::OpImageFetch:
705 		case spv::OpImageQuerySizeLod:
706 		case spv::OpImageQuerySize:
707 		case spv::OpImageQueryLod:
708 		case spv::OpImageQueryLevels:
709 		case spv::OpImageQuerySamples:
710 		case spv::OpImageRead:
711 		case spv::OpImageTexelPointer:
712 		case spv::OpGroupNonUniformElect:
713 		case spv::OpGroupNonUniformAll:
714 		case spv::OpGroupNonUniformAny:
715 		case spv::OpGroupNonUniformAllEqual:
716 		case spv::OpGroupNonUniformBroadcast:
717 		case spv::OpGroupNonUniformBroadcastFirst:
718 		case spv::OpGroupNonUniformQuadBroadcast:
719 		case spv::OpGroupNonUniformQuadSwap:
720 		case spv::OpGroupNonUniformBallot:
721 		case spv::OpGroupNonUniformInverseBallot:
722 		case spv::OpGroupNonUniformBallotBitExtract:
723 		case spv::OpGroupNonUniformBallotBitCount:
724 		case spv::OpGroupNonUniformBallotFindLSB:
725 		case spv::OpGroupNonUniformBallotFindMSB:
726 		case spv::OpGroupNonUniformShuffle:
727 		case spv::OpGroupNonUniformShuffleXor:
728 		case spv::OpGroupNonUniformShuffleUp:
729 		case spv::OpGroupNonUniformShuffleDown:
730 		case spv::OpGroupNonUniformIAdd:
731 		case spv::OpGroupNonUniformFAdd:
732 		case spv::OpGroupNonUniformIMul:
733 		case spv::OpGroupNonUniformFMul:
734 		case spv::OpGroupNonUniformSMin:
735 		case spv::OpGroupNonUniformUMin:
736 		case spv::OpGroupNonUniformFMin:
737 		case spv::OpGroupNonUniformSMax:
738 		case spv::OpGroupNonUniformUMax:
739 		case spv::OpGroupNonUniformFMax:
740 		case spv::OpGroupNonUniformBitwiseAnd:
741 		case spv::OpGroupNonUniformBitwiseOr:
742 		case spv::OpGroupNonUniformBitwiseXor:
743 		case spv::OpGroupNonUniformLogicalAnd:
744 		case spv::OpGroupNonUniformLogicalOr:
745 		case spv::OpGroupNonUniformLogicalXor:
746 		case spv::OpArrayLength:
747 		case spv::OpIsHelperInvocationEXT:
748 			// Instructions that yield an intermediate value or divergent pointer
749 			DefineResult(insn);
750 			break;
751 
752 		case spv::OpExtInst:
753 			switch(getExtension(insn.word(3)).name)
754 			{
755 			case Extension::GLSLstd450:
756 				DefineResult(insn);
757 				break;
758 			case Extension::NonSemanticInfo:
759 				// An extended set name which is prefixed with "NonSemantic." is
760 				// guaranteed to contain only non-semantic instructions and all
761 				// OpExtInst instructions referencing this set can be ignored.
762 				break;
763 			default:
764 				UNREACHABLE("Unexpected Extension name %d", int(getExtension(insn.word(3)).name));
765 				break;
766 			}
767 			break;
768 
769 		case spv::OpStore:
770 		case spv::OpAtomicStore:
771 		case spv::OpCopyMemory:
772 		case spv::OpMemoryBarrier:
773 			// Don't need to do anything during analysis pass
774 			break;
775 
776 		case spv::OpImageWrite:
777 			analysis.ContainsImageWrite = true;
778 			break;
779 
780 		case spv::OpControlBarrier:
781 			analysis.ContainsControlBarriers = true;
782 			break;
783 
784 		case spv::OpExtension:
785 			{
786 				const char *ext = insn.string(1);
787 				// Part of core SPIR-V 1.3. Vulkan 1.1 implementations must also accept the pre-1.3
788 				// extension per Appendix A, `Vulkan Environment for SPIR-V`.
789 				if(!strcmp(ext, "SPV_KHR_storage_buffer_storage_class")) break;
790 				if(!strcmp(ext, "SPV_KHR_shader_draw_parameters")) break;
791 				if(!strcmp(ext, "SPV_KHR_16bit_storage")) break;
792 				if(!strcmp(ext, "SPV_KHR_variable_pointers")) break;
793 				if(!strcmp(ext, "SPV_KHR_device_group")) break;
794 				if(!strcmp(ext, "SPV_KHR_multiview")) break;
795 				if(!strcmp(ext, "SPV_EXT_demote_to_helper_invocation")) break;
796 				if(!strcmp(ext, "SPV_KHR_terminate_invocation")) break;
797 				if(!strcmp(ext, "SPV_EXT_shader_stencil_export")) break;
798 				if(!strcmp(ext, "SPV_KHR_float_controls")) break;
799 				if(!strcmp(ext, "SPV_KHR_integer_dot_product")) break;
800 				if(!strcmp(ext, "SPV_KHR_non_semantic_info")) break;
801 				if(!strcmp(ext, "SPV_KHR_physical_storage_buffer")) break;
802 				if(!strcmp(ext, "SPV_KHR_vulkan_memory_model")) break;
803 				if(!strcmp(ext, "SPV_GOOGLE_decorate_string")) break;
804 				if(!strcmp(ext, "SPV_GOOGLE_hlsl_functionality1")) break;
805 				if(!strcmp(ext, "SPV_GOOGLE_user_type")) break;
806 				if(!strcmp(ext, "SPV_EXT_descriptor_indexing")) break;
807 				UNSUPPORTED("SPIR-V Extension: %s", ext);
808 			}
809 			break;
810 
811 		default:
812 			UNSUPPORTED("%s", OpcodeName(opcode));
813 		}
814 	}
815 
816 	ASSERT_MSG(entryPoint != 0, "Entry point '%s' not found", entryPointName);
817 	for(auto &it : functions)
818 	{
819 		it.second.AssignBlockFields();
820 	}
821 
822 #ifdef SPIRV_SHADER_CFG_GRAPHVIZ_DOT_FILEPATH
823 	{
824 		char path[1024];
825 		snprintf(path, sizeof(path), SPIRV_SHADER_CFG_GRAPHVIZ_DOT_FILEPATH, codeSerialID);
826 		WriteCFGGraphVizDotFile(path);
827 	}
828 #endif
829 }
830 
~Spirv()831 Spirv::~Spirv()
832 {
833 }
834 
DeclareType(InsnIterator insn)835 void Spirv::DeclareType(InsnIterator insn)
836 {
837 	Type::ID resultId = insn.word(1);
838 
839 	auto &type = types[resultId];
840 	type.definition = insn;
841 	type.componentCount = ComputeTypeSize(insn);
842 
843 	// A structure is a builtin block if it has a builtin
844 	// member. All members of such a structure are builtins.
845 	spv::Op opcode = insn.opcode();
846 	switch(opcode)
847 	{
848 	case spv::OpTypeStruct:
849 		{
850 			auto d = memberDecorations.find(resultId);
851 			if(d != memberDecorations.end())
852 			{
853 				for(auto &m : d->second)
854 				{
855 					if(m.HasBuiltIn)
856 					{
857 						type.isBuiltInBlock = true;
858 						break;
859 					}
860 				}
861 			}
862 		}
863 		break;
864 	case spv::OpTypePointer:
865 	case spv::OpTypeForwardPointer:
866 		{
867 			Type::ID elementTypeId = insn.word((opcode == spv::OpTypeForwardPointer) ? 1 : 3);
868 			type.element = elementTypeId;
869 			type.isBuiltInBlock = getType(elementTypeId).isBuiltInBlock;
870 			type.storageClass = static_cast<spv::StorageClass>(insn.word(2));
871 		}
872 		break;
873 	case spv::OpTypeVector:
874 	case spv::OpTypeMatrix:
875 	case spv::OpTypeArray:
876 	case spv::OpTypeRuntimeArray:
877 		{
878 			Type::ID elementTypeId = insn.word(2);
879 			type.element = elementTypeId;
880 		}
881 		break;
882 	default:
883 		break;
884 	}
885 }
886 
CreateConstant(InsnIterator insn)887 Spirv::Object &Spirv::CreateConstant(InsnIterator insn)
888 {
889 	Type::ID typeId = insn.word(1);
890 	Object::ID resultId = insn.word(2);
891 	auto &object = defs[resultId];
892 	auto &objectTy = getType(typeId);
893 	object.kind = Object::Kind::Constant;
894 	object.definition = insn;
895 	object.constantValue.resize(objectTy.componentCount);
896 
897 	return object;
898 }
899 
ProcessInterfaceVariable(Object & object)900 void Spirv::ProcessInterfaceVariable(Object &object)
901 {
902 	auto &objectTy = getType(object);
903 	ASSERT(objectTy.storageClass == spv::StorageClassInput || objectTy.storageClass == spv::StorageClassOutput);
904 
905 	ASSERT(objectTy.opcode() == spv::OpTypePointer);
906 	auto pointeeTy = getType(objectTy.element);
907 
908 	auto &builtinInterface = (objectTy.storageClass == spv::StorageClassInput) ? inputBuiltins : outputBuiltins;
909 	auto &userDefinedInterface = (objectTy.storageClass == spv::StorageClassInput) ? inputs : outputs;
910 
911 	ASSERT(object.opcode() == spv::OpVariable);
912 	Object::ID resultId = object.definition.word(2);
913 
914 	if(objectTy.isBuiltInBlock)
915 	{
916 		// Walk the builtin block, registering each of its members separately.
917 		auto m = memberDecorations.find(objectTy.element);
918 		ASSERT(m != memberDecorations.end());  // Otherwise we wouldn't have marked the type chain
919 		auto &structType = pointeeTy.definition;
920 		auto memberIndex = 0u;
921 		auto offset = 0u;
922 
923 		for(auto &member : m->second)
924 		{
925 			auto &memberType = getType(structType.word(2 + memberIndex));
926 
927 			if(member.HasBuiltIn)
928 			{
929 				builtinInterface[member.BuiltIn] = { resultId, offset, memberType.componentCount };
930 			}
931 
932 			offset += memberType.componentCount;
933 			++memberIndex;
934 		}
935 
936 		return;
937 	}
938 
939 	auto d = decorations.find(resultId);
940 	if(d != decorations.end() && d->second.HasBuiltIn)
941 	{
942 		builtinInterface[d->second.BuiltIn] = { resultId, 0, pointeeTy.componentCount };
943 	}
944 	else
945 	{
946 		object.kind = Object::Kind::InterfaceVariable;
947 		VisitInterface(resultId,
948 		               [&userDefinedInterface](const Decorations &d, AttribType type) {
949 			               // Populate a single scalar slot in the interface from a collection of decorations and the intended component type.
950 			               int32_t scalarSlot = (d.Location << 2) | d.Component;
951 			               ASSERT(scalarSlot >= 0 &&
952 			                      scalarSlot < static_cast<int32_t>(userDefinedInterface.size()));
953 
954 			               auto &slot = userDefinedInterface[scalarSlot];
955 			               slot.Type = type;
956 			               slot.Flat = d.Flat;
957 			               slot.NoPerspective = d.NoPerspective;
958 			               slot.Centroid = d.Centroid;
959 		               });
960 	}
961 }
962 
GetNumInputComponents(int32_t location) const963 uint32_t Spirv::GetNumInputComponents(int32_t location) const
964 {
965 	ASSERT(location >= 0);
966 
967 	// Verify how many component(s) per input
968 	// 1 to 4, for float, vec2, vec3, vec4.
969 	// Note that matrices are divided over multiple inputs
970 	uint32_t num_components_per_input = 0;
971 	for(; num_components_per_input < 4; ++num_components_per_input)
972 	{
973 		if(inputs[(location << 2) | num_components_per_input].Type == ATTRIBTYPE_UNUSED)
974 		{
975 			break;
976 		}
977 	}
978 
979 	return num_components_per_input;
980 }
981 
GetPackedInterpolant(int32_t location) const982 uint32_t Spirv::GetPackedInterpolant(int32_t location) const
983 {
984 	ASSERT(location >= 0);
985 	const uint32_t maxInterpolant = (location << 2);
986 
987 	// Return the number of used components only at location
988 	uint32_t packedInterpolant = 0;
989 	for(uint32_t i = 0; i < maxInterpolant; ++i)
990 	{
991 		if(inputs[i].Type != ATTRIBTYPE_UNUSED)
992 		{
993 			++packedInterpolant;
994 		}
995 	}
996 
997 	return packedInterpolant;
998 }
999 
ProcessExecutionMode(InsnIterator insn)1000 void Spirv::ProcessExecutionMode(InsnIterator insn)
1001 {
1002 	Function::ID function = insn.word(1);
1003 	if(function != entryPoint)
1004 	{
1005 		return;
1006 	}
1007 
1008 	auto mode = static_cast<spv::ExecutionMode>(insn.word(2));
1009 	switch(mode)
1010 	{
1011 	case spv::ExecutionModeEarlyFragmentTests:
1012 		executionModes.EarlyFragmentTests = true;
1013 		break;
1014 	case spv::ExecutionModeDepthReplacing:
1015 		executionModes.DepthReplacing = true;
1016 		break;
1017 	case spv::ExecutionModeDepthGreater:
1018 		// TODO(b/177915067): Can be used to optimize depth test, currently unused.
1019 		executionModes.DepthGreater = true;
1020 		break;
1021 	case spv::ExecutionModeDepthLess:
1022 		// TODO(b/177915067): Can be used to optimize depth test, currently unused.
1023 		executionModes.DepthLess = true;
1024 		break;
1025 	case spv::ExecutionModeDepthUnchanged:
1026 		// TODO(b/177915067): Can be used to optimize depth test, currently unused.
1027 		executionModes.DepthUnchanged = true;
1028 		break;
1029 	case spv::ExecutionModeStencilRefReplacingEXT:
1030 		executionModes.StencilRefReplacing = true;
1031 		break;
1032 	case spv::ExecutionModeLocalSize:
1033 	case spv::ExecutionModeLocalSizeId:
1034 		executionModes.WorkgroupSizeX = insn.word(3);
1035 		executionModes.WorkgroupSizeY = insn.word(4);
1036 		executionModes.WorkgroupSizeZ = insn.word(5);
1037 		executionModes.useWorkgroupSizeId = (mode == spv::ExecutionModeLocalSizeId);
1038 		break;
1039 	case spv::ExecutionModeOriginUpperLeft:
1040 		// This is always the case for a Vulkan shader. Do nothing.
1041 		break;
1042 	case spv::ExecutionModeSignedZeroInfNanPreserve:
1043 		// We currently don't perform any aggressive fast-math optimizations.
1044 		break;
1045 	default:
1046 		UNREACHABLE("Execution mode: %d", int(mode));
1047 	}
1048 }
1049 
getWorkgroupSizeX() const1050 uint32_t Spirv::getWorkgroupSizeX() const
1051 {
1052 	return executionModes.useWorkgroupSizeId ? getObject(executionModes.WorkgroupSizeX).constantValue[0] : executionModes.WorkgroupSizeX.value();
1053 }
1054 
getWorkgroupSizeY() const1055 uint32_t Spirv::getWorkgroupSizeY() const
1056 {
1057 	return executionModes.useWorkgroupSizeId ? getObject(executionModes.WorkgroupSizeY).constantValue[0] : executionModes.WorkgroupSizeY.value();
1058 }
1059 
getWorkgroupSizeZ() const1060 uint32_t Spirv::getWorkgroupSizeZ() const
1061 {
1062 	return executionModes.useWorkgroupSizeId ? getObject(executionModes.WorkgroupSizeZ).constantValue[0] : executionModes.WorkgroupSizeZ.value();
1063 }
1064 
ComputeTypeSize(InsnIterator insn)1065 uint32_t Spirv::ComputeTypeSize(InsnIterator insn)
1066 {
1067 	// Types are always built from the bottom up (with the exception of forward ptrs, which
1068 	// don't appear in Vulkan shaders. Therefore, we can always assume our component parts have
1069 	// already been described (and so their sizes determined)
1070 	switch(insn.opcode())
1071 	{
1072 	case spv::OpTypeVoid:
1073 	case spv::OpTypeSampler:
1074 	case spv::OpTypeImage:
1075 	case spv::OpTypeSampledImage:
1076 	case spv::OpTypeForwardPointer:
1077 	case spv::OpTypeFunction:
1078 	case spv::OpTypeRuntimeArray:
1079 		// Objects that don't consume any space.
1080 		// Descriptor-backed objects currently only need exist at compile-time.
1081 		// Runtime arrays don't appear in places where their size would be interesting
1082 		return 0;
1083 
1084 	case spv::OpTypeBool:
1085 	case spv::OpTypeFloat:
1086 	case spv::OpTypeInt:
1087 		// All the fundamental types are 1 component. If we ever add support for 8/16/64-bit components,
1088 		// we might need to change this, but only 32 bit components are required for Vulkan 1.1.
1089 		return 1;
1090 
1091 	case spv::OpTypeVector:
1092 	case spv::OpTypeMatrix:
1093 		// Vectors and matrices both consume element count * element size.
1094 		return getType(insn.word(2)).componentCount * insn.word(3);
1095 
1096 	case spv::OpTypeArray:
1097 		{
1098 			// Element count * element size. Array sizes come from constant ids.
1099 			auto arraySize = GetConstScalarInt(insn.word(3));
1100 			return getType(insn.word(2)).componentCount * arraySize;
1101 		}
1102 
1103 	case spv::OpTypeStruct:
1104 		{
1105 			uint32_t size = 0;
1106 			for(uint32_t i = 2u; i < insn.wordCount(); i++)
1107 			{
1108 				size += getType(insn.word(i)).componentCount;
1109 			}
1110 			return size;
1111 		}
1112 
1113 	case spv::OpTypePointer:
1114 		// Runtime representation of a pointer is a per-lane index.
1115 		// Note: clients are expected to look through the pointer if they want the pointee size instead.
1116 		return 1;
1117 
1118 	default:
1119 		UNREACHABLE("%s", OpcodeName(insn.opcode()));
1120 		return 0;
1121 	}
1122 }
1123 
VisitInterfaceInner(Type::ID id,Decorations d,const InterfaceVisitor & f) const1124 int Spirv::VisitInterfaceInner(Type::ID id, Decorations d, const InterfaceVisitor &f) const
1125 {
1126 	// Recursively walks variable definition and its type tree, taking into account
1127 	// any explicit Location or Component decorations encountered; where explicit
1128 	// Locations or Components are not specified, assigns them sequentially.
1129 	// Collected decorations are carried down toward the leaves and across
1130 	// siblings; Effect of decorations intentionally does not flow back up the tree.
1131 	//
1132 	// F is a functor to be called with the effective decoration set for every component.
1133 	//
1134 	// Returns the next available location, and calls f().
1135 
1136 	// This covers the rules in Vulkan 1.1 spec, 14.1.4 Location Assignment.
1137 
1138 	ApplyDecorationsForId(&d, id);
1139 
1140 	const auto &obj = getType(id);
1141 	switch(obj.opcode())
1142 	{
1143 	case spv::OpTypePointer:
1144 		return VisitInterfaceInner(obj.definition.word(3), d, f);
1145 	case spv::OpTypeMatrix:
1146 		for(auto i = 0u; i < obj.definition.word(3); i++, d.Location++)
1147 		{
1148 			// consumes same components of N consecutive locations
1149 			VisitInterfaceInner(obj.definition.word(2), d, f);
1150 		}
1151 		return d.Location;
1152 	case spv::OpTypeVector:
1153 		for(auto i = 0u; i < obj.definition.word(3); i++, d.Component++)
1154 		{
1155 			// consumes N consecutive components in the same location
1156 			VisitInterfaceInner(obj.definition.word(2), d, f);
1157 		}
1158 		return d.Location + 1;
1159 	case spv::OpTypeFloat:
1160 		f(d, ATTRIBTYPE_FLOAT);
1161 		return d.Location + 1;
1162 	case spv::OpTypeInt:
1163 		f(d, obj.definition.word(3) ? ATTRIBTYPE_INT : ATTRIBTYPE_UINT);
1164 		return d.Location + 1;
1165 	case spv::OpTypeBool:
1166 		f(d, ATTRIBTYPE_UINT);
1167 		return d.Location + 1;
1168 	case spv::OpTypeStruct:
1169 		{
1170 			// iterate over members, which may themselves have Location/Component decorations
1171 			for(auto i = 0u; i < obj.definition.wordCount() - 2; i++)
1172 			{
1173 				Decorations dMember = d;
1174 				ApplyDecorationsForIdMember(&dMember, id, i);
1175 				d.Location = VisitInterfaceInner(obj.definition.word(i + 2), dMember, f);
1176 				d.Component = 0;  // Implicit locations always have component=0
1177 			}
1178 			return d.Location;
1179 		}
1180 	case spv::OpTypeArray:
1181 		{
1182 			auto arraySize = GetConstScalarInt(obj.definition.word(3));
1183 			for(auto i = 0u; i < arraySize; i++)
1184 			{
1185 				d.Location = VisitInterfaceInner(obj.definition.word(2), d, f);
1186 			}
1187 			return d.Location;
1188 		}
1189 	default:
1190 		// Intentionally partial; most opcodes do not participate in type hierarchies
1191 		return 0;
1192 	}
1193 }
1194 
VisitInterface(Object::ID id,const InterfaceVisitor & f) const1195 void Spirv::VisitInterface(Object::ID id, const InterfaceVisitor &f) const
1196 {
1197 	// Walk a variable definition and call f for each component in it.
1198 	Decorations d = GetDecorationsForId(id);
1199 
1200 	auto def = getObject(id).definition;
1201 	ASSERT(def.opcode() == spv::OpVariable);
1202 	VisitInterfaceInner(def.word(1), d, f);
1203 }
1204 
ApplyDecorationsForAccessChain(Decorations * d,DescriptorDecorations * dd,Object::ID baseId,const Span & indexIds) const1205 void Spirv::ApplyDecorationsForAccessChain(Decorations *d, DescriptorDecorations *dd, Object::ID baseId, const Span &indexIds) const
1206 {
1207 	ApplyDecorationsForId(d, baseId);
1208 	auto &baseObject = getObject(baseId);
1209 	ApplyDecorationsForId(d, baseObject.typeId());
1210 	auto typeId = getType(baseObject).element;
1211 
1212 	for(uint32_t i = 0; i < indexIds.size(); i++)
1213 	{
1214 		ApplyDecorationsForId(d, typeId);
1215 		auto &type = getType(typeId);
1216 		switch(type.opcode())
1217 		{
1218 		case spv::OpTypeStruct:
1219 			{
1220 				int memberIndex = GetConstScalarInt(indexIds[i]);
1221 				ApplyDecorationsForIdMember(d, typeId, memberIndex);
1222 				typeId = type.definition.word(2u + memberIndex);
1223 			}
1224 			break;
1225 		case spv::OpTypeArray:
1226 		case spv::OpTypeRuntimeArray:
1227 			if(dd->InputAttachmentIndex >= 0)
1228 			{
1229 				dd->InputAttachmentIndex += GetConstScalarInt(indexIds[i]);
1230 			}
1231 			typeId = type.element;
1232 			break;
1233 		case spv::OpTypeVector:
1234 			typeId = type.element;
1235 			break;
1236 		case spv::OpTypeMatrix:
1237 			typeId = type.element;
1238 			d->InsideMatrix = true;
1239 			break;
1240 		default:
1241 			UNREACHABLE("%s", OpcodeName(type.definition.opcode()));
1242 		}
1243 	}
1244 }
1245 
WalkExplicitLayoutAccessChain(Object::ID baseId,Object::ID elementId,const Span & indexIds,bool nonUniform) const1246 SIMD::Pointer SpirvEmitter::WalkExplicitLayoutAccessChain(Object::ID baseId, Object::ID elementId, const Span &indexIds, bool nonUniform) const
1247 {
1248 	// Produce a offset into external memory in sizeof(float) units
1249 
1250 	auto &baseObject = shader.getObject(baseId);
1251 	Type::ID typeId = shader.getType(baseObject).element;
1252 	Decorations d = shader.GetDecorationsForId(baseObject.typeId());
1253 	SIMD::Int arrayIndex = 0;
1254 
1255 	uint32_t start = 0;
1256 	if(baseObject.kind == Object::Kind::DescriptorSet)
1257 	{
1258 		auto type = shader.getType(typeId).definition.opcode();
1259 		if(type == spv::OpTypeArray || type == spv::OpTypeRuntimeArray)
1260 		{
1261 			auto &obj = shader.getObject(indexIds[0]);
1262 			ASSERT(obj.kind == Object::Kind::Constant || obj.kind == Object::Kind::Intermediate);
1263 			if(obj.kind == Object::Kind::Constant)
1264 			{
1265 				arrayIndex = shader.GetConstScalarInt(indexIds[0]);
1266 			}
1267 			else
1268 			{
1269 				nonUniform |= shader.GetDecorationsForId(indexIds[0]).NonUniform;
1270 				arrayIndex = getIntermediate(indexIds[0]).Int(0);
1271 			}
1272 
1273 			start = 1;
1274 			typeId = shader.getType(typeId).element;
1275 		}
1276 	}
1277 
1278 	auto ptr = GetPointerToData(baseId, arrayIndex, nonUniform);
1279 	OffsetToElement(ptr, elementId, d.ArrayStride);
1280 
1281 	int constantOffset = 0;
1282 
1283 	for(uint32_t i = start; i < indexIds.size(); i++)
1284 	{
1285 		auto &type = shader.getType(typeId);
1286 		shader.ApplyDecorationsForId(&d, typeId);
1287 
1288 		switch(type.definition.opcode())
1289 		{
1290 		case spv::OpTypeStruct:
1291 			{
1292 				int memberIndex = shader.GetConstScalarInt(indexIds[i]);
1293 				shader.ApplyDecorationsForIdMember(&d, typeId, memberIndex);
1294 				ASSERT(d.HasOffset);
1295 				constantOffset += d.Offset;
1296 				typeId = type.definition.word(2u + memberIndex);
1297 			}
1298 			break;
1299 		case spv::OpTypeArray:
1300 		case spv::OpTypeRuntimeArray:
1301 			{
1302 				// TODO: b/127950082: Check bounds.
1303 				ASSERT(d.HasArrayStride);
1304 				auto &obj = shader.getObject(indexIds[i]);
1305 				if(obj.kind == Object::Kind::Constant)
1306 				{
1307 					constantOffset += d.ArrayStride * shader.GetConstScalarInt(indexIds[i]);
1308 				}
1309 				else
1310 				{
1311 					ptr += SIMD::Int(d.ArrayStride) * getIntermediate(indexIds[i]).Int(0);
1312 				}
1313 				typeId = type.element;
1314 			}
1315 			break;
1316 		case spv::OpTypeMatrix:
1317 			{
1318 				// TODO: b/127950082: Check bounds.
1319 				ASSERT(d.HasMatrixStride);
1320 				d.InsideMatrix = true;
1321 				auto columnStride = (d.HasRowMajor && d.RowMajor) ? static_cast<int32_t>(sizeof(float)) : d.MatrixStride;
1322 				auto &obj = shader.getObject(indexIds[i]);
1323 				if(obj.kind == Object::Kind::Constant)
1324 				{
1325 					constantOffset += columnStride * shader.GetConstScalarInt(indexIds[i]);
1326 				}
1327 				else
1328 				{
1329 					ptr += SIMD::Int(columnStride) * getIntermediate(indexIds[i]).Int(0);
1330 				}
1331 				typeId = type.element;
1332 			}
1333 			break;
1334 		case spv::OpTypeVector:
1335 			{
1336 				auto elemStride = (d.InsideMatrix && d.HasRowMajor && d.RowMajor) ? d.MatrixStride : static_cast<int32_t>(sizeof(float));
1337 				auto &obj = shader.getObject(indexIds[i]);
1338 				if(obj.kind == Object::Kind::Constant)
1339 				{
1340 					constantOffset += elemStride * shader.GetConstScalarInt(indexIds[i]);
1341 				}
1342 				else
1343 				{
1344 					ptr += SIMD::Int(elemStride) * getIntermediate(indexIds[i]).Int(0);
1345 				}
1346 				typeId = type.element;
1347 			}
1348 			break;
1349 		default:
1350 			UNREACHABLE("%s", shader.OpcodeName(type.definition.opcode()));
1351 		}
1352 	}
1353 
1354 	ptr += constantOffset;
1355 	return ptr;
1356 }
1357 
WalkAccessChain(Object::ID baseId,Object::ID elementId,const Span & indexIds,bool nonUniform) const1358 SIMD::Pointer SpirvEmitter::WalkAccessChain(Object::ID baseId, Object::ID elementId, const Span &indexIds, bool nonUniform) const
1359 {
1360 	// TODO: avoid doing per-lane work in some cases if we can?
1361 	auto &baseObject = shader.getObject(baseId);
1362 	Type::ID typeId = shader.getType(baseObject).element;
1363 	Decorations d = shader.GetDecorationsForId(baseObject.typeId());
1364 	auto storageClass = shader.getType(baseObject).storageClass;
1365 	bool interleavedByLane = IsStorageInterleavedByLane(storageClass);
1366 
1367 	auto ptr = getPointer(baseId);
1368 	OffsetToElement(ptr, elementId, d.ArrayStride);
1369 
1370 	int constantOffset = 0;
1371 
1372 	for(uint32_t i = 0; i < indexIds.size(); i++)
1373 	{
1374 		auto &type = shader.getType(typeId);
1375 		switch(type.opcode())
1376 		{
1377 		case spv::OpTypeStruct:
1378 			{
1379 				int memberIndex = shader.GetConstScalarInt(indexIds[i]);
1380 				int offsetIntoStruct = 0;
1381 				for(auto j = 0; j < memberIndex; j++)
1382 				{
1383 					auto memberType = type.definition.word(2u + j);
1384 					offsetIntoStruct += shader.getType(memberType).componentCount * sizeof(float);
1385 				}
1386 				constantOffset += offsetIntoStruct;
1387 				typeId = type.definition.word(2u + memberIndex);
1388 			}
1389 			break;
1390 
1391 		case spv::OpTypeVector:
1392 		case spv::OpTypeMatrix:
1393 		case spv::OpTypeArray:
1394 		case spv::OpTypeRuntimeArray:
1395 			{
1396 				// TODO(b/127950082): Check bounds.
1397 				if(storageClass == spv::StorageClassUniformConstant)
1398 				{
1399 					// indexing into an array of descriptors.
1400 					auto d = shader.descriptorDecorations.at(baseId);
1401 					ASSERT(d.DescriptorSet >= 0);
1402 					ASSERT(d.Binding >= 0);
1403 					uint32_t descriptorSize = routine->pipelineLayout->getDescriptorSize(d.DescriptorSet, d.Binding);
1404 
1405 					auto &obj = shader.getObject(indexIds[i]);
1406 					if(obj.kind == Object::Kind::Constant)
1407 					{
1408 						ptr += descriptorSize * shader.GetConstScalarInt(indexIds[i]);
1409 					}
1410 					else
1411 					{
1412 						nonUniform |= shader.GetDecorationsForId(indexIds[i]).NonUniform;
1413 						SIMD::Int intermediate = getIntermediate(indexIds[i]).Int(0);
1414 						if(nonUniform)
1415 						{
1416 							// NonUniform array data can deal with pointers not bound by a 32-bit address
1417 							// space, so we need to ensure we're using an array pointer, and not a base+offset
1418 							// pointer.
1419 							std::vector<Pointer<Byte>> pointers(SIMD::Width);
1420 							for(int i = 0; i < SIMD::Width; i++)
1421 							{
1422 								pointers[i] = ptr.getPointerForLane(i);
1423 							}
1424 							ptr = SIMD::Pointer(pointers);
1425 							ptr += descriptorSize * intermediate;
1426 						}
1427 						else
1428 						{
1429 							ptr += descriptorSize * Extract(intermediate, 0);
1430 						}
1431 					}
1432 				}
1433 				else
1434 				{
1435 					auto stride = shader.getType(type.element).componentCount * static_cast<uint32_t>(sizeof(float));
1436 
1437 					if(interleavedByLane)
1438 					{
1439 						stride *= SIMD::Width;
1440 					}
1441 
1442 					if(shader.getObject(indexIds[i]).kind == Object::Kind::Constant)
1443 					{
1444 						ptr += stride * shader.GetConstScalarInt(indexIds[i]);
1445 					}
1446 					else
1447 					{
1448 						ptr += SIMD::Int(stride) * getIntermediate(indexIds[i]).Int(0);
1449 					}
1450 				}
1451 				typeId = type.element;
1452 			}
1453 			break;
1454 
1455 		default:
1456 			UNREACHABLE("%s", shader.OpcodeName(type.opcode()));
1457 		}
1458 	}
1459 
1460 	if(constantOffset != 0)
1461 	{
1462 		if(interleavedByLane)
1463 		{
1464 			constantOffset *= SIMD::Width;
1465 		}
1466 
1467 		ptr += constantOffset;
1468 	}
1469 
1470 	return ptr;
1471 }
1472 
WalkLiteralAccessChain(Type::ID typeId,const Span & indexes) const1473 uint32_t Spirv::WalkLiteralAccessChain(Type::ID typeId, const Span &indexes) const
1474 {
1475 	uint32_t componentOffset = 0;
1476 
1477 	for(uint32_t i = 0; i < indexes.size(); i++)
1478 	{
1479 		auto &type = getType(typeId);
1480 		switch(type.opcode())
1481 		{
1482 		case spv::OpTypeStruct:
1483 			{
1484 				int memberIndex = indexes[i];
1485 				int offsetIntoStruct = 0;
1486 				for(auto j = 0; j < memberIndex; j++)
1487 				{
1488 					auto memberType = type.definition.word(2u + j);
1489 					offsetIntoStruct += getType(memberType).componentCount;
1490 				}
1491 				componentOffset += offsetIntoStruct;
1492 				typeId = type.definition.word(2u + memberIndex);
1493 			}
1494 			break;
1495 
1496 		case spv::OpTypeVector:
1497 		case spv::OpTypeMatrix:
1498 		case spv::OpTypeArray:
1499 			{
1500 				auto elementType = type.definition.word(2);
1501 				auto stride = getType(elementType).componentCount;
1502 				componentOffset += stride * indexes[i];
1503 				typeId = elementType;
1504 			}
1505 			break;
1506 
1507 		default:
1508 			UNREACHABLE("%s", OpcodeName(type.opcode()));
1509 		}
1510 	}
1511 
1512 	return componentOffset;
1513 }
1514 
Apply(spv::Decoration decoration,uint32_t arg)1515 void Spirv::Decorations::Apply(spv::Decoration decoration, uint32_t arg)
1516 {
1517 	switch(decoration)
1518 	{
1519 	case spv::DecorationLocation:
1520 		HasLocation = true;
1521 		Location = static_cast<int32_t>(arg);
1522 		break;
1523 	case spv::DecorationComponent:
1524 		HasComponent = true;
1525 		Component = arg;
1526 		break;
1527 	case spv::DecorationBuiltIn:
1528 		HasBuiltIn = true;
1529 		BuiltIn = static_cast<spv::BuiltIn>(arg);
1530 		break;
1531 	case spv::DecorationFlat:
1532 		Flat = true;
1533 		break;
1534 	case spv::DecorationNoPerspective:
1535 		NoPerspective = true;
1536 		break;
1537 	case spv::DecorationCentroid:
1538 		Centroid = true;
1539 		break;
1540 	case spv::DecorationBlock:
1541 		Block = true;
1542 		break;
1543 	case spv::DecorationBufferBlock:
1544 		BufferBlock = true;
1545 		break;
1546 	case spv::DecorationOffset:
1547 		HasOffset = true;
1548 		Offset = static_cast<int32_t>(arg);
1549 		break;
1550 	case spv::DecorationArrayStride:
1551 		HasArrayStride = true;
1552 		ArrayStride = static_cast<int32_t>(arg);
1553 		break;
1554 	case spv::DecorationMatrixStride:
1555 		HasMatrixStride = true;
1556 		MatrixStride = static_cast<int32_t>(arg);
1557 		break;
1558 	case spv::DecorationRelaxedPrecision:
1559 		RelaxedPrecision = true;
1560 		break;
1561 	case spv::DecorationRowMajor:
1562 		HasRowMajor = true;
1563 		RowMajor = true;
1564 		break;
1565 	case spv::DecorationColMajor:
1566 		HasRowMajor = true;
1567 		RowMajor = false;
1568 		break;
1569 	case spv::DecorationNonUniform:
1570 		NonUniform = true;
1571 		break;
1572 	default:
1573 		// Intentionally partial, there are many decorations we just don't care about.
1574 		break;
1575 	}
1576 }
1577 
Apply(const Decorations & src)1578 void Spirv::Decorations::Apply(const Decorations &src)
1579 {
1580 	// Apply a decoration group to this set of decorations
1581 	if(src.HasBuiltIn)
1582 	{
1583 		HasBuiltIn = true;
1584 		BuiltIn = src.BuiltIn;
1585 	}
1586 
1587 	if(src.HasLocation)
1588 	{
1589 		HasLocation = true;
1590 		Location = src.Location;
1591 	}
1592 
1593 	if(src.HasComponent)
1594 	{
1595 		HasComponent = true;
1596 		Component = src.Component;
1597 	}
1598 
1599 	if(src.HasOffset)
1600 	{
1601 		HasOffset = true;
1602 		Offset = src.Offset;
1603 	}
1604 
1605 	if(src.HasArrayStride)
1606 	{
1607 		HasArrayStride = true;
1608 		ArrayStride = src.ArrayStride;
1609 	}
1610 
1611 	if(src.HasMatrixStride)
1612 	{
1613 		HasMatrixStride = true;
1614 		MatrixStride = src.MatrixStride;
1615 	}
1616 
1617 	if(src.HasRowMajor)
1618 	{
1619 		HasRowMajor = true;
1620 		RowMajor = src.RowMajor;
1621 	}
1622 
1623 	Flat |= src.Flat;
1624 	NoPerspective |= src.NoPerspective;
1625 	Centroid |= src.Centroid;
1626 	Block |= src.Block;
1627 	BufferBlock |= src.BufferBlock;
1628 	RelaxedPrecision |= src.RelaxedPrecision;
1629 	InsideMatrix |= src.InsideMatrix;
1630 	NonUniform |= src.NonUniform;
1631 }
1632 
Apply(const sw::Spirv::DescriptorDecorations & src)1633 void Spirv::DescriptorDecorations::Apply(const sw::Spirv::DescriptorDecorations &src)
1634 {
1635 	if(src.DescriptorSet >= 0)
1636 	{
1637 		DescriptorSet = src.DescriptorSet;
1638 	}
1639 
1640 	if(src.Binding >= 0)
1641 	{
1642 		Binding = src.Binding;
1643 	}
1644 
1645 	if(src.InputAttachmentIndex >= 0)
1646 	{
1647 		InputAttachmentIndex = src.InputAttachmentIndex;
1648 	}
1649 }
1650 
GetDecorationsForId(TypeOrObjectID id) const1651 Spirv::Decorations Spirv::GetDecorationsForId(TypeOrObjectID id) const
1652 {
1653 	Decorations d;
1654 	ApplyDecorationsForId(&d, id);
1655 
1656 	return d;
1657 }
1658 
ApplyDecorationsForId(Decorations * d,TypeOrObjectID id) const1659 void Spirv::ApplyDecorationsForId(Decorations *d, TypeOrObjectID id) const
1660 {
1661 	auto it = decorations.find(id);
1662 	if(it != decorations.end())
1663 	{
1664 		d->Apply(it->second);
1665 	}
1666 }
1667 
ApplyDecorationsForIdMember(Decorations * d,Type::ID id,uint32_t member) const1668 void Spirv::ApplyDecorationsForIdMember(Decorations *d, Type::ID id, uint32_t member) const
1669 {
1670 	auto it = memberDecorations.find(id);
1671 	if(it != memberDecorations.end() && member < it->second.size())
1672 	{
1673 		d->Apply(it->second[member]);
1674 	}
1675 }
1676 
DefineResult(const InsnIterator & insn)1677 void Spirv::DefineResult(const InsnIterator &insn)
1678 {
1679 	Type::ID typeId = insn.word(1);
1680 	Object::ID resultId = insn.word(2);
1681 	auto &object = defs[resultId];
1682 
1683 	switch(getType(typeId).opcode())
1684 	{
1685 	case spv::OpTypeSampledImage:
1686 		object.kind = Object::Kind::SampledImage;
1687 		break;
1688 
1689 	case spv::OpTypePointer:
1690 	case spv::OpTypeImage:
1691 	case spv::OpTypeSampler:
1692 		object.kind = Object::Kind::Pointer;
1693 		break;
1694 
1695 	default:
1696 		object.kind = Object::Kind::Intermediate;
1697 	}
1698 
1699 	object.definition = insn;
1700 }
1701 
getOutOfBoundsBehavior(Object::ID pointerId,const vk::PipelineLayout * pipelineLayout) const1702 OutOfBoundsBehavior SpirvShader::getOutOfBoundsBehavior(Object::ID pointerId, const vk::PipelineLayout *pipelineLayout) const
1703 {
1704 	auto it = descriptorDecorations.find(pointerId);
1705 	if(it != descriptorDecorations.end())
1706 	{
1707 		const auto &d = it->second;
1708 		if((d.DescriptorSet >= 0) && (d.Binding >= 0))
1709 		{
1710 			auto descriptorType = pipelineLayout->getDescriptorType(d.DescriptorSet, d.Binding);
1711 			if(descriptorType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT)
1712 			{
1713 				return OutOfBoundsBehavior::UndefinedBehavior;
1714 			}
1715 		}
1716 	}
1717 
1718 	auto &pointer = getObject(pointerId);
1719 	auto &pointerTy = getType(pointer);
1720 	switch(pointerTy.storageClass)
1721 	{
1722 	case spv::StorageClassUniform:
1723 	case spv::StorageClassStorageBuffer:
1724 		// Buffer resource access. robustBufferAccess feature applies.
1725 		return robustBufferAccess ? OutOfBoundsBehavior::RobustBufferAccess
1726 		                          : OutOfBoundsBehavior::UndefinedBehavior;
1727 
1728 	case spv::StorageClassPhysicalStorageBuffer:
1729 		return OutOfBoundsBehavior::UndefinedBehavior;
1730 
1731 	case spv::StorageClassImage:
1732 		// VK_EXT_image_robustness requires nullifying out-of-bounds accesses.
1733 		// TODO(b/162327166): Only perform bounds checks when VK_EXT_image_robustness is enabled.
1734 		return OutOfBoundsBehavior::Nullify;
1735 
1736 	case spv::StorageClassInput:
1737 		if(executionModel == spv::ExecutionModelVertex)
1738 		{
1739 			// Vertex attributes follow robustBufferAccess rules.
1740 			return robustBufferAccess ? OutOfBoundsBehavior::RobustBufferAccess
1741 			                          : OutOfBoundsBehavior::UndefinedBehavior;
1742 		}
1743 		// Fall through to default case.
1744 	default:
1745 		// TODO(b/192310780): StorageClassFunction out-of-bounds accesses are undefined behavior.
1746 		// TODO(b/137183137): Optimize if the pointer resulted from OpInBoundsAccessChain.
1747 		// TODO(b/131224163): Optimize cases statically known to be within bounds.
1748 		return OutOfBoundsBehavior::UndefinedValue;
1749 	}
1750 
1751 	return OutOfBoundsBehavior::Nullify;
1752 }
1753 
getInputAttachmentFormat(const vk::Attachments & attachments,int32_t index) const1754 vk::Format SpirvShader::getInputAttachmentFormat(const vk::Attachments &attachments, int32_t index) const
1755 {
1756 	if(isUsedWithDynamicRendering)
1757 	{
1758 		// If no index is given in the shader, it refers to the depth/stencil
1759 		// attachment.
1760 		if(index < 0 || index == depthInputIndex || index == stencilInputIndex)
1761 		{
1762 			return attachments.depthStencilFormat();
1763 		}
1764 
1765 		// See if the input index is mapped to an attachment.  If it isn't, the
1766 		// mapping is identity.
1767 		int32_t attachmentIndex = index;
1768 		if(inputIndexToColorIndex.count(index) > 0)
1769 		{
1770 			attachmentIndex = inputIndexToColorIndex.at(index);
1771 		}
1772 
1773 		// Map the index to its location.  This is where read-only input attachments
1774 		// that aren't mapped to any color attachment cannot be supported the way
1775 		// SwiftShader currently works (see comment above `inputIndexToColorIndex`).
1776 		ASSERT(attachmentIndex >= 0 && attachmentIndex < sw::MAX_COLOR_BUFFERS);
1777 		const int32_t location = attachments.indexToLocation[attachmentIndex];
1778 
1779 		return attachments.colorFormat(location);
1780 	}
1781 
1782 	return inputAttachmentFormats[index];
1783 }
1784 
1785 // emit-time
1786 
emitProlog(SpirvRoutine * routine) const1787 void SpirvShader::emitProlog(SpirvRoutine *routine) const
1788 {
1789 	for(auto insn : *this)
1790 	{
1791 		switch(insn.opcode())
1792 		{
1793 		case spv::OpVariable:
1794 			{
1795 				auto resultPointerType = getType(insn.resultTypeId());
1796 				auto pointeeType = getType(resultPointerType.element);
1797 
1798 				if(pointeeType.componentCount > 0)
1799 				{
1800 					routine->createVariable(insn.resultId(), pointeeType.componentCount);
1801 				}
1802 			}
1803 			break;
1804 
1805 		case spv::OpImageSampleImplicitLod:
1806 		case spv::OpImageSampleExplicitLod:
1807 		case spv::OpImageSampleDrefImplicitLod:
1808 		case spv::OpImageSampleDrefExplicitLod:
1809 		case spv::OpImageSampleProjImplicitLod:
1810 		case spv::OpImageSampleProjExplicitLod:
1811 		case spv::OpImageSampleProjDrefImplicitLod:
1812 		case spv::OpImageSampleProjDrefExplicitLod:
1813 		case spv::OpImageFetch:
1814 		case spv::OpImageGather:
1815 		case spv::OpImageDrefGather:
1816 		case spv::OpImageWrite:
1817 		case spv::OpImageQueryLod:
1818 			{
1819 				// The 'inline' sampler caches must be created in the prolog to initialize the tags.
1820 				uint32_t instructionPosition = insn.distanceFrom(this->begin());
1821 				routine->samplerCache.emplace(instructionPosition, SpirvRoutine::SamplerCache{});
1822 			}
1823 			break;
1824 
1825 		default:
1826 			// Nothing else produces interface variables, so can all be safely ignored.
1827 			break;
1828 		}
1829 	}
1830 }
1831 
emit(SpirvRoutine * routine,const RValue<SIMD::Int> & activeLaneMask,const RValue<SIMD::Int> & storesAndAtomicsMask,const vk::DescriptorSet::Bindings & descriptorSets,const vk::Attachments * attachments,unsigned int multiSampleCount) const1832 void SpirvShader::emit(SpirvRoutine *routine, const RValue<SIMD::Int> &activeLaneMask, const RValue<SIMD::Int> &storesAndAtomicsMask, const vk::DescriptorSet::Bindings &descriptorSets, const vk::Attachments *attachments, unsigned int multiSampleCount) const
1833 {
1834 	SpirvEmitter::emit(*this, routine, entryPoint, activeLaneMask, storesAndAtomicsMask, attachments, descriptorSets, multiSampleCount);
1835 }
1836 
SpirvShader(VkShaderStageFlagBits stage,const char * entryPointName,const SpirvBinary & insns,const vk::RenderPass * renderPass,uint32_t subpassIndex,const VkRenderingInputAttachmentIndexInfoKHR * inputAttachmentMapping,bool robustBufferAccess)1837 SpirvShader::SpirvShader(VkShaderStageFlagBits stage,
1838                          const char *entryPointName,
1839                          const SpirvBinary &insns,
1840                          const vk::RenderPass *renderPass,
1841                          uint32_t subpassIndex,
1842                          const VkRenderingInputAttachmentIndexInfoKHR *inputAttachmentMapping,
1843                          bool robustBufferAccess)
1844     : Spirv(stage, entryPointName, insns)
1845     , robustBufferAccess(robustBufferAccess)
1846     , isUsedWithDynamicRendering(renderPass == nullptr)
1847 {
1848 	if(renderPass)
1849 	{
1850 		// capture formats of any input attachments present
1851 		auto subpass = renderPass->getSubpass(subpassIndex);
1852 		inputAttachmentFormats.reserve(subpass.inputAttachmentCount);
1853 		for(auto i = 0u; i < subpass.inputAttachmentCount; i++)
1854 		{
1855 			auto attachmentIndex = subpass.pInputAttachments[i].attachment;
1856 			inputAttachmentFormats.push_back(attachmentIndex != VK_ATTACHMENT_UNUSED
1857 			                                     ? renderPass->getAttachment(attachmentIndex).format
1858 			                                     : VK_FORMAT_UNDEFINED);
1859 		}
1860 	}
1861 	else if(inputAttachmentMapping)
1862 	{
1863 		for(auto i = 0u; i < inputAttachmentMapping->colorAttachmentCount; i++)
1864 		{
1865 			auto inputIndex = inputAttachmentMapping->pColorAttachmentInputIndices != nullptr ? inputAttachmentMapping->pColorAttachmentInputIndices[i] : i;
1866 			if(inputIndex != VK_ATTACHMENT_UNUSED)
1867 			{
1868 				inputIndexToColorIndex[inputIndex] = i;
1869 			}
1870 		}
1871 
1872 		if(inputAttachmentMapping->pDepthInputAttachmentIndex)
1873 		{
1874 			auto attachmentIndex = *inputAttachmentMapping->pDepthInputAttachmentIndex;
1875 			if(attachmentIndex != VK_ATTACHMENT_UNUSED)
1876 			{
1877 				depthInputIndex = attachmentIndex;
1878 			}
1879 		}
1880 
1881 		if(inputAttachmentMapping->pStencilInputAttachmentIndex)
1882 		{
1883 			auto attachmentIndex = *inputAttachmentMapping->pStencilInputAttachmentIndex;
1884 			if(attachmentIndex != VK_ATTACHMENT_UNUSED)
1885 			{
1886 				stencilInputIndex = attachmentIndex;
1887 			}
1888 		}
1889 	}
1890 }
1891 
~SpirvShader()1892 SpirvShader::~SpirvShader()
1893 {
1894 }
1895 
SpirvEmitter(const SpirvShader & shader,SpirvRoutine * routine,Spirv::Function::ID entryPoint,RValue<SIMD::Int> activeLaneMask,RValue<SIMD::Int> storesAndAtomicsMask,const vk::Attachments * attachments,const vk::DescriptorSet::Bindings & descriptorSets,unsigned int multiSampleCount)1896 SpirvEmitter::SpirvEmitter(const SpirvShader &shader,
1897                            SpirvRoutine *routine,
1898                            Spirv::Function::ID entryPoint,
1899                            RValue<SIMD::Int> activeLaneMask,
1900                            RValue<SIMD::Int> storesAndAtomicsMask,
1901                            const vk::Attachments *attachments,
1902                            const vk::DescriptorSet::Bindings &descriptorSets,
1903                            unsigned int multiSampleCount)
1904     : shader(shader)
1905     , routine(routine)
1906     , function(entryPoint)
1907     , activeLaneMaskValue(activeLaneMask.value())
1908     , storesAndAtomicsMaskValue(storesAndAtomicsMask.value())
1909     , attachments(attachments)
1910     , descriptorSets(descriptorSets)
1911     , multiSampleCount(multiSampleCount)
1912 {
1913 }
1914 
emit(const SpirvShader & shader,SpirvRoutine * routine,Spirv::Function::ID entryPoint,RValue<SIMD::Int> activeLaneMask,RValue<SIMD::Int> storesAndAtomicsMask,const vk::Attachments * attachments,const vk::DescriptorSet::Bindings & descriptorSets,unsigned int multiSampleCount)1915 void SpirvEmitter::emit(const SpirvShader &shader,
1916                         SpirvRoutine *routine,
1917                         Spirv::Function::ID entryPoint,
1918                         RValue<SIMD::Int> activeLaneMask,
1919                         RValue<SIMD::Int> storesAndAtomicsMask,
1920                         const vk::Attachments *attachments,
1921                         const vk::DescriptorSet::Bindings &descriptorSets,
1922                         unsigned int multiSampleCount)
1923 {
1924 	SpirvEmitter state(shader, routine, entryPoint, activeLaneMask, storesAndAtomicsMask, attachments, descriptorSets, multiSampleCount);
1925 
1926 	// Create phi variables
1927 	for(auto insn : shader)
1928 	{
1929 		if(insn.opcode() == spv::OpPhi)
1930 		{
1931 			auto type = shader.getType(insn.resultTypeId());
1932 			state.phis.emplace(insn.resultId(), std::vector<SIMD::Float>(type.componentCount));
1933 		}
1934 	}
1935 
1936 	// Emit everything up to the first label
1937 	// TODO: Separate out dispatch of block from non-block instructions?
1938 	for(auto insn : shader)
1939 	{
1940 		if(insn.opcode() == spv::OpLabel)
1941 		{
1942 			break;
1943 		}
1944 
1945 		state.EmitInstruction(insn);
1946 	}
1947 
1948 	// Emit all the blocks starting from entryPoint.
1949 	state.EmitBlocks(shader.getFunction(entryPoint).entry);
1950 }
1951 
EmitInstructions(InsnIterator begin,InsnIterator end)1952 void SpirvEmitter::EmitInstructions(InsnIterator begin, InsnIterator end)
1953 {
1954 	for(auto insn = begin; insn != end; insn++)
1955 	{
1956 		EmitInstruction(insn);
1957 
1958 		if(shader.IsTerminator(insn.opcode()))
1959 		{
1960 			break;
1961 		}
1962 	}
1963 }
1964 
EmitInstruction(InsnIterator insn)1965 void SpirvEmitter::EmitInstruction(InsnIterator insn)
1966 {
1967 	auto opcode = insn.opcode();
1968 
1969 #if SPIRV_SHADER_ENABLE_DBG
1970 	{
1971 		auto text = spvtools::spvInstructionBinaryToText(
1972 		    vk::SPIRV_VERSION,
1973 		    insn.data(),
1974 		    insn.wordCount(),
1975 		    shader.insns.data(),
1976 		    shader.insns.size(),
1977 		    SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
1978 		SPIRV_SHADER_DBG("{0}", text);
1979 	}
1980 #endif  // ENABLE_DBG_MSGS
1981 
1982 	if(shader.IsTerminator(opcode))
1983 	{
1984 		switch(opcode)
1985 		{
1986 		case spv::OpBranch:
1987 			return EmitBranch(insn);
1988 
1989 		case spv::OpBranchConditional:
1990 			return EmitBranchConditional(insn);
1991 
1992 		case spv::OpSwitch:
1993 			return EmitSwitch(insn);
1994 
1995 		case spv::OpUnreachable:
1996 			return EmitUnreachable(insn);
1997 
1998 		case spv::OpReturn:
1999 			return EmitReturn(insn);
2000 
2001 		case spv::OpKill:
2002 		case spv::OpTerminateInvocation:
2003 			return EmitTerminateInvocation(insn);
2004 
2005 		default:
2006 			UNREACHABLE("Unknown terminal instruction %s", shader.OpcodeName(opcode));
2007 			break;
2008 		}
2009 	}
2010 	else  // Non-terminal instructions
2011 	{
2012 		switch(opcode)
2013 		{
2014 		case spv::OpTypeVoid:
2015 		case spv::OpTypeInt:
2016 		case spv::OpTypeFloat:
2017 		case spv::OpTypeBool:
2018 		case spv::OpTypeVector:
2019 		case spv::OpTypeArray:
2020 		case spv::OpTypeRuntimeArray:
2021 		case spv::OpTypeMatrix:
2022 		case spv::OpTypeStruct:
2023 		case spv::OpTypePointer:
2024 		case spv::OpTypeForwardPointer:
2025 		case spv::OpTypeFunction:
2026 		case spv::OpTypeImage:
2027 		case spv::OpTypeSampledImage:
2028 		case spv::OpTypeSampler:
2029 		case spv::OpExecutionMode:
2030 		case spv::OpExecutionModeId:
2031 		case spv::OpMemoryModel:
2032 		case spv::OpFunction:
2033 		case spv::OpFunctionEnd:
2034 		case spv::OpConstant:
2035 		case spv::OpConstantNull:
2036 		case spv::OpConstantTrue:
2037 		case spv::OpConstantFalse:
2038 		case spv::OpConstantComposite:
2039 		case spv::OpSpecConstant:
2040 		case spv::OpSpecConstantTrue:
2041 		case spv::OpSpecConstantFalse:
2042 		case spv::OpSpecConstantComposite:
2043 		case spv::OpSpecConstantOp:
2044 		case spv::OpUndef:
2045 		case spv::OpExtension:
2046 		case spv::OpCapability:
2047 		case spv::OpEntryPoint:
2048 		case spv::OpExtInstImport:
2049 		case spv::OpDecorate:
2050 		case spv::OpMemberDecorate:
2051 		case spv::OpGroupDecorate:
2052 		case spv::OpGroupMemberDecorate:
2053 		case spv::OpDecorationGroup:
2054 		case spv::OpDecorateId:
2055 		case spv::OpDecorateString:
2056 		case spv::OpMemberDecorateString:
2057 		case spv::OpName:
2058 		case spv::OpMemberName:
2059 		case spv::OpSource:
2060 		case spv::OpSourceContinued:
2061 		case spv::OpSourceExtension:
2062 		case spv::OpNoLine:
2063 		case spv::OpModuleProcessed:
2064 		case spv::OpString:
2065 			// Nothing to do at emit time. These are either fully handled at analysis time,
2066 			// or don't require any work at all.
2067 			return;
2068 
2069 		case spv::OpLine:
2070 			return;  // TODO(b/251802301)
2071 
2072 		case spv::OpLabel:
2073 			return;
2074 
2075 		case spv::OpVariable:
2076 			return EmitVariable(insn);
2077 
2078 		case spv::OpLoad:
2079 		case spv::OpAtomicLoad:
2080 			return EmitLoad(insn);
2081 
2082 		case spv::OpStore:
2083 		case spv::OpAtomicStore:
2084 			return EmitStore(insn);
2085 
2086 		case spv::OpAtomicIAdd:
2087 		case spv::OpAtomicISub:
2088 		case spv::OpAtomicSMin:
2089 		case spv::OpAtomicSMax:
2090 		case spv::OpAtomicUMin:
2091 		case spv::OpAtomicUMax:
2092 		case spv::OpAtomicAnd:
2093 		case spv::OpAtomicOr:
2094 		case spv::OpAtomicXor:
2095 		case spv::OpAtomicIIncrement:
2096 		case spv::OpAtomicIDecrement:
2097 		case spv::OpAtomicExchange:
2098 			return EmitAtomicOp(insn);
2099 
2100 		case spv::OpAtomicCompareExchange:
2101 			return EmitAtomicCompareExchange(insn);
2102 
2103 		case spv::OpAccessChain:
2104 		case spv::OpInBoundsAccessChain:
2105 		case spv::OpPtrAccessChain:
2106 			return EmitAccessChain(insn);
2107 
2108 		case spv::OpCompositeConstruct:
2109 			return EmitCompositeConstruct(insn);
2110 
2111 		case spv::OpCompositeInsert:
2112 			return EmitCompositeInsert(insn);
2113 
2114 		case spv::OpCompositeExtract:
2115 			return EmitCompositeExtract(insn);
2116 
2117 		case spv::OpVectorShuffle:
2118 			return EmitVectorShuffle(insn);
2119 
2120 		case spv::OpVectorExtractDynamic:
2121 			return EmitVectorExtractDynamic(insn);
2122 
2123 		case spv::OpVectorInsertDynamic:
2124 			return EmitVectorInsertDynamic(insn);
2125 
2126 		case spv::OpVectorTimesScalar:
2127 		case spv::OpMatrixTimesScalar:
2128 			return EmitVectorTimesScalar(insn);
2129 
2130 		case spv::OpMatrixTimesVector:
2131 			return EmitMatrixTimesVector(insn);
2132 
2133 		case spv::OpVectorTimesMatrix:
2134 			return EmitVectorTimesMatrix(insn);
2135 
2136 		case spv::OpMatrixTimesMatrix:
2137 			return EmitMatrixTimesMatrix(insn);
2138 
2139 		case spv::OpOuterProduct:
2140 			return EmitOuterProduct(insn);
2141 
2142 		case spv::OpTranspose:
2143 			return EmitTranspose(insn);
2144 
2145 		case spv::OpNot:
2146 		case spv::OpBitFieldInsert:
2147 		case spv::OpBitFieldSExtract:
2148 		case spv::OpBitFieldUExtract:
2149 		case spv::OpBitReverse:
2150 		case spv::OpBitCount:
2151 		case spv::OpSNegate:
2152 		case spv::OpFNegate:
2153 		case spv::OpLogicalNot:
2154 		case spv::OpConvertFToU:
2155 		case spv::OpConvertFToS:
2156 		case spv::OpConvertSToF:
2157 		case spv::OpConvertUToF:
2158 		case spv::OpBitcast:
2159 		case spv::OpIsInf:
2160 		case spv::OpIsNan:
2161 		case spv::OpDPdx:
2162 		case spv::OpDPdxCoarse:
2163 		case spv::OpDPdy:
2164 		case spv::OpDPdyCoarse:
2165 		case spv::OpFwidth:
2166 		case spv::OpFwidthCoarse:
2167 		case spv::OpDPdxFine:
2168 		case spv::OpDPdyFine:
2169 		case spv::OpFwidthFine:
2170 		case spv::OpQuantizeToF16:
2171 			return EmitUnaryOp(insn);
2172 
2173 		case spv::OpIAdd:
2174 		case spv::OpISub:
2175 		case spv::OpIMul:
2176 		case spv::OpSDiv:
2177 		case spv::OpUDiv:
2178 		case spv::OpFAdd:
2179 		case spv::OpFSub:
2180 		case spv::OpFMul:
2181 		case spv::OpFDiv:
2182 		case spv::OpFMod:
2183 		case spv::OpFRem:
2184 		case spv::OpFOrdEqual:
2185 		case spv::OpFUnordEqual:
2186 		case spv::OpFOrdNotEqual:
2187 		case spv::OpFUnordNotEqual:
2188 		case spv::OpFOrdLessThan:
2189 		case spv::OpFUnordLessThan:
2190 		case spv::OpFOrdGreaterThan:
2191 		case spv::OpFUnordGreaterThan:
2192 		case spv::OpFOrdLessThanEqual:
2193 		case spv::OpFUnordLessThanEqual:
2194 		case spv::OpFOrdGreaterThanEqual:
2195 		case spv::OpFUnordGreaterThanEqual:
2196 		case spv::OpSMod:
2197 		case spv::OpSRem:
2198 		case spv::OpUMod:
2199 		case spv::OpIEqual:
2200 		case spv::OpINotEqual:
2201 		case spv::OpUGreaterThan:
2202 		case spv::OpSGreaterThan:
2203 		case spv::OpUGreaterThanEqual:
2204 		case spv::OpSGreaterThanEqual:
2205 		case spv::OpULessThan:
2206 		case spv::OpSLessThan:
2207 		case spv::OpULessThanEqual:
2208 		case spv::OpSLessThanEqual:
2209 		case spv::OpShiftRightLogical:
2210 		case spv::OpShiftRightArithmetic:
2211 		case spv::OpShiftLeftLogical:
2212 		case spv::OpBitwiseOr:
2213 		case spv::OpBitwiseXor:
2214 		case spv::OpBitwiseAnd:
2215 		case spv::OpLogicalOr:
2216 		case spv::OpLogicalAnd:
2217 		case spv::OpLogicalEqual:
2218 		case spv::OpLogicalNotEqual:
2219 		case spv::OpUMulExtended:
2220 		case spv::OpSMulExtended:
2221 		case spv::OpIAddCarry:
2222 		case spv::OpISubBorrow:
2223 			return EmitBinaryOp(insn);
2224 
2225 		case spv::OpDot:
2226 		case spv::OpSDot:
2227 		case spv::OpUDot:
2228 		case spv::OpSUDot:
2229 		case spv::OpSDotAccSat:
2230 		case spv::OpUDotAccSat:
2231 		case spv::OpSUDotAccSat:
2232 			return EmitDot(insn);
2233 
2234 		case spv::OpSelect:
2235 			return EmitSelect(insn);
2236 
2237 		case spv::OpExtInst:
2238 			return EmitExtendedInstruction(insn);
2239 
2240 		case spv::OpAny:
2241 			return EmitAny(insn);
2242 
2243 		case spv::OpAll:
2244 			return EmitAll(insn);
2245 
2246 		case spv::OpPhi:
2247 			return EmitPhi(insn);
2248 
2249 		case spv::OpSelectionMerge:
2250 		case spv::OpLoopMerge:
2251 			return;
2252 
2253 		case spv::OpFunctionCall:
2254 			return EmitFunctionCall(insn);
2255 
2256 		case spv::OpDemoteToHelperInvocation:
2257 			return EmitDemoteToHelperInvocation(insn);
2258 
2259 		case spv::OpIsHelperInvocationEXT:
2260 			return EmitIsHelperInvocation(insn);
2261 
2262 		case spv::OpImageSampleImplicitLod:
2263 		case spv::OpImageSampleExplicitLod:
2264 		case spv::OpImageSampleDrefImplicitLod:
2265 		case spv::OpImageSampleDrefExplicitLod:
2266 		case spv::OpImageSampleProjImplicitLod:
2267 		case spv::OpImageSampleProjExplicitLod:
2268 		case spv::OpImageSampleProjDrefImplicitLod:
2269 		case spv::OpImageSampleProjDrefExplicitLod:
2270 		case spv::OpImageGather:
2271 		case spv::OpImageDrefGather:
2272 		case spv::OpImageFetch:
2273 		case spv::OpImageQueryLod:
2274 			return EmitImageSample(ImageInstruction(insn, shader, *this));
2275 
2276 		case spv::OpImageQuerySizeLod:
2277 			return EmitImageQuerySizeLod(insn);
2278 
2279 		case spv::OpImageQuerySize:
2280 			return EmitImageQuerySize(insn);
2281 
2282 		case spv::OpImageQueryLevels:
2283 			return EmitImageQueryLevels(insn);
2284 
2285 		case spv::OpImageQuerySamples:
2286 			return EmitImageQuerySamples(insn);
2287 
2288 		case spv::OpImageRead:
2289 			return EmitImageRead(ImageInstruction(insn, shader, *this));
2290 
2291 		case spv::OpImageWrite:
2292 			return EmitImageWrite(ImageInstruction(insn, shader, *this));
2293 
2294 		case spv::OpImageTexelPointer:
2295 			return EmitImageTexelPointer(ImageInstruction(insn, shader, *this));
2296 
2297 		case spv::OpSampledImage:
2298 			return EmitSampledImage(insn);
2299 
2300 		case spv::OpImage:
2301 			return EmitImage(insn);
2302 
2303 		case spv::OpCopyObject:
2304 		case spv::OpCopyLogical:
2305 			return EmitCopyObject(insn);
2306 
2307 		case spv::OpCopyMemory:
2308 			return EmitCopyMemory(insn);
2309 
2310 		case spv::OpControlBarrier:
2311 			return EmitControlBarrier(insn);
2312 
2313 		case spv::OpMemoryBarrier:
2314 			return EmitMemoryBarrier(insn);
2315 
2316 		case spv::OpGroupNonUniformElect:
2317 		case spv::OpGroupNonUniformAll:
2318 		case spv::OpGroupNonUniformAny:
2319 		case spv::OpGroupNonUniformAllEqual:
2320 		case spv::OpGroupNonUniformBroadcast:
2321 		case spv::OpGroupNonUniformBroadcastFirst:
2322 		case spv::OpGroupNonUniformQuadBroadcast:
2323 		case spv::OpGroupNonUniformQuadSwap:
2324 		case spv::OpGroupNonUniformBallot:
2325 		case spv::OpGroupNonUniformInverseBallot:
2326 		case spv::OpGroupNonUniformBallotBitExtract:
2327 		case spv::OpGroupNonUniformBallotBitCount:
2328 		case spv::OpGroupNonUniformBallotFindLSB:
2329 		case spv::OpGroupNonUniformBallotFindMSB:
2330 		case spv::OpGroupNonUniformShuffle:
2331 		case spv::OpGroupNonUniformShuffleXor:
2332 		case spv::OpGroupNonUniformShuffleUp:
2333 		case spv::OpGroupNonUniformShuffleDown:
2334 		case spv::OpGroupNonUniformIAdd:
2335 		case spv::OpGroupNonUniformFAdd:
2336 		case spv::OpGroupNonUniformIMul:
2337 		case spv::OpGroupNonUniformFMul:
2338 		case spv::OpGroupNonUniformSMin:
2339 		case spv::OpGroupNonUniformUMin:
2340 		case spv::OpGroupNonUniformFMin:
2341 		case spv::OpGroupNonUniformSMax:
2342 		case spv::OpGroupNonUniformUMax:
2343 		case spv::OpGroupNonUniformFMax:
2344 		case spv::OpGroupNonUniformBitwiseAnd:
2345 		case spv::OpGroupNonUniformBitwiseOr:
2346 		case spv::OpGroupNonUniformBitwiseXor:
2347 		case spv::OpGroupNonUniformLogicalAnd:
2348 		case spv::OpGroupNonUniformLogicalOr:
2349 		case spv::OpGroupNonUniformLogicalXor:
2350 			return EmitGroupNonUniform(insn);
2351 
2352 		case spv::OpArrayLength:
2353 			return EmitArrayLength(insn);
2354 
2355 		default:
2356 			UNREACHABLE("Unknown non-terminal instruction %s", shader.OpcodeName(opcode));
2357 			break;
2358 		}
2359 	}
2360 }
2361 
EmitAccessChain(InsnIterator insn)2362 void SpirvEmitter::EmitAccessChain(InsnIterator insn)
2363 {
2364 	Type::ID typeId = insn.word(1);
2365 	Object::ID resultId = insn.word(2);
2366 	bool nonUniform = shader.GetDecorationsForId(resultId).NonUniform;
2367 	Object::ID baseId = insn.word(3);
2368 	auto &type = shader.getType(typeId);
2369 	ASSERT(type.componentCount == 1);
2370 	ASSERT(shader.getObject(resultId).kind == Object::Kind::Pointer);
2371 
2372 	Object::ID elementId = (insn.opcode() == spv::OpPtrAccessChain) ? insn.word(4) : 0;
2373 	int indexId = (insn.opcode() == spv::OpPtrAccessChain) ? 5 : 4;
2374 	// TODO(b/236280746): Eliminate lookahead by optimizing inside SIMD::Pointer.
2375 	for(auto it = insn; it != shader.end(); it++)
2376 	{
2377 		if(it.opcode() == spv::OpLoad)
2378 		{
2379 			Object::ID pointerId = it.word(3);
2380 			if(pointerId.value() == resultId.value())
2381 			{
2382 				nonUniform |= shader.GetDecorationsForId(it.word(2)).NonUniform;
2383 				break;
2384 			}
2385 		}
2386 	}
2387 
2388 	if(Spirv::IsExplicitLayout(type.storageClass))
2389 	{
2390 		auto ptr = WalkExplicitLayoutAccessChain(baseId, elementId, Span(insn, indexId, insn.wordCount() - indexId), nonUniform);
2391 		createPointer(resultId, ptr);
2392 	}
2393 	else
2394 	{
2395 		auto ptr = WalkAccessChain(baseId, elementId, Span(insn, indexId, insn.wordCount() - indexId), nonUniform);
2396 		createPointer(resultId, ptr);
2397 	}
2398 }
2399 
EmitCompositeConstruct(InsnIterator insn)2400 void SpirvEmitter::EmitCompositeConstruct(InsnIterator insn)
2401 {
2402 	auto &type = shader.getType(insn.resultTypeId());
2403 	auto &dst = createIntermediate(insn.resultId(), type.componentCount);
2404 	auto offset = 0u;
2405 
2406 	for(auto i = 0u; i < insn.wordCount() - 3; i++)
2407 	{
2408 		Object::ID srcObjectId = insn.word(3u + i);
2409 		auto &srcObject = shader.getObject(srcObjectId);
2410 		auto &srcObjectTy = shader.getType(srcObject);
2411 		Operand srcObjectAccess(shader, *this, srcObjectId);
2412 
2413 		for(auto j = 0u; j < srcObjectTy.componentCount; j++)
2414 		{
2415 			dst.move(offset++, srcObjectAccess.Float(j));
2416 		}
2417 	}
2418 }
2419 
EmitCompositeInsert(InsnIterator insn)2420 void SpirvEmitter::EmitCompositeInsert(InsnIterator insn)
2421 {
2422 	Type::ID resultTypeId = insn.word(1);
2423 	auto &type = shader.getType(resultTypeId);
2424 	auto &dst = createIntermediate(insn.resultId(), type.componentCount);
2425 	auto &newPartObject = shader.getObject(insn.word(3));
2426 	auto &newPartObjectTy = shader.getType(newPartObject);
2427 	auto firstNewComponent = shader.WalkLiteralAccessChain(resultTypeId, Span(insn, 5, insn.wordCount() - 5));
2428 
2429 	Operand srcObjectAccess(shader, *this, insn.word(4));
2430 	Operand newPartObjectAccess(shader, *this, insn.word(3));
2431 
2432 	// old components before
2433 	for(auto i = 0u; i < firstNewComponent; i++)
2434 	{
2435 		dst.move(i, srcObjectAccess.Float(i));
2436 	}
2437 	// new part
2438 	for(auto i = 0u; i < newPartObjectTy.componentCount; i++)
2439 	{
2440 		dst.move(firstNewComponent + i, newPartObjectAccess.Float(i));
2441 	}
2442 	// old components after
2443 	for(auto i = firstNewComponent + newPartObjectTy.componentCount; i < type.componentCount; i++)
2444 	{
2445 		dst.move(i, srcObjectAccess.Float(i));
2446 	}
2447 }
2448 
EmitCompositeExtract(InsnIterator insn)2449 void SpirvEmitter::EmitCompositeExtract(InsnIterator insn)
2450 {
2451 	auto &type = shader.getType(insn.resultTypeId());
2452 	auto &dst = createIntermediate(insn.resultId(), type.componentCount);
2453 	auto &compositeObject = shader.getObject(insn.word(3));
2454 	Type::ID compositeTypeId = compositeObject.definition.word(1);
2455 	auto firstComponent = shader.WalkLiteralAccessChain(compositeTypeId, Span(insn, 4, insn.wordCount() - 4));
2456 
2457 	Operand compositeObjectAccess(shader, *this, insn.word(3));
2458 	for(auto i = 0u; i < type.componentCount; i++)
2459 	{
2460 		dst.move(i, compositeObjectAccess.Float(firstComponent + i));
2461 	}
2462 }
2463 
EmitVectorShuffle(InsnIterator insn)2464 void SpirvEmitter::EmitVectorShuffle(InsnIterator insn)
2465 {
2466 	// Note: number of components in result, first vector, and second vector are all independent.
2467 	uint32_t resultSize = shader.getType(insn.resultTypeId()).componentCount;
2468 	uint32_t firstVectorSize = shader.getObjectType(insn.word(3)).componentCount;
2469 
2470 	auto &result = createIntermediate(insn.resultId(), resultSize);
2471 	Operand firstVector(shader, *this, insn.word(3));
2472 	Operand secondVector(shader, *this, insn.word(4));
2473 
2474 	for(uint32_t i = 0u; i < resultSize; i++)
2475 	{
2476 		uint32_t selector = insn.word(5 + i);
2477 		if(selector == 0xFFFFFFFF)  // Undefined value.
2478 		{
2479 			result.move(i, SIMD::Float());
2480 		}
2481 		else if(selector < firstVectorSize)
2482 		{
2483 			result.move(i, firstVector.Float(selector));
2484 		}
2485 		else
2486 		{
2487 			result.move(i, secondVector.Float(selector - firstVectorSize));
2488 		}
2489 	}
2490 }
2491 
EmitVectorExtractDynamic(InsnIterator insn)2492 void SpirvEmitter::EmitVectorExtractDynamic(InsnIterator insn)
2493 {
2494 	auto &type = shader.getType(insn.resultTypeId());
2495 	auto &dst = createIntermediate(insn.resultId(), type.componentCount);
2496 	auto &srcType = shader.getObjectType(insn.word(3));
2497 
2498 	Operand src(shader, *this, insn.word(3));
2499 	Operand index(shader, *this, insn.word(4));
2500 
2501 	SIMD::UInt v = SIMD::UInt(0);
2502 
2503 	for(auto i = 0u; i < srcType.componentCount; i++)
2504 	{
2505 		v |= CmpEQ(index.UInt(0), SIMD::UInt(i)) & src.UInt(i);
2506 	}
2507 
2508 	dst.move(0, v);
2509 }
2510 
EmitVectorInsertDynamic(InsnIterator insn)2511 void SpirvEmitter::EmitVectorInsertDynamic(InsnIterator insn)
2512 {
2513 	auto &type = shader.getType(insn.resultTypeId());
2514 	auto &dst = createIntermediate(insn.resultId(), type.componentCount);
2515 
2516 	Operand src(shader, *this, insn.word(3));
2517 	Operand component(shader, *this, insn.word(4));
2518 	Operand index(shader, *this, insn.word(5));
2519 
2520 	for(auto i = 0u; i < type.componentCount; i++)
2521 	{
2522 		SIMD::UInt mask = CmpEQ(SIMD::UInt(i), index.UInt(0));
2523 		dst.move(i, (src.UInt(i) & ~mask) | (component.UInt(0) & mask));
2524 	}
2525 }
2526 
EmitSelect(InsnIterator insn)2527 void SpirvEmitter::EmitSelect(InsnIterator insn)
2528 {
2529 	auto &type = shader.getType(insn.resultTypeId());
2530 	auto result = shader.getObject(insn.resultId());
2531 	auto cond = Operand(shader, *this, insn.word(3));
2532 	auto condIsScalar = (cond.componentCount == 1);
2533 
2534 	if(result.kind == Object::Kind::Pointer)
2535 	{
2536 		ASSERT(condIsScalar);
2537 		ASSERT(type.storageClass == spv::StorageClassPhysicalStorageBuffer);
2538 
2539 		auto &lhs = getPointer(insn.word(4));
2540 		auto &rhs = getPointer(insn.word(5));
2541 		createPointer(insn.resultId(), SIMD::Pointer::IfThenElse(cond.Int(0), lhs, rhs));
2542 
2543 		SPIRV_SHADER_DBG("{0}: {1}", insn.word(3), cond);
2544 		SPIRV_SHADER_DBG("{0}: {1}", insn.word(4), lhs);
2545 		SPIRV_SHADER_DBG("{0}: {1}", insn.word(5), rhs);
2546 	}
2547 	else
2548 	{
2549 		auto lhs = Operand(shader, *this, insn.word(4));
2550 		auto rhs = Operand(shader, *this, insn.word(5));
2551 		auto &dst = createIntermediate(insn.resultId(), type.componentCount);
2552 
2553 		for(auto i = 0u; i < type.componentCount; i++)
2554 		{
2555 			auto sel = cond.Int(condIsScalar ? 0 : i);
2556 			dst.move(i, (sel & lhs.Int(i)) | (~sel & rhs.Int(i)));  // TODO: IfThenElse()
2557 		}
2558 
2559 		SPIRV_SHADER_DBG("{0}: {1}", insn.word(2), dst);
2560 		SPIRV_SHADER_DBG("{0}: {1}", insn.word(3), cond);
2561 		SPIRV_SHADER_DBG("{0}: {1}", insn.word(4), lhs);
2562 		SPIRV_SHADER_DBG("{0}: {1}", insn.word(5), rhs);
2563 	}
2564 }
2565 
EmitAny(InsnIterator insn)2566 void SpirvEmitter::EmitAny(InsnIterator insn)
2567 {
2568 	auto &type = shader.getType(insn.resultTypeId());
2569 	ASSERT(type.componentCount == 1);
2570 	auto &dst = createIntermediate(insn.resultId(), type.componentCount);
2571 	auto &srcType = shader.getObjectType(insn.word(3));
2572 	auto src = Operand(shader, *this, insn.word(3));
2573 
2574 	SIMD::UInt result = src.UInt(0);
2575 
2576 	for(auto i = 1u; i < srcType.componentCount; i++)
2577 	{
2578 		result |= src.UInt(i);
2579 	}
2580 
2581 	dst.move(0, result);
2582 }
2583 
EmitAll(InsnIterator insn)2584 void SpirvEmitter::EmitAll(InsnIterator insn)
2585 {
2586 	auto &type = shader.getType(insn.resultTypeId());
2587 	ASSERT(type.componentCount == 1);
2588 	auto &dst = createIntermediate(insn.resultId(), type.componentCount);
2589 	auto &srcType = shader.getObjectType(insn.word(3));
2590 	auto src = Operand(shader, *this, insn.word(3));
2591 
2592 	SIMD::UInt result = src.UInt(0);
2593 
2594 	for(uint32_t i = 1; i < srcType.componentCount; i++)
2595 	{
2596 		result &= src.UInt(i);
2597 	}
2598 
2599 	dst.move(0, result);
2600 }
2601 
EmitAtomicOp(InsnIterator insn)2602 void SpirvEmitter::EmitAtomicOp(InsnIterator insn)
2603 {
2604 	auto &resultType = shader.getType(Type::ID(insn.word(1)));
2605 	Object::ID resultId = insn.word(2);
2606 	Object::ID pointerId = insn.word(3);
2607 	Object::ID semanticsId = insn.word(5);
2608 	auto memorySemantics = static_cast<spv::MemorySemanticsMask>(shader.getObject(semanticsId).constantValue[0]);
2609 	auto memoryOrder = shader.MemoryOrder(memorySemantics);
2610 	// Where no value is provided (increment/decrement) use an implicit value of 1.
2611 	auto value = (insn.wordCount() == 7) ? Operand(shader, *this, insn.word(6)).UInt(0) : RValue<SIMD::UInt>(1);
2612 	auto &dst = createIntermediate(resultId, resultType.componentCount);
2613 	auto ptr = getPointer(pointerId);
2614 
2615 	SIMD::Int mask = activeLaneMask() & storesAndAtomicsMask();
2616 
2617 	if((shader.getObject(pointerId).opcode() == spv::OpImageTexelPointer) && ptr.isBasePlusOffset)
2618 	{
2619 		mask &= ptr.isInBounds(sizeof(int32_t), OutOfBoundsBehavior::Nullify);
2620 	}
2621 
2622 	SIMD::UInt result(0);
2623 	for(int j = 0; j < SIMD::Width; j++)
2624 	{
2625 		If(Extract(mask, j) != 0)
2626 		{
2627 			auto laneValue = Extract(value, j);
2628 			UInt v;
2629 			switch(insn.opcode())
2630 			{
2631 			case spv::OpAtomicIAdd:
2632 			case spv::OpAtomicIIncrement:
2633 				v = AddAtomic(Pointer<UInt>(ptr.getPointerForLane(j)), laneValue, memoryOrder);
2634 				break;
2635 			case spv::OpAtomicISub:
2636 			case spv::OpAtomicIDecrement:
2637 				v = SubAtomic(Pointer<UInt>(ptr.getPointerForLane(j)), laneValue, memoryOrder);
2638 				break;
2639 			case spv::OpAtomicAnd:
2640 				v = AndAtomic(Pointer<UInt>(ptr.getPointerForLane(j)), laneValue, memoryOrder);
2641 				break;
2642 			case spv::OpAtomicOr:
2643 				v = OrAtomic(Pointer<UInt>(ptr.getPointerForLane(j)), laneValue, memoryOrder);
2644 				break;
2645 			case spv::OpAtomicXor:
2646 				v = XorAtomic(Pointer<UInt>(ptr.getPointerForLane(j)), laneValue, memoryOrder);
2647 				break;
2648 			case spv::OpAtomicSMin:
2649 				v = As<UInt>(MinAtomic(Pointer<Int>(ptr.getPointerForLane(j)), As<Int>(laneValue), memoryOrder));
2650 				break;
2651 			case spv::OpAtomicSMax:
2652 				v = As<UInt>(MaxAtomic(Pointer<Int>(ptr.getPointerForLane(j)), As<Int>(laneValue), memoryOrder));
2653 				break;
2654 			case spv::OpAtomicUMin:
2655 				v = MinAtomic(Pointer<UInt>(ptr.getPointerForLane(j)), laneValue, memoryOrder);
2656 				break;
2657 			case spv::OpAtomicUMax:
2658 				v = MaxAtomic(Pointer<UInt>(ptr.getPointerForLane(j)), laneValue, memoryOrder);
2659 				break;
2660 			case spv::OpAtomicExchange:
2661 				v = ExchangeAtomic(Pointer<UInt>(ptr.getPointerForLane(j)), laneValue, memoryOrder);
2662 				break;
2663 			default:
2664 				UNREACHABLE("%s", shader.OpcodeName(insn.opcode()));
2665 				break;
2666 			}
2667 			result = Insert(result, v, j);
2668 		}
2669 	}
2670 
2671 	dst.move(0, result);
2672 }
2673 
EmitAtomicCompareExchange(InsnIterator insn)2674 void SpirvEmitter::EmitAtomicCompareExchange(InsnIterator insn)
2675 {
2676 	// Separate from EmitAtomicOp due to different instruction encoding
2677 	auto &resultType = shader.getType(Type::ID(insn.word(1)));
2678 	Object::ID resultId = insn.word(2);
2679 
2680 	auto memorySemanticsEqual = static_cast<spv::MemorySemanticsMask>(shader.getObject(insn.word(5)).constantValue[0]);
2681 	auto memoryOrderEqual = shader.MemoryOrder(memorySemanticsEqual);
2682 	auto memorySemanticsUnequal = static_cast<spv::MemorySemanticsMask>(shader.getObject(insn.word(6)).constantValue[0]);
2683 	auto memoryOrderUnequal = shader.MemoryOrder(memorySemanticsUnequal);
2684 
2685 	auto value = Operand(shader, *this, insn.word(7));
2686 	auto comparator = Operand(shader, *this, insn.word(8));
2687 	auto &dst = createIntermediate(resultId, resultType.componentCount);
2688 	auto ptr = getPointer(insn.word(3));
2689 
2690 	SIMD::UInt x(0);
2691 	auto mask = activeLaneMask() & storesAndAtomicsMask();
2692 	for(int j = 0; j < SIMD::Width; j++)
2693 	{
2694 		If(Extract(mask, j) != 0)
2695 		{
2696 			auto laneValue = Extract(value.UInt(0), j);
2697 			auto laneComparator = Extract(comparator.UInt(0), j);
2698 			UInt v = CompareExchangeAtomic(Pointer<UInt>(ptr.getPointerForLane(j)), laneValue, laneComparator, memoryOrderEqual, memoryOrderUnequal);
2699 			x = Insert(x, v, j);
2700 		}
2701 	}
2702 
2703 	dst.move(0, x);
2704 }
2705 
EmitCopyObject(InsnIterator insn)2706 void SpirvEmitter::EmitCopyObject(InsnIterator insn)
2707 {
2708 	auto src = Operand(shader, *this, insn.word(3));
2709 	if(src.isPointer())
2710 	{
2711 		createPointer(insn.resultId(), src.Pointer());
2712 	}
2713 	else if(src.isSampledImage())
2714 	{
2715 		createSampledImage(insn.resultId(), src.SampledImage());
2716 	}
2717 	else
2718 	{
2719 		auto type = shader.getType(insn.resultTypeId());
2720 		auto &dst = createIntermediate(insn.resultId(), type.componentCount);
2721 		for(uint32_t i = 0; i < type.componentCount; i++)
2722 		{
2723 			dst.move(i, src.Int(i));
2724 		}
2725 	}
2726 }
2727 
EmitArrayLength(InsnIterator insn)2728 void SpirvEmitter::EmitArrayLength(InsnIterator insn)
2729 {
2730 	auto structPtrId = Object::ID(insn.word(3));
2731 	auto arrayFieldIdx = insn.word(4);
2732 
2733 	auto &resultType = shader.getType(insn.resultTypeId());
2734 	ASSERT(resultType.componentCount == 1);
2735 	ASSERT(resultType.definition.opcode() == spv::OpTypeInt);
2736 
2737 	auto &structPtrTy = shader.getObjectType(structPtrId);
2738 	auto &structTy = shader.getType(structPtrTy.element);
2739 	auto arrayId = Type::ID(structTy.definition.word(2 + arrayFieldIdx));
2740 
2741 	auto &result = createIntermediate(insn.resultId(), 1);
2742 	auto structBase = GetPointerToData(structPtrId, 0, false);
2743 
2744 	Decorations structDecorations = {};
2745 	shader.ApplyDecorationsForIdMember(&structDecorations, structPtrTy.element, arrayFieldIdx);
2746 	ASSERT(structDecorations.HasOffset);
2747 
2748 	auto arrayBase = structBase + structDecorations.Offset;
2749 	auto arraySizeInBytes = SIMD::Int(arrayBase.limit()) - arrayBase.offsets();
2750 
2751 	Decorations arrayDecorations = shader.GetDecorationsForId(arrayId);
2752 	ASSERT(arrayDecorations.HasArrayStride);
2753 	auto arrayLength = arraySizeInBytes / SIMD::Int(arrayDecorations.ArrayStride);
2754 
2755 	result.move(0, SIMD::Int(arrayLength));
2756 }
2757 
EmitExtendedInstruction(InsnIterator insn)2758 void SpirvEmitter::EmitExtendedInstruction(InsnIterator insn)
2759 {
2760 	auto ext = shader.getExtension(insn.word(3));
2761 	switch(ext.name)
2762 	{
2763 	case Spirv::Extension::GLSLstd450:
2764 		return EmitExtGLSLstd450(insn);
2765 	case Spirv::Extension::NonSemanticInfo:
2766 		// An extended set name which is prefixed with "NonSemantic." is
2767 		// guaranteed to contain only non-semantic instructions and all
2768 		// OpExtInst instructions referencing this set can be ignored.
2769 		break;
2770 	default:
2771 		UNREACHABLE("Unknown Extension::Name<%d>", int(ext.name));
2772 	}
2773 }
2774 
GetConstScalarInt(Object::ID id) const2775 uint32_t Spirv::GetConstScalarInt(Object::ID id) const
2776 {
2777 	auto &scopeObj = getObject(id);
2778 	ASSERT(scopeObj.kind == Object::Kind::Constant);
2779 	ASSERT(getType(scopeObj).componentCount == 1);
2780 
2781 	return scopeObj.constantValue[0];
2782 }
2783 
emitEpilog(SpirvRoutine * routine) const2784 void SpirvShader::emitEpilog(SpirvRoutine *routine) const
2785 {
2786 	for(auto insn : *this)
2787 	{
2788 		if(insn.opcode() == spv::OpVariable)
2789 		{
2790 			auto &object = getObject(insn.resultId());
2791 			auto &objectTy = getType(object);
2792 
2793 			if(object.kind == Object::Kind::InterfaceVariable && objectTy.storageClass == spv::StorageClassOutput)
2794 			{
2795 				auto &dst = routine->getVariable(insn.resultId());
2796 				int offset = 0;
2797 
2798 				VisitInterface(insn.resultId(),
2799 				               [&](const Decorations &d, AttribType type) {
2800 					               auto scalarSlot = d.Location << 2 | d.Component;
2801 					               routine->outputs[scalarSlot] = dst[offset++];
2802 				               });
2803 			}
2804 		}
2805 	}
2806 }
2807 
executionModelToStage(spv::ExecutionModel model)2808 VkShaderStageFlagBits Spirv::executionModelToStage(spv::ExecutionModel model)
2809 {
2810 	switch(model)
2811 	{
2812 	case spv::ExecutionModelVertex: return VK_SHADER_STAGE_VERTEX_BIT;
2813 	// case spv::ExecutionModelTessellationControl:    return VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
2814 	// case spv::ExecutionModelTessellationEvaluation: return VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
2815 	// case spv::ExecutionModelGeometry:               return VK_SHADER_STAGE_GEOMETRY_BIT;
2816 	case spv::ExecutionModelFragment: return VK_SHADER_STAGE_FRAGMENT_BIT;
2817 	case spv::ExecutionModelGLCompute: return VK_SHADER_STAGE_COMPUTE_BIT;
2818 	// case spv::ExecutionModelKernel:                 return VkShaderStageFlagBits(0); // Not supported by vulkan.
2819 	// case spv::ExecutionModelTaskNV:                 return VK_SHADER_STAGE_TASK_BIT_NV;
2820 	// case spv::ExecutionModelMeshNV:                 return VK_SHADER_STAGE_MESH_BIT_NV;
2821 	// case spv::ExecutionModelRayGenerationNV:        return VK_SHADER_STAGE_RAYGEN_BIT_NV;
2822 	// case spv::ExecutionModelIntersectionNV:         return VK_SHADER_STAGE_INTERSECTION_BIT_NV;
2823 	// case spv::ExecutionModelAnyHitNV:               return VK_SHADER_STAGE_ANY_HIT_BIT_NV;
2824 	// case spv::ExecutionModelClosestHitNV:           return VK_SHADER_STAGE_CLOSEST_HIT_BIT_NV;
2825 	// case spv::ExecutionModelMissNV:                 return VK_SHADER_STAGE_MISS_BIT_NV;
2826 	// case spv::ExecutionModelCallableNV:             return VK_SHADER_STAGE_CALLABLE_BIT_NV;
2827 	default:
2828 		UNSUPPORTED("ExecutionModel: %d", int(model));
2829 		return VkShaderStageFlagBits(0);
2830 	}
2831 }
2832 
Operand(const Spirv & shader,const SpirvEmitter & state,Object::ID objectId)2833 SpirvEmitter::Operand::Operand(const Spirv &shader, const SpirvEmitter &state, Object::ID objectId)
2834     : Operand(state, shader.getObject(objectId))
2835 {}
2836 
Operand(const SpirvEmitter & state,const Object & object)2837 SpirvEmitter::Operand::Operand(const SpirvEmitter &state, const Object &object)
2838     : constant(object.kind == Object::Kind::Constant ? object.constantValue.data() : nullptr)
2839     , intermediate(object.kind == Object::Kind::Intermediate ? &state.getIntermediate(object.id()) : nullptr)
2840     , pointer(object.kind == Object::Kind::Pointer ? &state.getPointer(object.id()) : nullptr)
2841     , sampledImage(object.kind == Object::Kind::SampledImage ? &state.getSampledImage(object.id()) : nullptr)
2842     , componentCount(intermediate ? intermediate->componentCount : object.constantValue.size())
2843 {
2844 	ASSERT(intermediate || constant || pointer || sampledImage);
2845 }
2846 
Operand(const Intermediate & value)2847 SpirvEmitter::Operand::Operand(const Intermediate &value)
2848     : intermediate(&value)
2849     , componentCount(value.componentCount)
2850 {
2851 }
2852 
isConstantZero() const2853 bool Spirv::Object::isConstantZero() const
2854 {
2855 	if(kind != Kind::Constant)
2856 	{
2857 		return false;
2858 	}
2859 
2860 	for(uint32_t i = 0; i < constantValue.size(); i++)
2861 	{
2862 		if(constantValue[i] != 0)
2863 		{
2864 			return false;
2865 		}
2866 	}
2867 
2868 	return true;
2869 }
2870 
SpirvRoutine(const vk::PipelineLayout * pipelineLayout)2871 SpirvRoutine::SpirvRoutine(const vk::PipelineLayout *pipelineLayout)
2872     : pipelineLayout(pipelineLayout)
2873 {
2874 }
2875 
setImmutableInputBuiltins(const SpirvShader * shader)2876 void SpirvRoutine::setImmutableInputBuiltins(const SpirvShader *shader)
2877 {
2878 	setInputBuiltin(shader, spv::BuiltInSubgroupLocalInvocationId, [&](const Spirv::BuiltinMapping &builtin, Array<SIMD::Float> &value) {
2879 		ASSERT(builtin.SizeInComponents == 1);
2880 		value[builtin.FirstComponent] = As<SIMD::Float>(SIMD::Int(0, 1, 2, 3));
2881 	});
2882 
2883 	setInputBuiltin(shader, spv::BuiltInSubgroupEqMask, [&](const Spirv::BuiltinMapping &builtin, Array<SIMD::Float> &value) {
2884 		ASSERT(builtin.SizeInComponents == 4);
2885 		value[builtin.FirstComponent + 0] = As<SIMD::Float>(SIMD::Int(1, 2, 4, 8));
2886 		value[builtin.FirstComponent + 1] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2887 		value[builtin.FirstComponent + 2] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2888 		value[builtin.FirstComponent + 3] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2889 	});
2890 
2891 	setInputBuiltin(shader, spv::BuiltInSubgroupGeMask, [&](const Spirv::BuiltinMapping &builtin, Array<SIMD::Float> &value) {
2892 		ASSERT(builtin.SizeInComponents == 4);
2893 		value[builtin.FirstComponent + 0] = As<SIMD::Float>(SIMD::Int(15, 14, 12, 8));
2894 		value[builtin.FirstComponent + 1] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2895 		value[builtin.FirstComponent + 2] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2896 		value[builtin.FirstComponent + 3] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2897 	});
2898 
2899 	setInputBuiltin(shader, spv::BuiltInSubgroupGtMask, [&](const Spirv::BuiltinMapping &builtin, Array<SIMD::Float> &value) {
2900 		ASSERT(builtin.SizeInComponents == 4);
2901 		value[builtin.FirstComponent + 0] = As<SIMD::Float>(SIMD::Int(14, 12, 8, 0));
2902 		value[builtin.FirstComponent + 1] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2903 		value[builtin.FirstComponent + 2] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2904 		value[builtin.FirstComponent + 3] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2905 	});
2906 
2907 	setInputBuiltin(shader, spv::BuiltInSubgroupLeMask, [&](const Spirv::BuiltinMapping &builtin, Array<SIMD::Float> &value) {
2908 		ASSERT(builtin.SizeInComponents == 4);
2909 		value[builtin.FirstComponent + 0] = As<SIMD::Float>(SIMD::Int(1, 3, 7, 15));
2910 		value[builtin.FirstComponent + 1] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2911 		value[builtin.FirstComponent + 2] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2912 		value[builtin.FirstComponent + 3] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2913 	});
2914 
2915 	setInputBuiltin(shader, spv::BuiltInSubgroupLtMask, [&](const Spirv::BuiltinMapping &builtin, Array<SIMD::Float> &value) {
2916 		ASSERT(builtin.SizeInComponents == 4);
2917 		value[builtin.FirstComponent + 0] = As<SIMD::Float>(SIMD::Int(0, 1, 3, 7));
2918 		value[builtin.FirstComponent + 1] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2919 		value[builtin.FirstComponent + 2] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2920 		value[builtin.FirstComponent + 3] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2921 	});
2922 
2923 	setInputBuiltin(shader, spv::BuiltInDeviceIndex, [&](const Spirv::BuiltinMapping &builtin, Array<SIMD::Float> &value) {
2924 		ASSERT(builtin.SizeInComponents == 1);
2925 		// Only a single physical device is supported.
2926 		value[builtin.FirstComponent] = As<SIMD::Float>(SIMD::Int(0, 0, 0, 0));
2927 	});
2928 }
2929 
2930 }  // namespace sw
2931