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