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