21#include "llvm/ADT/STLExtras.h"
22#include "llvm/ADT/Sequence.h"
23#include "llvm/ADT/StringExtras.h"
24#include "llvm/ADT/TypeSwitch.h"
25#include "llvm/ADT/bit.h"
26#include "llvm/Support/Debug.h"
30#define DEBUG_TYPE "spirv-serialization"
37 if (
auto selectionOp = dyn_cast<spirv::SelectionOp>(op))
38 return selectionOp.getMergeBlock();
39 if (
auto loopOp = dyn_cast<spirv::LoopOp>(op))
40 return loopOp.getMergeBlock();
51 if (
auto loopOp = dyn_cast<spirv::LoopOp>(block->
getParentOp())) {
55 while ((op = op->getPrevNode()) !=
nullptr)
74 if (
auto floatAttr = dyn_cast<FloatAttr>(attr)) {
75 return floatAttr.getValue().isZero();
77 if (
auto boolAttr = dyn_cast<BoolAttr>(attr)) {
78 return !boolAttr.getValue();
80 if (
auto intAttr = dyn_cast<IntegerAttr>(attr)) {
81 return intAttr.getValue().isZero();
83 if (
auto splatElemAttr = dyn_cast<SplatElementsAttr>(attr)) {
86 if (
auto denseElemAttr = dyn_cast<DenseElementsAttr>(attr)) {
102 for (
Operation &op : llvm::drop_begin(ops))
103 if (
auto funcOp = dyn_cast<spirv::FuncOp>(op))
104 if (funcOp.getBody().empty())
115 uint32_t wordCount = 1 + operands.size();
117 binary.append(operands.begin(), operands.end());
122 : module(module), mlirBuilder(module.
getContext()), options(options) {}
125 LLVM_DEBUG(llvm::dbgs() <<
"+++ starting serialization +++\n");
127 if (failed(module.verifyInvariants()))
132 if (failed(processExtension())) {
135 processMemoryModel();
142 for (
auto &op : *module.getBody()) {
143 if (failed(processOperation(&op))) {
148 LLVM_DEBUG(llvm::dbgs() <<
"+++ completed serialization +++\n");
154 extensions.size() + extendedSets.size() +
155 memoryModel.size() + entryPoints.size() +
156 executionModes.size() + decorations.size() +
157 typesGlobalValues.size() + functions.size() + graphs.size();
160 binary.reserve(moduleSize);
164 binary.append(capabilities.begin(), capabilities.end());
165 binary.append(extensions.begin(), extensions.end());
166 binary.append(extendedSets.begin(), extendedSets.end());
167 binary.append(memoryModel.begin(), memoryModel.end());
168 binary.append(entryPoints.begin(), entryPoints.end());
169 binary.append(executionModes.begin(), executionModes.end());
170 binary.append(debug.begin(), debug.end());
171 binary.append(names.begin(), names.end());
172 binary.append(decorations.begin(), decorations.end());
173 binary.append(typesGlobalValues.begin(), typesGlobalValues.end());
174 binary.append(functions.begin(), functions.end());
175 binary.append(graphs.begin(), graphs.end());
176 binary.append(graphsDebugInfo.begin(), graphsDebugInfo.end());
181 os <<
"\n= Value <id> Map =\n\n";
182 for (
auto valueIDPair : valueIDMap) {
183 Value val = valueIDPair.first;
184 os <<
" " << val <<
" "
185 <<
"id = " << valueIDPair.second <<
' ';
187 os <<
"from op '" << op->getName() <<
"'";
188 }
else if (
auto arg = dyn_cast<BlockArgument>(val)) {
189 Block *block = arg.getOwner();
190 os <<
"from argument of block " << block <<
' ';
202uint32_t Serializer::getOrCreateFunctionID(StringRef fnName) {
203 auto funcID = funcIDMap.lookup(fnName);
205 funcID = getNextID();
206 funcIDMap[fnName] = funcID;
211void Serializer::processCapability() {
212 for (
auto cap : module.getVceTriple()->getCapabilities())
214 {
static_cast<uint32_t
>(cap)});
217void Serializer::addLongCompositesCapability() {
218 if (longCompositesEmitted)
220 longCompositesEmitted =
true;
221 auto vceTriple =
module.getVceTriple();
222 if (!llvm::is_contained(vceTriple->getCapabilities(),
223 spirv::Capability::LongCompositesINTEL))
225 capabilities, spirv::Opcode::OpCapability,
226 {
static_cast<uint32_t
>(spirv::Capability::LongCompositesINTEL)});
227 if (!llvm::is_contained(vceTriple->getExtensions(),
228 spirv::Extension::SPV_INTEL_long_composites)) {
229 SmallVector<uint32_t, 8> extName;
232 spirv::stringifyExtension(spirv::Extension::SPV_INTEL_long_composites));
237void Serializer::encodeInstructionWithContinuationInto(
238 SmallVectorImpl<uint32_t> &binary, spirv::Opcode op,
239 ArrayRef<uint32_t> operands) {
245 std::optional<spirv::Opcode> continuationOp =
247 assert(continuationOp &&
"op is not a splittable composite/struct opcode");
251 for (ArrayRef<uint32_t> rest = operands.drop_front(chunk); !rest.empty();
252 rest = rest.drop_front(std::min<size_t>(rest.size(), chunk))) {
256 addLongCompositesCapability();
259void Serializer::processDebugInfo() {
260 if (!options.emitDebugInfo)
262 auto fileLoc = dyn_cast<FileLineColLoc>(module.getLoc());
263 auto fileName = fileLoc ? fileLoc.getFilename().strref() :
"<unknown>";
264 fileID = getNextID();
265 SmallVector<uint32_t, 16> operands;
266 operands.push_back(fileID);
272LogicalResult Serializer::processExtension() {
273 llvm::SmallVector<uint32_t, 16> extName;
274 llvm::SmallSet<Extension, 4> deducedExts(
275 llvm::from_range, module.getVceTriple()->getExtensions());
276 auto nonSemanticInfoExt = spirv::Extension::SPV_KHR_non_semantic_info;
277 if (options.emitDebugInfo && !deducedExts.contains(nonSemanticInfoExt)) {
279 if (!is_contained(targetEnvAttr.getExtensions(), nonSemanticInfoExt))
280 return module.emitError(
281 "SPV_KHR_non_semantic_info extension not available");
282 deducedExts.insert(nonSemanticInfoExt);
284 for (spirv::Extension ext : deducedExts) {
292void Serializer::processMemoryModel() {
293 StringAttr memoryModelName =
module.getMemoryModelAttrName();
294 auto mm =
static_cast<uint32_t
>(
295 module->getAttrOfType<spirv::MemoryModelAttr>(memoryModelName)
298 StringAttr addressingModelName =
module.getAddressingModelAttrName();
299 auto am =
static_cast<uint32_t
>(
300 module->getAttrOfType<spirv::AddressingModelAttr>(addressingModelName)
309 if (attrName ==
"fp_fast_math_mode")
310 return "FPFastMathMode";
312 if (attrName ==
"fp_rounding_mode")
313 return "FPRoundingMode";
315 if (attrName ==
"cache_control_load_intel")
316 return "CacheControlLoadINTEL";
317 if (attrName ==
"cache_control_store_intel")
318 return "CacheControlStoreINTEL";
320 return llvm::convertToCamelFromSnakeCase(attrName,
true);
323template <
typename AttrTy,
typename EmitF>
326 StringRef attrName, EmitF emitter) {
327 auto arrayAttr = dyn_cast<ArrayAttr>(attrList);
329 return emitError(loc,
"expecting array attribute of ")
330 << attrName <<
" for " << stringifyDecoration(decoration);
332 if (arrayAttr.empty()) {
333 return emitError(loc,
"expecting non-empty array attribute of ")
334 << attrName <<
" for " << stringifyDecoration(decoration);
336 for (
Attribute attr : arrayAttr.getValue()) {
337 auto cacheControlAttr = dyn_cast<AttrTy>(attr);
338 if (!cacheControlAttr) {
339 return emitError(loc,
"expecting array attribute of ")
340 << attrName <<
" for " << stringifyDecoration(decoration);
344 if (failed(emitter(cacheControlAttr)))
350LogicalResult Serializer::processDecorationAttr(
Location loc, uint32_t resultID,
351 Decoration decoration,
354 switch (decoration) {
355 case spirv::Decoration::LinkageAttributes: {
358 auto linkageAttr = dyn_cast<spirv::LinkageAttributesAttr>(attr);
359 auto linkageName = linkageAttr.getLinkageName();
360 auto linkageType = linkageAttr.getLinkageType().getValue();
364 args.push_back(
static_cast<uint32_t
>(linkageType));
367 case spirv::Decoration::FPFastMathMode:
368 if (
auto intAttr = dyn_cast<FPFastMathModeAttr>(attr)) {
369 args.push_back(
static_cast<uint32_t
>(intAttr.getValue()));
372 return emitError(loc,
"expected FPFastMathModeAttr attribute for ")
373 << stringifyDecoration(decoration);
374 case spirv::Decoration::FPRoundingMode:
375 if (
auto intAttr = dyn_cast<FPRoundingModeAttr>(attr)) {
376 args.push_back(
static_cast<uint32_t
>(intAttr.getValue()));
379 return emitError(loc,
"expected FPRoundingModeAttr attribute for ")
380 << stringifyDecoration(decoration);
381 case spirv::Decoration::Binding:
382 case spirv::Decoration::DescriptorSet:
383 case spirv::Decoration::Location:
384 case spirv::Decoration::Index:
385 case spirv::Decoration::Offset:
386 case spirv::Decoration::XfbBuffer:
387 case spirv::Decoration::XfbStride:
388 if (
auto intAttr = dyn_cast<IntegerAttr>(attr)) {
389 args.push_back(intAttr.getValue().getZExtValue());
392 return emitError(loc,
"expected integer attribute for ")
393 << stringifyDecoration(decoration);
394 case spirv::Decoration::BuiltIn:
395 if (
auto strAttr = dyn_cast<StringAttr>(attr)) {
396 auto enumVal = spirv::symbolizeBuiltIn(strAttr.getValue());
398 args.push_back(
static_cast<uint32_t
>(*enumVal));
402 << stringifyDecoration(decoration) <<
" decoration attribute "
403 << strAttr.getValue();
405 return emitError(loc,
"expected string attribute for ")
406 << stringifyDecoration(decoration);
407 case spirv::Decoration::Aliased:
408 case spirv::Decoration::AliasedPointer:
409 case spirv::Decoration::Flat:
410 case spirv::Decoration::NonReadable:
411 case spirv::Decoration::NonWritable:
412 case spirv::Decoration::NoPerspective:
413 case spirv::Decoration::NoSignedWrap:
414 case spirv::Decoration::NoUnsignedWrap:
415 case spirv::Decoration::RelaxedPrecision:
416 case spirv::Decoration::Restrict:
417 case spirv::Decoration::RestrictPointer:
418 case spirv::Decoration::NoContraction:
419 case spirv::Decoration::Constant:
420 case spirv::Decoration::Block:
421 case spirv::Decoration::BufferBlock:
422 case spirv::Decoration::Invariant:
423 case spirv::Decoration::Patch:
424 case spirv::Decoration::Coherent:
425 case spirv::Decoration::Volatile:
428 if (isa<UnitAttr, DecorationAttr>(attr))
431 "expected unit attribute or decoration attribute for ")
432 << stringifyDecoration(decoration);
433 case spirv::Decoration::CacheControlLoadINTEL:
435 loc, decoration, attr,
"CacheControlLoadINTEL",
436 [&](CacheControlLoadINTELAttr attr) {
437 unsigned cacheLevel = attr.getCacheLevel();
438 LoadCacheControl loadCacheControl = attr.getLoadCacheControl();
439 return emitDecoration(
440 resultID, decoration,
441 {cacheLevel,
static_cast<uint32_t
>(loadCacheControl)});
443 case spirv::Decoration::CacheControlStoreINTEL:
445 loc, decoration, attr,
"CacheControlStoreINTEL",
446 [&](CacheControlStoreINTELAttr attr) {
447 unsigned cacheLevel = attr.getCacheLevel();
448 StoreCacheControl storeCacheControl = attr.getStoreCacheControl();
449 return emitDecoration(
450 resultID, decoration,
451 {cacheLevel,
static_cast<uint32_t
>(storeCacheControl)});
453 case spirv::Decoration::AlignmentId:
454 case spirv::Decoration::MaxByteOffsetId:
455 case spirv::Decoration::CounterBuffer: {
456 auto symRef = dyn_cast<FlatSymbolRefAttr>(attr);
458 return emitError(loc,
"expected symbol reference for ")
459 << stringifyDecoration(decoration);
460 StringRef symName = symRef.getValue();
461 uint32_t operandID = getVariableID(symName);
463 operandID = getSpecConstID(symName);
465 return emitError(loc,
"could not find <id> for symbol '")
466 << symName <<
"' referenced by "
467 << stringifyDecoration(decoration);
468 return emitDecorationId(resultID, decoration, {operandID});
471 return emitError(loc,
"unhandled decoration ")
472 << stringifyDecoration(decoration);
474 return emitDecoration(resultID, decoration, args);
477LogicalResult Serializer::processDecoration(Location loc, uint32_t resultID,
478 NamedAttribute attr) {
479 StringRef attrName = attr.
getName().strref();
481 std::optional<Decoration> decoration =
482 spirv::symbolizeDecoration(decorationName);
485 loc,
"non-argument attributes expected to have snake-case-ified "
486 "decoration name, unhandled attribute with name : ")
489 return processDecorationAttr(loc, resultID, *decoration, attr.
getValue());
492LogicalResult Serializer::processName(uint32_t resultID, StringRef name) {
493 assert(!name.empty() &&
"unexpected empty string for OpName");
494 if (!options.emitSymbolName)
497 SmallVector<uint32_t, 4> nameOperands;
498 nameOperands.push_back(resultID);
505LogicalResult Serializer::processTypeDecoration<spirv::ArrayType>(
509 return emitDecoration(resultID, spirv::Decoration::ArrayStride, {stride});
515LogicalResult Serializer::processTypeDecoration<spirv::RuntimeArrayType>(
519 return emitDecoration(resultID, spirv::Decoration::ArrayStride, {stride});
524LogicalResult Serializer::processMemberDecoration(
529 static_cast<uint32_t
>(memberDecoration.
decoration)});
545bool Serializer::isInterfaceStructPtrType(Type type)
const {
546 if (
auto ptrType = dyn_cast<spirv::PointerType>(type)) {
547 switch (ptrType.getStorageClass()) {
548 case spirv::StorageClass::PhysicalStorageBuffer:
549 case spirv::StorageClass::PushConstant:
550 case spirv::StorageClass::StorageBuffer:
551 case spirv::StorageClass::Uniform:
552 return isa<spirv::StructType>(ptrType.getPointeeType());
560LogicalResult Serializer::processType(Location loc, Type type,
565 return processTypeImpl(loc, type, typeID, serializationCtx);
569Serializer::processTypeImpl(Location loc, Type type, uint32_t &typeID,
581 IntegerType::SignednessSemantics::Signless);
584 typeID = getTypeID(type);
588 typeID = getNextID();
589 SmallVector<uint32_t, 4> operands;
591 operands.push_back(typeID);
592 auto typeEnum = spirv::Opcode::OpTypeVoid;
593 bool deferSerialization =
false;
595 if ((isa<FunctionType>(type) &&
596 succeeded(prepareFunctionType(loc, cast<FunctionType>(type), typeEnum,
598 (isa<GraphType>(type) &&
600 prepareGraphType(loc, cast<GraphType>(type), typeEnum, operands))) ||
601 succeeded(prepareBasicType(loc, type, typeID, typeEnum, operands,
602 deferSerialization, serializationCtx))) {
603 if (deferSerialization)
606 typeIDMap[type] = typeID;
608 if (typeEnum == spirv::Opcode::OpTypeStruct)
609 encodeInstructionWithContinuationInto(typesGlobalValues, typeEnum,
614 if (recursiveStructInfos.count(type) != 0) {
617 for (
auto &ptrInfo : recursiveStructInfos[type]) {
620 SmallVector<uint32_t, 4> ptrOperands;
621 ptrOperands.push_back(ptrInfo.pointerTypeID);
622 ptrOperands.push_back(
static_cast<uint32_t
>(ptrInfo.storageClass));
623 ptrOperands.push_back(typeIDMap[type]);
629 recursiveStructInfos[type].clear();
635 return emitError(loc,
"failed to process type: ") << type;
638LogicalResult Serializer::prepareBasicType(
639 Location loc, Type type, uint32_t resultID, spirv::Opcode &typeEnum,
640 SmallVectorImpl<uint32_t> &operands,
bool &deferSerialization,
642 deferSerialization =
false;
644 if (isVoidType(type)) {
645 typeEnum = spirv::Opcode::OpTypeVoid;
649 if (
auto intType = dyn_cast<IntegerType>(type)) {
650 if (intType.getWidth() == 1) {
651 typeEnum = spirv::Opcode::OpTypeBool;
655 typeEnum = spirv::Opcode::OpTypeInt;
656 operands.push_back(intType.getWidth());
661 operands.push_back(intType.isSigned() ? 1 : 0);
665 if (
auto floatType = dyn_cast<FloatType>(type)) {
666 typeEnum = spirv::Opcode::OpTypeFloat;
667 operands.push_back(floatType.getWidth());
668 if (floatType.isBF16()) {
669 operands.push_back(
static_cast<uint32_t
>(spirv::FPEncoding::BFloat16KHR));
671 if (floatType.isF8E4M3FN()) {
673 static_cast<uint32_t
>(spirv::FPEncoding::Float8E4M3EXT));
675 if (floatType.isF8E5M2()) {
677 static_cast<uint32_t
>(spirv::FPEncoding::Float8E5M2EXT));
683 if (
auto vectorType = dyn_cast<VectorType>(type)) {
684 uint32_t elementTypeID = 0;
685 if (
failed(processTypeImpl(loc, vectorType.getElementType(), elementTypeID,
686 serializationCtx))) {
689 typeEnum = spirv::Opcode::OpTypeVector;
690 operands.push_back(elementTypeID);
691 operands.push_back(vectorType.getNumElements());
695 if (
auto imageType = dyn_cast<spirv::ImageType>(type)) {
696 typeEnum = spirv::Opcode::OpTypeImage;
697 uint32_t sampledTypeID = 0;
698 if (
failed(processType(loc, imageType.getElementType(), sampledTypeID)))
701 llvm::append_values(operands, sampledTypeID,
702 static_cast<uint32_t
>(imageType.getDim()),
703 static_cast<uint32_t
>(imageType.getDepthInfo()),
704 static_cast<uint32_t
>(imageType.getArrayedInfo()),
705 static_cast<uint32_t
>(imageType.getSamplingInfo()),
706 static_cast<uint32_t
>(imageType.getSamplerUseInfo()),
707 static_cast<uint32_t
>(imageType.getImageFormat()));
711 if (
auto arrayType = dyn_cast<spirv::ArrayType>(type)) {
712 typeEnum = spirv::Opcode::OpTypeArray;
713 uint32_t elementTypeID = 0;
714 if (
failed(processTypeImpl(loc, arrayType.getElementType(), elementTypeID,
715 serializationCtx))) {
718 operands.push_back(elementTypeID);
719 if (
auto elementCountID = prepareConstantInt(
720 loc, mlirBuilder.getI32IntegerAttr(arrayType.getNumElements()))) {
721 operands.push_back(elementCountID);
723 return processTypeDecoration(loc, arrayType, resultID);
726 if (
auto ptrType = dyn_cast<spirv::PointerType>(type)) {
727 uint32_t pointeeTypeID = 0;
728 spirv::StructType pointeeStruct =
729 dyn_cast<spirv::StructType>(ptrType.getPointeeType());
732 serializationCtx.count(pointeeStruct.
getIdentifier()) != 0) {
737 SmallVector<uint32_t, 2> forwardPtrOperands;
738 forwardPtrOperands.push_back(resultID);
739 forwardPtrOperands.push_back(
740 static_cast<uint32_t
>(ptrType.getStorageClass()));
743 spirv::Opcode::OpTypeForwardPointer,
755 deferSerialization =
true;
759 recursiveStructInfos[structType].push_back(
760 {resultID, ptrType.getStorageClass()});
762 if (
failed(processTypeImpl(loc, ptrType.getPointeeType(), pointeeTypeID,
767 typeEnum = spirv::Opcode::OpTypePointer;
768 operands.push_back(
static_cast<uint32_t
>(ptrType.getStorageClass()));
769 operands.push_back(pointeeTypeID);
774 if (isInterfaceStructPtrType(ptrType)) {
775 auto structType = cast<spirv::StructType>(ptrType.getPointeeType());
776 if (!structType.hasDecoration(spirv::Decoration::Block) &&
777 !structType.hasDecoration(spirv::Decoration::BufferBlock))
778 if (
failed(emitDecoration(getTypeID(pointeeStruct),
779 spirv::Decoration::Block)))
780 return emitError(loc,
"cannot decorate ")
781 << pointeeStruct <<
" with Block decoration";
787 if (
auto runtimeArrayType = dyn_cast<spirv::RuntimeArrayType>(type)) {
788 uint32_t elementTypeID = 0;
789 if (
failed(processTypeImpl(loc, runtimeArrayType.getElementType(),
790 elementTypeID, serializationCtx))) {
793 typeEnum = spirv::Opcode::OpTypeRuntimeArray;
794 operands.push_back(elementTypeID);
795 return processTypeDecoration(loc, runtimeArrayType, resultID);
798 if (isa<spirv::SamplerType>(type)) {
799 typeEnum = spirv::Opcode::OpTypeSampler;
803 if (isa<spirv::NamedBarrierType>(type)) {
804 typeEnum = spirv::Opcode::OpTypeNamedBarrier;
808 if (
auto sampledImageType = dyn_cast<spirv::SampledImageType>(type)) {
809 typeEnum = spirv::Opcode::OpTypeSampledImage;
810 uint32_t imageTypeID = 0;
812 processType(loc, sampledImageType.getImageType(), imageTypeID))) {
815 operands.push_back(imageTypeID);
819 if (
auto structType = dyn_cast<spirv::StructType>(type)) {
820 if (structType.isIdentified()) {
821 if (
failed(processName(resultID, structType.getIdentifier())))
823 serializationCtx.insert(structType.getIdentifier());
826 bool hasOffset = structType.hasOffset();
827 for (
auto elementIndex :
828 llvm::seq<uint32_t>(0, structType.getNumElements())) {
829 uint32_t elementTypeID = 0;
830 if (
failed(processTypeImpl(loc, structType.getElementType(elementIndex),
831 elementTypeID, serializationCtx))) {
834 operands.push_back(elementTypeID);
836 auto intType = IntegerType::get(structType.getContext(), 32);
838 spirv::StructType::MemberDecorationInfo offsetDecoration{
839 elementIndex, spirv::Decoration::Offset,
840 IntegerAttr::get(intType,
841 structType.getMemberOffset(elementIndex))};
842 if (
failed(processMemberDecoration(resultID, offsetDecoration))) {
843 return emitError(loc,
"cannot decorate ")
844 << elementIndex <<
"-th member of " << structType
845 <<
" with its offset";
849 SmallVector<spirv::StructType::MemberDecorationInfo, 4> memberDecorations;
850 structType.getMemberDecorations(memberDecorations);
852 for (
auto &memberDecoration : memberDecorations) {
853 if (
failed(processMemberDecoration(resultID, memberDecoration))) {
854 return emitError(loc,
"cannot decorate ")
855 <<
static_cast<uint32_t
>(memberDecoration.
memberIndex)
856 <<
"-th member of " << structType <<
" with "
857 << stringifyDecoration(memberDecoration.
decoration);
861 SmallVector<spirv::StructType::StructDecorationInfo, 1> structDecorations;
862 structType.getStructDecorations(structDecorations);
864 for (spirv::StructType::StructDecorationInfo &structDecoration :
866 if (
failed(processDecorationAttr(loc, resultID,
867 structDecoration.decoration,
868 structDecoration.decorationValue))) {
869 return emitError(loc,
"cannot decorate struct ")
870 << structType <<
" with "
871 << stringifyDecoration(structDecoration.decoration);
875 typeEnum = spirv::Opcode::OpTypeStruct;
877 if (structType.isIdentified())
878 serializationCtx.remove(structType.getIdentifier());
883 if (
auto cooperativeMatrixType =
884 dyn_cast<spirv::CooperativeMatrixType>(type)) {
885 uint32_t elementTypeID = 0;
886 if (
failed(processTypeImpl(loc, cooperativeMatrixType.getElementType(),
887 elementTypeID, serializationCtx))) {
890 typeEnum = spirv::Opcode::OpTypeCooperativeMatrixKHR;
891 auto getConstantOp = [&](uint32_t id) {
892 auto attr = IntegerAttr::get(IntegerType::get(type.
getContext(), 32),
id);
893 return prepareConstantInt(loc, attr);
896 operands, elementTypeID,
897 getConstantOp(
static_cast<uint32_t
>(cooperativeMatrixType.getScope())),
898 getConstantOp(cooperativeMatrixType.getRows()),
899 getConstantOp(cooperativeMatrixType.getColumns()),
900 getConstantOp(
static_cast<uint32_t
>(cooperativeMatrixType.getUse())));
904 if (
auto matrixType = dyn_cast<spirv::MatrixType>(type)) {
905 uint32_t elementTypeID = 0;
906 if (
failed(processTypeImpl(loc, matrixType.getColumnType(), elementTypeID,
907 serializationCtx))) {
910 typeEnum = spirv::Opcode::OpTypeMatrix;
911 llvm::append_values(operands, elementTypeID, matrixType.getNumColumns());
915 if (
auto tensorArmType = dyn_cast<TensorArmType>(type)) {
916 uint32_t elementTypeID = 0;
918 uint32_t shapeID = 0;
920 if (
failed(processTypeImpl(loc, tensorArmType.getElementType(),
921 elementTypeID, serializationCtx))) {
924 if (tensorArmType.hasRank()) {
925 ArrayRef<int64_t> dims = tensorArmType.getShape();
927 rankID = prepareConstantInt(loc, mlirBuilder.getI32IntegerAttr(rank));
932 bool shaped = llvm::all_of(dims, [](
const auto &dim) {
return dim > 0; });
933 if (rank > 0 && shaped) {
934 auto I32Type = IntegerType::get(type.
getContext(), 32);
937 SmallVector<uint64_t, 1> index(rank);
938 shapeID = prepareDenseElementsConstant(
940 mlirBuilder.getI32TensorAttr(SmallVector<int32_t>(dims)), 0,
943 shapeID = prepareArrayConstant(
945 mlirBuilder.getI32ArrayAttr(SmallVector<int32_t>(dims)));
952 typeEnum = spirv::Opcode::OpTypeTensorARM;
953 operands.push_back(elementTypeID);
956 operands.push_back(rankID);
959 operands.push_back(shapeID);
964 return emitError(loc,
"unhandled type in serialization: ") << type;
968Serializer::prepareFunctionType(Location loc, FunctionType type,
969 spirv::Opcode &typeEnum,
970 SmallVectorImpl<uint32_t> &operands) {
971 typeEnum = spirv::Opcode::OpTypeFunction;
972 assert(type.getNumResults() <= 1 &&
973 "serialization supports only a single return value");
974 uint32_t resultID = 0;
976 loc, type.getNumResults() == 1 ? type.getResult(0) : getVoidType(),
980 operands.push_back(resultID);
981 for (
auto &res : type.getInputs()) {
982 uint32_t argTypeID = 0;
983 if (
failed(processType(loc, res, argTypeID))) {
986 operands.push_back(argTypeID);
992Serializer::prepareGraphType(Location loc, GraphType type,
993 spirv::Opcode &typeEnum,
994 SmallVectorImpl<uint32_t> &operands) {
995 typeEnum = spirv::Opcode::OpTypeGraphARM;
996 assert(type.getNumResults() >= 1 &&
997 "serialization requires at least a return value");
999 operands.push_back(type.getNumInputs());
1001 for (Type argType : type.getInputs()) {
1002 uint32_t argTypeID = 0;
1003 if (
failed(processType(loc, argType, argTypeID)))
1005 operands.push_back(argTypeID);
1008 for (Type resType : type.getResults()) {
1009 uint32_t resTypeID = 0;
1010 if (
failed(processType(loc, resType, resTypeID)))
1012 operands.push_back(resTypeID);
1022uint32_t Serializer::prepareConstant(Location loc, Type constType,
1023 Attribute valueAttr) {
1024 if (
auto id = prepareConstantScalar(loc, valueAttr)) {
1031 if (
auto id = getConstantID(valueAttr)) {
1035 uint32_t typeID = 0;
1036 if (
failed(processType(loc, constType, typeID))) {
1040 uint32_t resultID = 0;
1041 if (
auto attr = dyn_cast<DenseElementsAttr>(valueAttr)) {
1042 int rank = dyn_cast<ShapedType>(attr.getType()).getRank();
1043 SmallVector<uint64_t, 4> index(rank);
1044 resultID = prepareDenseElementsConstant(loc, constType, attr,
1046 }
else if (
auto arrayAttr = dyn_cast<ArrayAttr>(valueAttr)) {
1047 resultID = prepareArrayConstant(loc, constType, arrayAttr);
1050 if (resultID == 0) {
1051 emitError(loc,
"cannot serialize attribute: ") << valueAttr;
1055 constIDMap[valueAttr] = resultID;
1059uint32_t Serializer::prepareArrayConstant(Location loc, Type constType,
1061 uint32_t typeID = 0;
1062 if (
failed(processType(loc, constType, typeID))) {
1066 uint32_t resultID = getNextID();
1067 SmallVector<uint32_t, 4> operands = {typeID, resultID};
1068 operands.reserve(attr.size() + 2);
1069 spirv::CompositeType compositeType = cast<spirv::CompositeType>(constType);
1070 for (
auto [idx, elementAttr] : llvm::enumerate(attr)) {
1071 if (uint32_t elementID = prepareConstant(
1073 operands.push_back(elementID);
1078 encodeInstructionWithContinuationInto(
1079 typesGlobalValues, spirv::Opcode::OpConstantComposite, operands);
1087Serializer::prepareDenseElementsConstant(Location loc, Type constType,
1088 DenseElementsAttr valueAttr,
int dim,
1089 MutableArrayRef<uint64_t> index) {
1090 auto shapedType = dyn_cast<ShapedType>(valueAttr.
getType());
1091 assert(dim <= shapedType.getRank());
1092 if (shapedType.getRank() == dim) {
1093 if (
auto attr = dyn_cast<DenseIntElementsAttr>(valueAttr)) {
1094 return attr.getType().getElementType().isInteger(1)
1095 ? prepareConstantBool(loc, attr.getValues<BoolAttr>()[index])
1096 : prepareConstantInt(loc,
1097 attr.getValues<IntegerAttr>()[index]);
1099 if (
auto attr = dyn_cast<DenseFPElementsAttr>(valueAttr)) {
1100 return prepareConstantFp(loc, attr.getValues<FloatAttr>()[index]);
1105 uint32_t typeID = 0;
1106 if (
failed(processType(loc, constType, typeID))) {
1110 int64_t numberOfConstituents = shapedType.getDimSize(dim);
1111 uint32_t resultID = getNextID();
1112 SmallVector<uint32_t, 4> operands = {typeID, resultID};
1113 auto elementType = cast<spirv::CompositeType>(constType).getElementType(0);
1114 if (
auto tensorArmType = dyn_cast<spirv::TensorArmType>(constType)) {
1115 ArrayRef<int64_t> innerShape = tensorArmType.getShape().drop_front();
1116 if (!innerShape.empty())
1124 if (isa<spirv::CooperativeMatrixType>(constType)) {
1128 "cannot serialize a non-splat value for a cooperative matrix type");
1133 operands.reserve(3);
1136 if (
auto elementID = prepareDenseElementsConstant(
1137 loc, elementType, valueAttr, shapedType.getRank(), index)) {
1138 operands.push_back(elementID);
1142 }
else if (isa<spirv::TensorArmType>(constType) &&
isZeroValue(valueAttr)) {
1144 {typeID, resultID});
1147 operands.reserve(numberOfConstituents + 2);
1148 for (
int i = 0; i < numberOfConstituents; ++i) {
1150 if (
auto elementID = prepareDenseElementsConstant(
1151 loc, elementType, valueAttr, dim + 1, index)) {
1152 operands.push_back(elementID);
1158 encodeInstructionWithContinuationInto(
1159 typesGlobalValues, spirv::Opcode::OpConstantComposite, operands);
1164uint32_t Serializer::prepareConstantScalar(Location loc, Attribute valueAttr,
1166 if (
auto floatAttr = dyn_cast<FloatAttr>(valueAttr)) {
1167 return prepareConstantFp(loc, floatAttr, isSpec);
1169 if (
auto boolAttr = dyn_cast<BoolAttr>(valueAttr)) {
1170 return prepareConstantBool(loc, boolAttr, isSpec);
1172 if (
auto intAttr = dyn_cast<IntegerAttr>(valueAttr)) {
1173 return prepareConstantInt(loc, intAttr, isSpec);
1179uint32_t Serializer::prepareConstantBool(Location loc, BoolAttr boolAttr,
1183 if (
auto id = getConstantID(boolAttr)) {
1189 uint32_t typeID = 0;
1190 if (
failed(processType(loc, cast<IntegerAttr>(boolAttr).
getType(), typeID))) {
1194 auto resultID = getNextID();
1196 ? (isSpec ? spirv::Opcode::OpSpecConstantTrue
1197 : spirv::Opcode::OpConstantTrue)
1198 : (isSpec ? spirv::Opcode::OpSpecConstantFalse
1199 : spirv::Opcode::OpConstantFalse);
1203 constIDMap[boolAttr] = resultID;
1208uint32_t Serializer::prepareConstantInt(Location loc, IntegerAttr intAttr,
1212 if (
auto id = getConstantID(intAttr)) {
1218 uint32_t typeID = 0;
1219 if (
failed(processType(loc, intAttr.getType(), typeID))) {
1223 auto resultID = getNextID();
1224 APInt value = intAttr.getValue();
1225 unsigned bitwidth = value.getBitWidth();
1226 bool isSigned = intAttr.getType().isSignedInteger();
1228 isSpec ? spirv::Opcode::OpSpecConstant : spirv::Opcode::OpConstant;
1241 word =
static_cast<int32_t
>(value.getSExtValue());
1243 word =
static_cast<uint32_t
>(value.getZExtValue());
1255 words = llvm::bit_cast<DoubleWord>(value.getSExtValue());
1257 words = llvm::bit_cast<DoubleWord>(value.getZExtValue());
1260 {typeID, resultID, words.word1, words.word2});
1263 std::string valueStr;
1264 llvm::raw_string_ostream rss(valueStr);
1265 value.print(rss,
false);
1268 << bitwidth <<
"-bit integer literal: " << valueStr;
1274 constIDMap[intAttr] = resultID;
1279uint32_t Serializer::prepareGraphConstantId(Location loc, Type graphConstType,
1280 IntegerAttr intAttr) {
1282 if (uint32_t
id = getGraphConstantARMId(intAttr)) {
1287 uint32_t typeID = 0;
1288 if (
failed(processType(loc, graphConstType, typeID))) {
1292 uint32_t resultID = getNextID();
1293 APInt value = intAttr.getValue();
1294 unsigned bitwidth = value.getBitWidth();
1295 if (bitwidth > 32) {
1296 emitError(loc,
"Too wide attribute for OpGraphConstantARM: ")
1297 << bitwidth <<
" bits";
1300 bool isSigned = value.isSignedIntN(bitwidth);
1304 word =
static_cast<int32_t
>(value.getSExtValue());
1306 word =
static_cast<uint32_t
>(value.getZExtValue());
1309 {typeID, resultID, word});
1310 graphConstIDMap[intAttr] = resultID;
1314uint32_t Serializer::prepareConstantFp(Location loc, FloatAttr floatAttr,
1318 if (
auto id = getConstantID(floatAttr)) {
1324 uint32_t typeID = 0;
1325 if (
failed(processType(loc, floatAttr.getType(), typeID))) {
1329 auto resultID = getNextID();
1330 APFloat value = floatAttr.getValue();
1331 const llvm::fltSemantics *semantics = &value.getSemantics();
1334 isSpec ? spirv::Opcode::OpSpecConstant : spirv::Opcode::OpConstant;
1336 if (semantics == &APFloat::IEEEsingle()) {
1337 uint32_t word = llvm::bit_cast<uint32_t>(value.convertToFloat());
1339 }
else if (semantics == &APFloat::IEEEdouble()) {
1343 } words = llvm::bit_cast<DoubleWord>(value.convertToDouble());
1345 {typeID, resultID, words.word1, words.word2});
1346 }
else if (llvm::is_contained({&APFloat::IEEEhalf(), &APFloat::BFloat(),
1347 &APFloat::Float8E4M3FN(),
1348 &APFloat::Float8E5M2()},
1351 static_cast<uint32_t
>(value.bitcastToAPInt().getZExtValue());
1354 std::string valueStr;
1355 llvm::raw_string_ostream rss(valueStr);
1359 << floatAttr.getType() <<
"-typed float literal: " << valueStr;
1364 constIDMap[floatAttr] = resultID;
1373 if (
auto typedAttr = dyn_cast<TypedAttr>(attr)) {
1374 return typedAttr.getType();
1377 if (
auto arrayAttr = dyn_cast<ArrayAttr>(attr)) {
1384uint32_t Serializer::prepareConstantCompositeReplicate(
Location loc,
1387 std::pair<Attribute, Type> valueTypePair{valueAttr, resultType};
1388 if (uint32_t
id = getConstantCompositeReplicateID(valueTypePair)) {
1392 uint32_t typeID = 0;
1393 if (
failed(processType(loc, resultType, typeID))) {
1401 auto compositeType = dyn_cast<CompositeType>(resultType);
1406 uint32_t constandID;
1407 if (elementType == valueType) {
1408 constandID = prepareConstant(loc, elementType, valueAttr);
1410 constandID = prepareConstantCompositeReplicate(loc, elementType, valueAttr);
1413 uint32_t resultID = getNextID();
1414 if (dyn_cast<spirv::TensorArmType>(resultType) &&
isZeroValue(valueAttr)) {
1416 {typeID, resultID});
1419 spirv::Opcode::OpConstantCompositeReplicateEXT,
1420 {typeID, resultID, constandID});
1423 constCompositeReplicateIDMap[valueTypePair] = resultID;
1431uint32_t Serializer::getOrCreateBlockID(
Block *block) {
1432 if (uint32_t
id = getBlockID(block))
1434 return blockIDMap[block] = getNextID();
1438void Serializer::printBlock(
Block *block, raw_ostream &os) {
1439 os <<
"block " << block <<
" (id = ";
1440 if (uint32_t
id = getBlockID(block))
1449Serializer::processBlock(
Block *block,
bool omitLabel,
1451 LLVM_DEBUG(llvm::dbgs() <<
"processing block " << block <<
":\n");
1452 LLVM_DEBUG(block->
print(llvm::dbgs()));
1453 LLVM_DEBUG(llvm::dbgs() <<
'\n');
1455 uint32_t blockID = getOrCreateBlockID(block);
1456 LLVM_DEBUG(printBlock(block, llvm::dbgs()));
1463 if (
failed(emitPhiForBlockArguments(block)))
1473 llvm::IsaPred<spirv::LoopOp, spirv::SelectionOp>)) {
1476 emitMerge =
nullptr;
1479 uint32_t blockID = getNextID();
1485 for (Operation &op : llvm::drop_end(*block)) {
1486 if (
failed(processOperation(&op)))
1494 if (
failed(processOperation(&block->
back())))
1500LogicalResult Serializer::emitPhiForBlockArguments(
Block *block) {
1506 LLVM_DEBUG(llvm::dbgs() <<
"emitting phi instructions..\n");
1513 SmallVector<std::pair<Block *, OperandRange>, 4> predecessors;
1515 auto *terminator = mlirPredecessor->getTerminator();
1516 LLVM_DEBUG(llvm::dbgs() <<
" mlir predecessor ");
1517 LLVM_DEBUG(printBlock(mlirPredecessor, llvm::dbgs()));
1518 LLVM_DEBUG(llvm::dbgs() <<
" terminator: " << *terminator <<
"\n");
1527 LLVM_DEBUG(llvm::dbgs() <<
" spirv predecessor ");
1528 LLVM_DEBUG(printBlock(spirvPredecessor, llvm::dbgs()));
1529 if (
auto branchOp = dyn_cast<spirv::BranchOp>(terminator)) {
1530 predecessors.emplace_back(spirvPredecessor, branchOp.getOperands());
1531 }
else if (
auto branchCondOp =
1532 dyn_cast<spirv::BranchConditionalOp>(terminator)) {
1533 std::optional<OperandRange> blockOperands;
1534 if (branchCondOp.getTrueTarget() == block) {
1535 blockOperands = branchCondOp.getTrueTargetOperands();
1537 assert(branchCondOp.getFalseTarget() == block);
1538 blockOperands = branchCondOp.getFalseTargetOperands();
1540 assert(!blockOperands->empty() &&
1541 "expected non-empty block operand range");
1542 predecessors.emplace_back(spirvPredecessor, *blockOperands);
1543 }
else if (
auto switchOp = dyn_cast<spirv::SwitchOp>(terminator)) {
1544 std::optional<OperandRange> blockOperands;
1545 if (block == switchOp.getDefaultTarget()) {
1546 blockOperands = switchOp.getDefaultOperands();
1548 SuccessorRange targets = switchOp.getTargets();
1549 auto it = llvm::find(targets, block);
1550 assert(it != targets.end());
1551 size_t index = std::distance(targets.begin(), it);
1552 blockOperands = switchOp.getTargetOperands(index);
1554 assert(!blockOperands->empty() &&
1555 "expected non-empty block operand range");
1556 predecessors.emplace_back(spirvPredecessor, *blockOperands);
1558 return terminator->emitError(
"unimplemented terminator for Phi creation");
1561 llvm::dbgs() <<
" block arguments:\n";
1562 for (Value v : predecessors.back().second)
1563 llvm::dbgs() <<
" " << v <<
"\n";
1568 for (
auto argIndex : llvm::seq<unsigned>(0, block->
getNumArguments())) {
1572 uint32_t phiTypeID = 0;
1575 uint32_t phiID = getNextID();
1577 LLVM_DEBUG(llvm::dbgs() <<
"[phi] for block argument #" << argIndex <<
' '
1578 << arg <<
" (id = " << phiID <<
")\n");
1581 SmallVector<uint32_t, 8> phiArgs;
1582 phiArgs.push_back(phiTypeID);
1583 phiArgs.push_back(phiID);
1585 for (
auto predIndex : llvm::seq<unsigned>(0, predecessors.size())) {
1586 Value value = predecessors[predIndex].second[argIndex];
1587 uint32_t predBlockId = getOrCreateBlockID(predecessors[predIndex].first);
1588 LLVM_DEBUG(llvm::dbgs() <<
"[phi] use predecessor (id = " << predBlockId
1589 <<
") value " << value <<
' ');
1591 uint32_t valueId = getValueID(value);
1595 LLVM_DEBUG(llvm::dbgs() <<
"(need to fix)\n");
1596 deferredPhiValues[value].push_back(functionBody.size() + 1 +
1599 LLVM_DEBUG(llvm::dbgs() <<
"(id = " << valueId <<
")\n");
1601 phiArgs.push_back(valueId);
1603 phiArgs.push_back(predBlockId);
1607 valueIDMap[arg] = phiID;
1617LogicalResult Serializer::encodeExtensionInstruction(
1618 Operation *op, StringRef extensionSetName, uint32_t extensionOpcode,
1619 ArrayRef<uint32_t> operands, SmallVectorImpl<uint32_t> &binary) {
1621 auto &setID = extendedInstSetIDMap[extensionSetName];
1623 setID = getNextID();
1624 SmallVector<uint32_t, 16> importOperands;
1625 importOperands.push_back(setID);
1633 if (operands.size() < 2) {
1634 return op->
emitError(
"extended instructions must have a result encoding");
1636 SmallVector<uint32_t, 8> extInstOperands;
1637 extInstOperands.reserve(operands.size() + 2);
1638 extInstOperands.append(operands.begin(), std::next(operands.begin(), 2));
1639 extInstOperands.push_back(setID);
1640 extInstOperands.push_back(extensionOpcode);
1641 extInstOperands.append(std::next(operands.begin(), 2), operands.end());
1646LogicalResult Serializer::encodeExtensionInstruction(
1647 Operation *op, StringRef extensionSetName, uint32_t extensionOpcode,
1648 ArrayRef<uint32_t> operands) {
1649 if (
failed(encodeExtensionInstruction(op, extensionSetName, extensionOpcode,
1650 operands, functionBody)))
1653 if (extensionSetName ==
extTosa)
1654 updateTosaOpsMap(op);
1659LogicalResult Serializer::processOperation(Operation *opInst) {
1660 LLVM_DEBUG(llvm::dbgs() <<
"[op] '" << opInst->
getName() <<
"'\n");
1665 .Case([&](spirv::AddressOfOp op) {
return processAddressOfOp(op); })
1666 .Case([&](spirv::BranchOp op) {
return processBranchOp(op); })
1667 .Case([&](spirv::BranchConditionalOp op) {
1668 return processBranchConditionalOp(op);
1670 .Case([&](spirv::ConstantOp op) {
return processConstantOp(op); })
1671 .Case([&](spirv::CompositeConstructOp op) {
1672 return processCompositeConstructOp(op);
1674 .Case([&](spirv::EXTConstantCompositeReplicateOp op) {
1675 return processConstantCompositeReplicateOp(op);
1677 .Case([&](spirv::FuncOp op) {
return processFuncOp(op); })
1678 .Case([&](spirv::GraphARMOp op) {
return processGraphARMOp(op); })
1679 .Case([&](spirv::GraphEntryPointARMOp op) {
1680 return processGraphEntryPointARMOp(op);
1682 .Case([&](spirv::GraphOutputsARMOp op) {
1683 return processGraphOutputsARMOp(op);
1685 .Case([&](spirv::GlobalVariableOp op) {
1686 return processGlobalVariableOp(op);
1688 .Case([&](spirv::GraphConstantARMOp op) {
1689 return processGraphConstantARMOp(op);
1691 .Case([&](spirv::LoopOp op) {
return processLoopOp(op); })
1692 .Case([&](spirv::ReferenceOfOp op) {
return processReferenceOfOp(op); })
1693 .Case([&](spirv::SelectionOp op) {
return processSelectionOp(op); })
1694 .Case([&](spirv::SpecConstantOp op) {
return processSpecConstantOp(op); })
1695 .Case([&](spirv::SpecConstantCompositeOp op) {
1696 return processSpecConstantCompositeOp(op);
1698 .Case([&](spirv::EXTSpecConstantCompositeReplicateOp op) {
1699 return processSpecConstantCompositeReplicateOp(op);
1701 .Case([&](spirv::SpecConstantOperationOp op) {
1702 return processSpecConstantOperationOp(op);
1704 .Case([&](spirv::SwitchOp op) {
return processSwitchOp(op); })
1705 .Case([&](spirv::UndefOp op) {
return processUndefOp(op); })
1706 .Case([&](spirv::VariableOp op) {
return processVariableOp(op); })
1711 [&](Operation *op) {
return dispatchToAutogenSerialization(op); });
1715Serializer::processCompositeConstructOp(spirv::CompositeConstructOp op) {
1716 Location loc = op.getLoc();
1718 uint32_t resultTypeID = 0;
1719 if (
failed(processType(loc, op.getType(), resultTypeID)))
1722 uint32_t resultID = getNextID();
1723 valueIDMap[op.getResult()] = resultID;
1725 SmallVector<uint32_t, 8> operands;
1726 operands.reserve(2 + op.getConstituents().size());
1727 operands.push_back(resultTypeID);
1728 operands.push_back(resultID);
1729 for (Value constituent : op.getConstituents()) {
1730 uint32_t
id = getValueID(constituent);
1731 assert(
id &&
"use before def!");
1732 operands.push_back(
id);
1735 if (
failed(emitDebugLine(functionBody, loc)))
1738 encodeInstructionWithContinuationInto(
1739 functionBody, spirv::Opcode::OpCompositeConstruct, operands);
1741 for (
auto attr : op->getAttrs()) {
1742 if (
failed(processDecoration(loc, resultID, attr)))
1749LogicalResult Serializer::processOpWithoutGrammarAttr(Operation *op,
1750 StringRef extInstSet,
1752 SmallVector<uint32_t, 4> operands;
1753 Location loc = op->
getLoc();
1755 uint32_t resultID = 0;
1757 uint32_t resultTypeID = 0;
1760 operands.push_back(resultTypeID);
1762 resultID = getNextID();
1763 operands.push_back(resultID);
1764 valueIDMap[op->
getResult(0)] = resultID;
1768 operands.push_back(getValueID(operand));
1772 if (
failed(emitDebugLine(functionBody, loc)))
1775 if (extInstSet.empty()) {
1779 if (
failed(encodeExtensionInstruction(op, extInstSet, opcode, operands)))
1785 if (
failed(processDecoration(loc, resultID, attr)))
1793void Serializer::updateTosaOpsMap(Operation *op) {
1794 if (!options.emitDebugInfo)
1797 if (
auto graphOp = dyn_cast<spirv::GraphARMOp>(op->
getParentOp())) {
1798 if (uint32_t graphID = getFunctionID(graphOp.getName()))
1799 tosaOpsMap[graphID][op->
getLoc()].insert(op);
1803LogicalResult Serializer::emitDecoration(uint32_t
target,
1804 spirv::Decoration decoration,
1805 ArrayRef<uint32_t> params) {
1806 uint32_t wordCount = 3 + params.size();
1807 llvm::append_values(
1810 static_cast<uint32_t
>(decoration));
1811 llvm::append_range(decorations, params);
1815LogicalResult Serializer::emitDecorationId(uint32_t
target,
1816 spirv::Decoration decoration,
1817 ArrayRef<uint32_t> operandIds) {
1818 uint32_t wordCount = 3 + operandIds.size();
1819 llvm::append_values(
1822 static_cast<uint32_t
>(decoration));
1823 llvm::append_range(decorations, operandIds);
1827LogicalResult Serializer::emitDebugLine(SmallVectorImpl<uint32_t> &binary,
1829 if (!options.emitDebugInfo)
1832 if (lastProcessedWasMergeInst) {
1833 lastProcessedWasMergeInst =
false;
1837 auto fileLoc = dyn_cast<FileLineColLoc>(loc);
1840 {fileID, fileLoc.getLine(), fileLoc.getColumn()});
static Block * getStructuredControlFlowOpMergeBlock(Operation *op)
Returns the merge block if the given op is a structured control flow op.
static Block * getPhiIncomingBlock(Block *block)
Given a predecessor block for a block with arguments, returns the block that should be used as the pa...
static bool isZeroValue(Attribute attr)
static void moveFuncDeclarationsToTop(spirv::ModuleOp moduleOp)
Move all functions declaration before functions definitions.
Attributes are known-constant values of operations.
MLIRContext * getContext() const
Return the context this attribute belongs to.
Location getLoc() const
Return the location for this argument.
Block represents an ordered list of Operations.
BlockArgument getArgument(unsigned i)
unsigned getNumArguments()
iterator_range< pred_iterator > getPredecessors()
OpListType & getOperations()
void print(raw_ostream &os)
bool isEntryBlock()
Return if this block is the entry block in the parent region.
Operation * getParentOp()
Returns the closest surrounding operation that contains this block.
llvm::iplist< Operation > OpListType
This is the list of operations in the block.
bool getValue() const
Return the boolean value of this attribute.
bool isSplat() const
Returns true if this attribute corresponds to a splat, i.e.
ShapedType getType() const
Return the type of this ElementsAttr, guaranteed to be a vector or tensor with static shape.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
StringAttr getName() const
Return the name of the attribute.
Attribute getValue() const
Return the value of the attribute.
Operation is the basic unit of execution within MLIR.
ArrayRef< NamedAttribute > getAttrs()
Return all of the attributes on this operation.
Block * getBlock()
Returns the operation block that contains this operation.
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
Location getLoc()
The source location the operation was defined or derived from.
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
InFlightDiagnostic emitError(const Twine &message={})
Emit an error about fatal conditions with this operation, reporting up to any diagnostic handlers tha...
OperationName getName()
The name of an operation is the key identifier for it.
operand_range getOperands()
Returns an iterator on the underlying Value's.
void moveBefore(Operation *existingOp)
Unlink this operation from its current block and insert it right before existingOp which may be in th...
unsigned getNumResults()
Return the number of results held by this operation.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
MLIRContext * getContext() const
Return the MLIRContext in which this type was uniqued.
bool isUnsignedInteger() const
Return true if this is an unsigned integer type (with the specified width).
unsigned getIntOrFloatBitWidth() const
Return the bit width of an integer or a float type, assert failure on other types.
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Type getType() const
Return the type of this value.
Operation * getDefiningOp() const
If this value is the result of an operation, return the operation that defines it.
unsigned getArrayStride() const
Returns the array stride in bytes.
static ArrayType get(Type elementType, unsigned elementCount)
Type getElementType(unsigned) const
unsigned getArrayStride() const
Returns the array stride in bytes.
void printValueIDMap(raw_ostream &os)
(For debugging) prints each value and its corresponding result <id>.
Serializer(spirv::ModuleOp module, const SerializationOptions &options)
Creates a serializer for the given SPIR-V module.
LogicalResult serialize()
Serializes the remembered SPIR-V module.
void collect(SmallVectorImpl< uint32_t > &binary)
Collects the final SPIR-V binary.
static StructType getIdentified(MLIRContext *context, StringRef identifier)
Construct an identified StructType.
bool isIdentified() const
Returns true if the StructType is identified.
StringRef getIdentifier() const
For literal structs, return an empty string.
static TensorArmType get(ArrayRef< int64_t > shape, Type elementType)
static Type getValueType(Attribute attr)
void encodeStringLiteralInto(SmallVectorImpl< uint32_t > &binary, StringRef literal)
Encodes an SPIR-V literal string into the given binary vector.
TargetEnvAttr lookupTargetEnvOrDefault(Operation *op)
Queries the target environment recursively from enclosing symbol table ops containing the given op or...
std::optional< spirv::Opcode > getContinuationOpcode(spirv::Opcode parent)
Returns the SPV_INTEL_long_composites continuation opcode that may follow parent, or std::nullopt if ...
uint32_t getPrefixedOpcode(uint32_t wordCount, spirv::Opcode opcode)
Returns the word-count-prefixed opcode for an SPIR-V instruction.
void encodeInstructionInto(SmallVectorImpl< uint32_t > &binary, spirv::Opcode op, ArrayRef< uint32_t > operands)
Encodes an SPIR-V instruction with the given opcode and operands into the given binary vector.
constexpr uint32_t kMaxWordCount
Max number of words https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#_universal_limits.
void appendModuleHeader(SmallVectorImpl< uint32_t > &header, spirv::Version version, uint32_t idBound)
Appends a SPRI-V module header to header with the given version and idBound.
constexpr unsigned kHeaderWordCount
SPIR-V binary header word count.
constexpr llvm::StringLiteral extTosa
Extension set name for TOSA ops.
static LogicalResult processDecorationList(Location loc, Decoration decoration, Attribute attrList, StringRef attrName, EmitF emitter)
static std::string getDecorationName(StringRef attrName)
Include the generated interface declarations.
Type getType(OpFoldResult ofr)
Returns the int type of the integer in ofr.
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
llvm::SetVector< T, Vector, Set, N > SetVector
llvm::TypeSwitch< T, ResultT > TypeSwitch
llvm::function_ref< Fn > function_ref
Attribute decorationValue