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