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