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