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