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