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