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 auto mm =
static_cast<uint32_t
>(
module.getMemoryModel());
294 auto am =
static_cast<uint32_t
>(
module.getAddressingModel());
302 if (attrName ==
"fp_fast_math_mode")
303 return "FPFastMathMode";
305 if (attrName ==
"fp_rounding_mode")
306 return "FPRoundingMode";
308 if (attrName ==
"cache_control_load_intel")
309 return "CacheControlLoadINTEL";
310 if (attrName ==
"cache_control_store_intel")
311 return "CacheControlStoreINTEL";
313 return llvm::convertToCamelFromSnakeCase(attrName,
true);
316template <
typename AttrTy,
typename EmitF>
319 StringRef attrName, EmitF emitter) {
320 auto arrayAttr = dyn_cast<ArrayAttr>(attrList);
322 return emitError(loc,
"expecting array attribute of ")
323 << attrName <<
" for " << stringifyDecoration(decoration);
325 if (arrayAttr.empty()) {
326 return emitError(loc,
"expecting non-empty array attribute of ")
327 << attrName <<
" for " << stringifyDecoration(decoration);
329 for (
Attribute attr : arrayAttr.getValue()) {
330 auto cacheControlAttr = dyn_cast<AttrTy>(attr);
331 if (!cacheControlAttr) {
332 return emitError(loc,
"expecting array attribute of ")
333 << attrName <<
" for " << stringifyDecoration(decoration);
337 if (failed(emitter(cacheControlAttr)))
343LogicalResult Serializer::processDecorationAttr(
Location loc, uint32_t resultID,
344 Decoration decoration,
347 switch (decoration) {
348 case spirv::Decoration::LinkageAttributes: {
351 auto linkageAttr = dyn_cast<spirv::LinkageAttributesAttr>(attr);
352 auto linkageName = linkageAttr.getLinkageName();
353 auto linkageType = linkageAttr.getLinkageType().getValue();
357 args.push_back(
static_cast<uint32_t
>(linkageType));
360 case spirv::Decoration::FPFastMathMode:
361 if (
auto intAttr = dyn_cast<FPFastMathModeAttr>(attr)) {
362 args.push_back(
static_cast<uint32_t
>(intAttr.getValue()));
365 return emitError(loc,
"expected FPFastMathModeAttr attribute for ")
366 << stringifyDecoration(decoration);
367 case spirv::Decoration::FPRoundingMode:
368 if (
auto intAttr = dyn_cast<FPRoundingModeAttr>(attr)) {
369 args.push_back(
static_cast<uint32_t
>(intAttr.getValue()));
372 return emitError(loc,
"expected FPRoundingModeAttr attribute for ")
373 << stringifyDecoration(decoration);
374 case spirv::Decoration::FuncParamAttr:
376 loc, decoration, attr,
"FunctionParameterAttribute",
377 [&](FunctionParameterAttributeAttr attr) {
378 return emitDecoration(resultID, decoration,
379 {
static_cast<uint32_t
>(attr.getValue())});
381 case spirv::Decoration::Alignment:
382 case spirv::Decoration::MaxByteOffset:
383 case spirv::Decoration::Binding:
384 case spirv::Decoration::DescriptorSet:
385 case spirv::Decoration::Location:
386 case spirv::Decoration::Index:
387 case spirv::Decoration::Offset:
388 case spirv::Decoration::XfbBuffer:
389 case spirv::Decoration::XfbStride:
390 if (
auto intAttr = dyn_cast<IntegerAttr>(attr)) {
391 args.push_back(intAttr.getValue().getZExtValue());
394 return emitError(loc,
"expected integer attribute for ")
395 << stringifyDecoration(decoration);
396 case spirv::Decoration::BuiltIn:
397 if (
auto strAttr = dyn_cast<StringAttr>(attr)) {
398 auto enumVal = spirv::symbolizeBuiltIn(strAttr.getValue());
400 args.push_back(
static_cast<uint32_t
>(*enumVal));
404 << stringifyDecoration(decoration) <<
" decoration attribute "
405 << strAttr.getValue();
407 return emitError(loc,
"expected string attribute for ")
408 << stringifyDecoration(decoration);
409 case spirv::Decoration::Aliased:
410 case spirv::Decoration::AliasedPointer:
411 case spirv::Decoration::Flat:
412 case spirv::Decoration::NonReadable:
413 case spirv::Decoration::NonWritable:
414 case spirv::Decoration::NoPerspective:
415 case spirv::Decoration::NoSignedWrap:
416 case spirv::Decoration::NoUnsignedWrap:
417 case spirv::Decoration::RelaxedPrecision:
418 case spirv::Decoration::Restrict:
419 case spirv::Decoration::RestrictPointer:
420 case spirv::Decoration::NoContraction:
421 case spirv::Decoration::Constant:
422 case spirv::Decoration::Block:
423 case spirv::Decoration::BufferBlock:
424 case spirv::Decoration::CPacked:
425 case spirv::Decoration::Invariant:
426 case spirv::Decoration::Patch:
427 case spirv::Decoration::Coherent:
428 case spirv::Decoration::Volatile:
429 case spirv::Decoration::SaturatedConversion:
432 if (isa<UnitAttr, DecorationAttr>(attr))
435 "expected unit attribute or decoration attribute for ")
436 << stringifyDecoration(decoration);
437 case spirv::Decoration::CacheControlLoadINTEL:
439 loc, decoration, attr,
"CacheControlLoadINTEL",
440 [&](CacheControlLoadINTELAttr attr) {
441 unsigned cacheLevel = attr.getCacheLevel();
442 LoadCacheControl loadCacheControl = attr.getLoadCacheControl();
443 return emitDecoration(
444 resultID, decoration,
445 {cacheLevel,
static_cast<uint32_t
>(loadCacheControl)});
447 case spirv::Decoration::CacheControlStoreINTEL:
449 loc, decoration, attr,
"CacheControlStoreINTEL",
450 [&](CacheControlStoreINTELAttr attr) {
451 unsigned cacheLevel = attr.getCacheLevel();
452 StoreCacheControl storeCacheControl = attr.getStoreCacheControl();
453 return emitDecoration(
454 resultID, decoration,
455 {cacheLevel,
static_cast<uint32_t
>(storeCacheControl)});
457 case spirv::Decoration::AlignmentId:
458 case spirv::Decoration::MaxByteOffsetId:
459 case spirv::Decoration::CounterBuffer: {
460 auto symRef = dyn_cast<FlatSymbolRefAttr>(attr);
462 return emitError(loc,
"expected symbol reference for ")
463 << stringifyDecoration(decoration);
464 StringRef symName = symRef.getValue();
465 uint32_t operandID = getVariableID(symName);
467 operandID = getSpecConstID(symName);
469 return emitError(loc,
"could not find <id> for symbol '")
470 << symName <<
"' referenced by "
471 << stringifyDecoration(decoration);
472 return emitDecorationId(resultID, decoration, {operandID});
475 return emitError(loc,
"unhandled decoration ")
476 << stringifyDecoration(decoration);
478 return emitDecoration(resultID, decoration, args);
481LogicalResult Serializer::processDecoration(Location loc, uint32_t resultID,
482 NamedAttribute attr) {
483 StringRef attrName = attr.
getName().strref();
485 std::optional<Decoration> decoration =
486 spirv::symbolizeDecoration(decorationName);
489 loc,
"non-argument attributes expected to have snake-case-ified "
490 "decoration name, unhandled attribute with name : ")
493 return processDecorationAttr(loc, resultID, *decoration, attr.
getValue());
496LogicalResult Serializer::processName(uint32_t resultID, StringRef name) {
497 assert(!name.empty() &&
"unexpected empty string for OpName");
498 if (!options.emitSymbolName)
501 SmallVector<uint32_t, 4> nameOperands;
502 nameOperands.push_back(resultID);
509LogicalResult Serializer::processTypeDecoration<spirv::ArrayType>(
513 return emitDecoration(resultID, spirv::Decoration::ArrayStride, {stride});
519LogicalResult Serializer::processTypeDecoration<spirv::RuntimeArrayType>(
523 return emitDecoration(resultID, spirv::Decoration::ArrayStride, {stride});
528LogicalResult Serializer::processMemberDecoration(
533 static_cast<uint32_t
>(memberDecoration.
decoration)});
549bool Serializer::isInterfaceStructPtrType(Type type)
const {
550 if (
auto ptrType = dyn_cast<spirv::PointerType>(type)) {
551 switch (ptrType.getStorageClass()) {
552 case spirv::StorageClass::PhysicalStorageBuffer:
553 case spirv::StorageClass::PushConstant:
554 case spirv::StorageClass::StorageBuffer:
555 case spirv::StorageClass::Uniform:
556 return isa<spirv::StructType>(ptrType.getPointeeType());
564LogicalResult Serializer::processType(Location loc, Type type,
569 return processTypeImpl(loc, type, typeID, serializationCtx);
573Serializer::processTypeImpl(Location loc, Type type, uint32_t &typeID,
585 IntegerType::SignednessSemantics::Signless);
588 typeID = getTypeID(type);
592 typeID = getNextID();
593 SmallVector<uint32_t, 4> operands;
595 operands.push_back(typeID);
596 auto typeEnum = spirv::Opcode::OpTypeVoid;
597 bool deferSerialization =
false;
599 if ((isa<FunctionType>(type) &&
600 succeeded(prepareFunctionType(loc, cast<FunctionType>(type), typeEnum,
602 (isa<GraphType>(type) &&
604 prepareGraphType(loc, cast<GraphType>(type), typeEnum, operands))) ||
605 succeeded(prepareBasicType(loc, type, typeID, typeEnum, operands,
606 deferSerialization, serializationCtx))) {
607 if (deferSerialization)
610 typeIDMap[type] = typeID;
612 if (typeEnum == spirv::Opcode::OpTypeStruct)
613 encodeInstructionWithContinuationInto(typesGlobalValues, typeEnum,
618 if (recursiveStructInfos.count(type) != 0) {
621 for (
auto &ptrInfo : recursiveStructInfos[type]) {
624 SmallVector<uint32_t, 4> ptrOperands;
625 ptrOperands.push_back(ptrInfo.pointerTypeID);
626 ptrOperands.push_back(
static_cast<uint32_t
>(ptrInfo.storageClass));
627 ptrOperands.push_back(typeIDMap[type]);
633 recursiveStructInfos[type].clear();
639 return emitError(loc,
"failed to process type: ") << type;
642LogicalResult Serializer::prepareBasicType(
643 Location loc, Type type, uint32_t resultID, spirv::Opcode &typeEnum,
644 SmallVectorImpl<uint32_t> &operands,
bool &deferSerialization,
646 deferSerialization =
false;
648 if (isVoidType(type)) {
649 typeEnum = spirv::Opcode::OpTypeVoid;
653 if (
auto intType = dyn_cast<IntegerType>(type)) {
654 if (intType.getWidth() == 1) {
655 typeEnum = spirv::Opcode::OpTypeBool;
659 typeEnum = spirv::Opcode::OpTypeInt;
660 operands.push_back(intType.getWidth());
665 operands.push_back(intType.isSigned() ? 1 : 0);
669 if (
auto floatType = dyn_cast<FloatType>(type)) {
670 typeEnum = spirv::Opcode::OpTypeFloat;
671 operands.push_back(floatType.getWidth());
672 if (floatType.isBF16()) {
673 operands.push_back(
static_cast<uint32_t
>(spirv::FPEncoding::BFloat16KHR));
675 if (floatType.isF8E4M3FN()) {
677 static_cast<uint32_t
>(spirv::FPEncoding::Float8E4M3EXT));
679 if (floatType.isF8E5M2()) {
681 static_cast<uint32_t
>(spirv::FPEncoding::Float8E5M2EXT));
687 if (
auto vectorType = dyn_cast<VectorType>(type)) {
688 uint32_t elementTypeID = 0;
689 if (
failed(processTypeImpl(loc, vectorType.getElementType(), elementTypeID,
690 serializationCtx))) {
693 typeEnum = spirv::Opcode::OpTypeVector;
694 operands.push_back(elementTypeID);
695 operands.push_back(vectorType.getNumElements());
699 if (
auto imageType = dyn_cast<spirv::ImageType>(type)) {
700 typeEnum = spirv::Opcode::OpTypeImage;
701 uint32_t sampledTypeID = 0;
702 if (
failed(processType(loc, imageType.getElementType(), sampledTypeID)))
705 llvm::append_values(operands, sampledTypeID,
706 static_cast<uint32_t
>(imageType.getDim()),
707 static_cast<uint32_t
>(imageType.getDepthInfo()),
708 static_cast<uint32_t
>(imageType.getArrayedInfo()),
709 static_cast<uint32_t
>(imageType.getSamplingInfo()),
710 static_cast<uint32_t
>(imageType.getSamplerUseInfo()),
711 static_cast<uint32_t
>(imageType.getImageFormat()));
715 if (
auto arrayType = dyn_cast<spirv::ArrayType>(type)) {
716 typeEnum = spirv::Opcode::OpTypeArray;
717 uint32_t elementTypeID = 0;
718 if (
failed(processTypeImpl(loc, arrayType.getElementType(), elementTypeID,
719 serializationCtx))) {
722 operands.push_back(elementTypeID);
723 if (
auto elementCountID = prepareConstantInt(
724 loc, mlirBuilder.getI32IntegerAttr(arrayType.getNumElements()))) {
725 operands.push_back(elementCountID);
727 return processTypeDecoration(loc, arrayType, resultID);
730 if (
auto ptrType = dyn_cast<spirv::PointerType>(type)) {
731 uint32_t pointeeTypeID = 0;
732 spirv::StructType pointeeStruct =
733 dyn_cast<spirv::StructType>(ptrType.getPointeeType());
736 serializationCtx.count(pointeeStruct.
getIdentifier()) != 0) {
741 SmallVector<uint32_t, 2> forwardPtrOperands;
742 forwardPtrOperands.push_back(resultID);
743 forwardPtrOperands.push_back(
744 static_cast<uint32_t
>(ptrType.getStorageClass()));
747 spirv::Opcode::OpTypeForwardPointer,
759 deferSerialization =
true;
763 recursiveStructInfos[structType].push_back(
764 {resultID, ptrType.getStorageClass()});
766 if (
failed(processTypeImpl(loc, ptrType.getPointeeType(), pointeeTypeID,
771 typeEnum = spirv::Opcode::OpTypePointer;
772 operands.push_back(
static_cast<uint32_t
>(ptrType.getStorageClass()));
773 operands.push_back(pointeeTypeID);
778 if (isInterfaceStructPtrType(ptrType)) {
779 auto structType = cast<spirv::StructType>(ptrType.getPointeeType());
780 if (!structType.hasDecoration(spirv::Decoration::Block) &&
781 !structType.hasDecoration(spirv::Decoration::BufferBlock))
782 if (
failed(emitDecoration(getTypeID(pointeeStruct),
783 spirv::Decoration::Block)))
784 return emitError(loc,
"cannot decorate ")
785 << pointeeStruct <<
" with Block decoration";
791 if (
auto runtimeArrayType = dyn_cast<spirv::RuntimeArrayType>(type)) {
792 uint32_t elementTypeID = 0;
793 if (
failed(processTypeImpl(loc, runtimeArrayType.getElementType(),
794 elementTypeID, serializationCtx))) {
797 typeEnum = spirv::Opcode::OpTypeRuntimeArray;
798 operands.push_back(elementTypeID);
799 return processTypeDecoration(loc, runtimeArrayType, resultID);
802 if (isa<spirv::SamplerType>(type)) {
803 typeEnum = spirv::Opcode::OpTypeSampler;
807 if (isa<spirv::NamedBarrierType>(type)) {
808 typeEnum = spirv::Opcode::OpTypeNamedBarrier;
812 if (
auto sampledImageType = dyn_cast<spirv::SampledImageType>(type)) {
813 typeEnum = spirv::Opcode::OpTypeSampledImage;
814 uint32_t imageTypeID = 0;
816 processType(loc, sampledImageType.getImageType(), imageTypeID))) {
819 operands.push_back(imageTypeID);
823 if (
auto structType = dyn_cast<spirv::StructType>(type)) {
824 if (structType.isIdentified()) {
825 if (
failed(processName(resultID, structType.getIdentifier())))
827 serializationCtx.insert(structType.getIdentifier());
830 bool hasOffset = structType.hasOffset();
831 for (
auto elementIndex :
832 llvm::seq<uint32_t>(0, structType.getNumElements())) {
833 uint32_t elementTypeID = 0;
834 if (
failed(processTypeImpl(loc, structType.getElementType(elementIndex),
835 elementTypeID, serializationCtx))) {
838 operands.push_back(elementTypeID);
840 auto intType = IntegerType::get(structType.getContext(), 32);
842 spirv::StructType::MemberDecorationInfo offsetDecoration{
843 elementIndex, spirv::Decoration::Offset,
844 IntegerAttr::get(intType,
845 structType.getMemberOffset(elementIndex))};
846 if (
failed(processMemberDecoration(resultID, offsetDecoration))) {
847 return emitError(loc,
"cannot decorate ")
848 << elementIndex <<
"-th member of " << structType
849 <<
" with its offset";
853 SmallVector<spirv::StructType::MemberDecorationInfo, 4> memberDecorations;
854 structType.getMemberDecorations(memberDecorations);
856 for (
auto &memberDecoration : memberDecorations) {
857 if (
failed(processMemberDecoration(resultID, memberDecoration))) {
858 return emitError(loc,
"cannot decorate ")
859 <<
static_cast<uint32_t
>(memberDecoration.
memberIndex)
860 <<
"-th member of " << structType <<
" with "
861 << stringifyDecoration(memberDecoration.
decoration);
865 SmallVector<spirv::StructType::StructDecorationInfo, 1> structDecorations;
866 structType.getStructDecorations(structDecorations);
868 for (spirv::StructType::StructDecorationInfo &structDecoration :
870 if (
failed(processDecorationAttr(loc, resultID,
871 structDecoration.decoration,
872 structDecoration.decorationValue))) {
873 return emitError(loc,
"cannot decorate struct ")
874 << structType <<
" with "
875 << stringifyDecoration(structDecoration.decoration);
879 typeEnum = spirv::Opcode::OpTypeStruct;
881 if (structType.isIdentified())
882 serializationCtx.remove(structType.getIdentifier());
887 if (
auto cooperativeMatrixType =
888 dyn_cast<spirv::CooperativeMatrixType>(type)) {
889 uint32_t elementTypeID = 0;
890 if (
failed(processTypeImpl(loc, cooperativeMatrixType.getElementType(),
891 elementTypeID, serializationCtx))) {
894 typeEnum = spirv::Opcode::OpTypeCooperativeMatrixKHR;
895 auto getConstantOp = [&](uint32_t id) {
896 auto attr = IntegerAttr::get(IntegerType::get(type.
getContext(), 32),
id);
897 return prepareConstantInt(loc, attr);
900 operands, elementTypeID,
901 getConstantOp(
static_cast<uint32_t
>(cooperativeMatrixType.getScope())),
902 getConstantOp(cooperativeMatrixType.getRows()),
903 getConstantOp(cooperativeMatrixType.getColumns()),
904 getConstantOp(
static_cast<uint32_t
>(cooperativeMatrixType.getUse())));
908 if (
auto matrixType = dyn_cast<spirv::MatrixType>(type)) {
909 uint32_t elementTypeID = 0;
910 if (
failed(processTypeImpl(loc, matrixType.getColumnType(), elementTypeID,
911 serializationCtx))) {
914 typeEnum = spirv::Opcode::OpTypeMatrix;
915 llvm::append_values(operands, elementTypeID, matrixType.getNumColumns());
919 if (
auto tensorArmType = dyn_cast<TensorArmType>(type)) {
920 uint32_t elementTypeID = 0;
922 uint32_t shapeID = 0;
924 if (
failed(processTypeImpl(loc, tensorArmType.getElementType(),
925 elementTypeID, serializationCtx))) {
928 if (tensorArmType.hasRank()) {
929 ArrayRef<int64_t> dims = tensorArmType.getShape();
931 rankID = prepareConstantInt(loc, mlirBuilder.getI32IntegerAttr(rank));
936 bool shaped = llvm::all_of(dims, [](
const auto &dim) {
return dim > 0; });
937 if (rank > 0 && shaped) {
938 auto I32Type = IntegerType::get(type.
getContext(), 32);
941 SmallVector<uint64_t, 1> index(rank);
942 shapeID = prepareDenseElementsConstant(
944 mlirBuilder.getI32TensorAttr(SmallVector<int32_t>(dims)), 0,
947 shapeID = prepareArrayConstant(
949 mlirBuilder.getI32ArrayAttr(SmallVector<int32_t>(dims)));
956 typeEnum = spirv::Opcode::OpTypeTensorARM;
957 operands.push_back(elementTypeID);
960 operands.push_back(rankID);
963 operands.push_back(shapeID);
968 return emitError(loc,
"unhandled type in serialization: ") << type;
972Serializer::prepareFunctionType(Location loc, FunctionType type,
973 spirv::Opcode &typeEnum,
974 SmallVectorImpl<uint32_t> &operands) {
975 typeEnum = spirv::Opcode::OpTypeFunction;
976 assert(type.getNumResults() <= 1 &&
977 "serialization supports only a single return value");
978 uint32_t resultID = 0;
980 loc, type.getNumResults() == 1 ? type.getResult(0) : getVoidType(),
984 operands.push_back(resultID);
985 for (
auto &res : type.getInputs()) {
986 uint32_t argTypeID = 0;
987 if (
failed(processType(loc, res, argTypeID))) {
990 operands.push_back(argTypeID);
996Serializer::prepareGraphType(Location loc, GraphType type,
997 spirv::Opcode &typeEnum,
998 SmallVectorImpl<uint32_t> &operands) {
999 typeEnum = spirv::Opcode::OpTypeGraphARM;
1000 assert(type.getNumResults() >= 1 &&
1001 "serialization requires at least a return value");
1003 operands.push_back(type.getNumInputs());
1005 for (Type argType : type.getInputs()) {
1006 uint32_t argTypeID = 0;
1007 if (
failed(processType(loc, argType, argTypeID)))
1009 operands.push_back(argTypeID);
1012 for (Type resType : type.getResults()) {
1013 uint32_t resTypeID = 0;
1014 if (
failed(processType(loc, resType, resTypeID)))
1016 operands.push_back(resTypeID);
1026uint32_t Serializer::prepareConstant(Location loc, Type constType,
1027 Attribute valueAttr) {
1028 if (
auto id = prepareConstantScalar(loc, valueAttr)) {
1035 if (
auto id = getConstantID(valueAttr)) {
1039 uint32_t typeID = 0;
1040 if (
failed(processType(loc, constType, typeID))) {
1044 uint32_t resultID = 0;
1045 if (
auto attr = dyn_cast<DenseElementsAttr>(valueAttr)) {
1046 int rank = dyn_cast<ShapedType>(attr.getType()).getRank();
1047 SmallVector<uint64_t, 4> index(rank);
1048 resultID = prepareDenseElementsConstant(loc, constType, attr,
1050 }
else if (
auto arrayAttr = dyn_cast<ArrayAttr>(valueAttr)) {
1051 resultID = prepareArrayConstant(loc, constType, arrayAttr);
1054 if (resultID == 0) {
1055 emitError(loc,
"cannot serialize attribute: ") << valueAttr;
1059 constIDMap[valueAttr] = resultID;
1063uint32_t Serializer::prepareArrayConstant(Location loc, Type constType,
1065 uint32_t typeID = 0;
1066 if (
failed(processType(loc, constType, typeID))) {
1070 uint32_t resultID = getNextID();
1071 SmallVector<uint32_t, 4> operands = {typeID, resultID};
1072 operands.reserve(attr.size() + 2);
1073 spirv::CompositeType compositeType = cast<spirv::CompositeType>(constType);
1074 for (
auto [idx, elementAttr] : llvm::enumerate(attr)) {
1075 if (uint32_t elementID = prepareConstant(
1077 operands.push_back(elementID);
1082 encodeInstructionWithContinuationInto(
1083 typesGlobalValues, spirv::Opcode::OpConstantComposite, operands);
1091Serializer::prepareDenseElementsConstant(Location loc, Type constType,
1092 DenseElementsAttr valueAttr,
int dim,
1093 MutableArrayRef<uint64_t> index) {
1094 auto shapedType = dyn_cast<ShapedType>(valueAttr.
getType());
1095 assert(dim <= shapedType.getRank());
1096 if (shapedType.getRank() == dim) {
1097 if (
auto attr = dyn_cast<DenseIntElementsAttr>(valueAttr)) {
1098 return attr.getType().getElementType().isInteger(1)
1099 ? prepareConstantBool(loc, attr.getValues<BoolAttr>()[index])
1100 : prepareConstantInt(loc,
1101 attr.getValues<IntegerAttr>()[index]);
1103 if (
auto attr = dyn_cast<DenseFPElementsAttr>(valueAttr)) {
1104 return prepareConstantFp(loc, attr.getValues<FloatAttr>()[index]);
1109 uint32_t typeID = 0;
1110 if (
failed(processType(loc, constType, typeID))) {
1114 int64_t numberOfConstituents = shapedType.getDimSize(dim);
1115 uint32_t resultID = getNextID();
1116 SmallVector<uint32_t, 4> operands = {typeID, resultID};
1117 auto elementType = cast<spirv::CompositeType>(constType).getElementType(0);
1118 if (
auto tensorArmType = dyn_cast<spirv::TensorArmType>(constType)) {
1119 ArrayRef<int64_t> innerShape = tensorArmType.getShape().drop_front();
1120 if (!innerShape.empty())
1128 if (isa<spirv::CooperativeMatrixType>(constType)) {
1132 "cannot serialize a non-splat value for a cooperative matrix type");
1137 operands.reserve(3);
1140 if (
auto elementID = prepareDenseElementsConstant(
1141 loc, elementType, valueAttr, shapedType.getRank(), index)) {
1142 operands.push_back(elementID);
1146 }
else if (isa<spirv::TensorArmType>(constType) &&
isZeroValue(valueAttr)) {
1148 {typeID, resultID});
1151 operands.reserve(numberOfConstituents + 2);
1152 for (
int i = 0; i < numberOfConstituents; ++i) {
1154 if (
auto elementID = prepareDenseElementsConstant(
1155 loc, elementType, valueAttr, dim + 1, index)) {
1156 operands.push_back(elementID);
1162 encodeInstructionWithContinuationInto(
1163 typesGlobalValues, spirv::Opcode::OpConstantComposite, operands);
1168uint32_t Serializer::prepareConstantScalar(Location loc, Attribute valueAttr,
1170 if (
auto floatAttr = dyn_cast<FloatAttr>(valueAttr)) {
1171 return prepareConstantFp(loc, floatAttr, isSpec);
1173 if (
auto boolAttr = dyn_cast<BoolAttr>(valueAttr)) {
1174 return prepareConstantBool(loc, boolAttr, isSpec);
1176 if (
auto intAttr = dyn_cast<IntegerAttr>(valueAttr)) {
1177 return prepareConstantInt(loc, intAttr, isSpec);
1183uint32_t Serializer::prepareConstantBool(Location loc, BoolAttr boolAttr,
1187 if (
auto id = getConstantID(boolAttr)) {
1193 uint32_t typeID = 0;
1194 if (
failed(processType(loc, cast<IntegerAttr>(boolAttr).
getType(), typeID))) {
1198 auto resultID = getNextID();
1200 ? (isSpec ? spirv::Opcode::OpSpecConstantTrue
1201 : spirv::Opcode::OpConstantTrue)
1202 : (isSpec ? spirv::Opcode::OpSpecConstantFalse
1203 : spirv::Opcode::OpConstantFalse);
1207 constIDMap[boolAttr] = resultID;
1212uint32_t Serializer::prepareConstantInt(Location loc, IntegerAttr intAttr,
1216 if (
auto id = getConstantID(intAttr)) {
1222 uint32_t typeID = 0;
1223 if (
failed(processType(loc, intAttr.getType(), typeID))) {
1227 auto resultID = getNextID();
1228 APInt value = intAttr.getValue();
1229 unsigned bitwidth = value.getBitWidth();
1230 bool isSigned = intAttr.getType().isSignedInteger();
1232 isSpec ? spirv::Opcode::OpSpecConstant : spirv::Opcode::OpConstant;
1245 word =
static_cast<int32_t
>(value.getSExtValue());
1247 word =
static_cast<uint32_t
>(value.getZExtValue());
1259 words = llvm::bit_cast<DoubleWord>(value.getSExtValue());
1261 words = llvm::bit_cast<DoubleWord>(value.getZExtValue());
1264 {typeID, resultID, words.word1, words.word2});
1267 std::string valueStr;
1268 llvm::raw_string_ostream rss(valueStr);
1269 value.print(rss,
false);
1272 << bitwidth <<
"-bit integer literal: " << valueStr;
1278 constIDMap[intAttr] = resultID;
1283uint32_t Serializer::prepareGraphConstantId(Location loc, Type graphConstType,
1284 IntegerAttr intAttr) {
1286 if (uint32_t
id = getGraphConstantARMId(intAttr)) {
1291 uint32_t typeID = 0;
1292 if (
failed(processType(loc, graphConstType, typeID))) {
1296 uint32_t resultID = getNextID();
1297 APInt value = intAttr.getValue();
1298 unsigned bitwidth = value.getBitWidth();
1299 if (bitwidth > 32) {
1300 emitError(loc,
"Too wide attribute for OpGraphConstantARM: ")
1301 << bitwidth <<
" bits";
1304 bool isSigned = value.isSignedIntN(bitwidth);
1308 word =
static_cast<int32_t
>(value.getSExtValue());
1310 word =
static_cast<uint32_t
>(value.getZExtValue());
1313 {typeID, resultID, word});
1314 graphConstIDMap[intAttr] = resultID;
1318uint32_t Serializer::prepareConstantFp(Location loc, FloatAttr floatAttr,
1322 if (
auto id = getConstantID(floatAttr)) {
1328 uint32_t typeID = 0;
1329 if (
failed(processType(loc, floatAttr.getType(), typeID))) {
1333 auto resultID = getNextID();
1334 APFloat value = floatAttr.getValue();
1335 const llvm::fltSemantics *semantics = &value.getSemantics();
1338 isSpec ? spirv::Opcode::OpSpecConstant : spirv::Opcode::OpConstant;
1340 if (semantics == &APFloat::IEEEsingle()) {
1341 uint32_t word = llvm::bit_cast<uint32_t>(value.convertToFloat());
1343 }
else if (semantics == &APFloat::IEEEdouble()) {
1347 } words = llvm::bit_cast<DoubleWord>(value.convertToDouble());
1349 {typeID, resultID, words.word1, words.word2});
1350 }
else if (llvm::is_contained({&APFloat::IEEEhalf(), &APFloat::BFloat(),
1351 &APFloat::Float8E4M3FN(),
1352 &APFloat::Float8E5M2()},
1355 static_cast<uint32_t
>(value.bitcastToAPInt().getZExtValue());
1358 std::string valueStr;
1359 llvm::raw_string_ostream rss(valueStr);
1363 << floatAttr.getType() <<
"-typed float literal: " << valueStr;
1368 constIDMap[floatAttr] = resultID;
1377 if (
auto typedAttr = dyn_cast<TypedAttr>(attr)) {
1378 return typedAttr.getType();
1381 if (
auto arrayAttr = dyn_cast<ArrayAttr>(attr)) {
1388uint32_t Serializer::prepareConstantCompositeReplicate(
Location loc,
1391 std::pair<Attribute, Type> valueTypePair{valueAttr, resultType};
1392 if (uint32_t
id = getConstantCompositeReplicateID(valueTypePair)) {
1396 uint32_t typeID = 0;
1397 if (
failed(processType(loc, resultType, typeID))) {
1405 auto compositeType = dyn_cast<CompositeType>(resultType);
1410 uint32_t constandID;
1411 if (elementType == valueType) {
1412 constandID = prepareConstant(loc, elementType, valueAttr);
1414 constandID = prepareConstantCompositeReplicate(loc, elementType, valueAttr);
1417 uint32_t resultID = getNextID();
1418 if (dyn_cast<spirv::TensorArmType>(resultType) &&
isZeroValue(valueAttr)) {
1420 {typeID, resultID});
1423 spirv::Opcode::OpConstantCompositeReplicateEXT,
1424 {typeID, resultID, constandID});
1427 constCompositeReplicateIDMap[valueTypePair] = resultID;
1435uint32_t Serializer::getOrCreateBlockID(
Block *block) {
1436 if (uint32_t
id = getBlockID(block))
1438 return blockIDMap[block] = getNextID();
1442void Serializer::printBlock(
Block *block, raw_ostream &os) {
1443 os <<
"block " << block <<
" (id = ";
1444 if (uint32_t
id = getBlockID(block))
1453Serializer::processBlock(
Block *block,
bool omitLabel,
1455 LLVM_DEBUG(llvm::dbgs() <<
"processing block " << block <<
":\n");
1456 LLVM_DEBUG(block->
print(llvm::dbgs()));
1457 LLVM_DEBUG(llvm::dbgs() <<
'\n');
1459 uint32_t blockID = getOrCreateBlockID(block);
1460 LLVM_DEBUG(printBlock(block, llvm::dbgs()));
1467 if (
failed(emitPhiForBlockArguments(block)))
1477 llvm::IsaPred<spirv::LoopOp, spirv::SelectionOp>)) {
1480 emitMerge =
nullptr;
1483 uint32_t blockID = getNextID();
1489 for (Operation &op : llvm::drop_end(*block)) {
1490 if (
failed(processOperation(&op)))
1498 if (
failed(processOperation(&block->
back())))
1504LogicalResult Serializer::emitPhiForBlockArguments(
Block *block) {
1510 LLVM_DEBUG(llvm::dbgs() <<
"emitting phi instructions..\n");
1517 SmallVector<std::pair<Block *, OperandRange>, 4> predecessors;
1519 auto *terminator = mlirPredecessor->getTerminator();
1520 LLVM_DEBUG(llvm::dbgs() <<
" mlir predecessor ");
1521 LLVM_DEBUG(printBlock(mlirPredecessor, llvm::dbgs()));
1522 LLVM_DEBUG(llvm::dbgs() <<
" terminator: " << *terminator <<
"\n");
1531 LLVM_DEBUG(llvm::dbgs() <<
" spirv predecessor ");
1532 LLVM_DEBUG(printBlock(spirvPredecessor, llvm::dbgs()));
1533 if (
auto branchOp = dyn_cast<spirv::BranchOp>(terminator)) {
1534 predecessors.emplace_back(spirvPredecessor, branchOp.getOperands());
1535 }
else if (
auto branchCondOp =
1536 dyn_cast<spirv::BranchConditionalOp>(terminator)) {
1537 std::optional<OperandRange> blockOperands;
1538 if (branchCondOp.getTrueTarget() == block) {
1539 blockOperands = branchCondOp.getTrueTargetOperands();
1541 assert(branchCondOp.getFalseTarget() == block);
1542 blockOperands = branchCondOp.getFalseTargetOperands();
1544 assert(!blockOperands->empty() &&
1545 "expected non-empty block operand range");
1546 predecessors.emplace_back(spirvPredecessor, *blockOperands);
1547 }
else if (
auto switchOp = dyn_cast<spirv::SwitchOp>(terminator)) {
1548 std::optional<OperandRange> blockOperands;
1549 if (block == switchOp.getDefaultTarget()) {
1550 blockOperands = switchOp.getDefaultOperands();
1552 SuccessorRange targets = switchOp.getTargets();
1553 auto it = llvm::find(targets, block);
1554 assert(it != targets.end());
1555 size_t index = std::distance(targets.begin(), it);
1556 blockOperands = switchOp.getTargetOperands(index);
1558 assert(!blockOperands->empty() &&
1559 "expected non-empty block operand range");
1560 predecessors.emplace_back(spirvPredecessor, *blockOperands);
1562 return terminator->emitError(
"unimplemented terminator for Phi creation");
1565 llvm::dbgs() <<
" block arguments:\n";
1566 for (Value v : predecessors.back().second)
1567 llvm::dbgs() <<
" " << v <<
"\n";
1572 for (
auto argIndex : llvm::seq<unsigned>(0, block->
getNumArguments())) {
1576 uint32_t phiTypeID = 0;
1579 uint32_t phiID = getNextID();
1581 LLVM_DEBUG(llvm::dbgs() <<
"[phi] for block argument #" << argIndex <<
' '
1582 << arg <<
" (id = " << phiID <<
")\n");
1585 SmallVector<uint32_t, 8> phiArgs;
1586 phiArgs.push_back(phiTypeID);
1587 phiArgs.push_back(phiID);
1589 for (
auto predIndex : llvm::seq<unsigned>(0, predecessors.size())) {
1590 Value value = predecessors[predIndex].second[argIndex];
1591 uint32_t predBlockId = getOrCreateBlockID(predecessors[predIndex].first);
1592 LLVM_DEBUG(llvm::dbgs() <<
"[phi] use predecessor (id = " << predBlockId
1593 <<
") value " << value <<
' ');
1595 uint32_t valueId = getValueID(value);
1599 LLVM_DEBUG(llvm::dbgs() <<
"(need to fix)\n");
1600 deferredPhiValues[value].push_back(functionBody.size() + 1 +
1603 LLVM_DEBUG(llvm::dbgs() <<
"(id = " << valueId <<
")\n");
1605 phiArgs.push_back(valueId);
1607 phiArgs.push_back(predBlockId);
1611 valueIDMap[arg] = phiID;
1621LogicalResult Serializer::encodeExtensionInstruction(
1622 Operation *op, StringRef extensionSetName, uint32_t extensionOpcode,
1623 ArrayRef<uint32_t> operands, SmallVectorImpl<uint32_t> &binary) {
1625 auto &setID = extendedInstSetIDMap[extensionSetName];
1627 setID = getNextID();
1628 SmallVector<uint32_t, 16> importOperands;
1629 importOperands.push_back(setID);
1637 if (operands.size() < 2) {
1638 return op->
emitError(
"extended instructions must have a result encoding");
1640 SmallVector<uint32_t, 8> extInstOperands;
1641 extInstOperands.reserve(operands.size() + 2);
1642 extInstOperands.append(operands.begin(), std::next(operands.begin(), 2));
1643 extInstOperands.push_back(setID);
1644 extInstOperands.push_back(extensionOpcode);
1645 extInstOperands.append(std::next(operands.begin(), 2), operands.end());
1650LogicalResult Serializer::encodeExtensionInstruction(
1651 Operation *op, StringRef extensionSetName, uint32_t extensionOpcode,
1652 ArrayRef<uint32_t> operands) {
1653 if (
failed(encodeExtensionInstruction(op, extensionSetName, extensionOpcode,
1654 operands, functionBody)))
1657 if (extensionSetName ==
extTosa)
1658 updateTosaOpsMap(op);
1663LogicalResult Serializer::processOperation(Operation *opInst) {
1664 LLVM_DEBUG(llvm::dbgs() <<
"[op] '" << opInst->
getName() <<
"'\n");
1669 .Case([&](spirv::AddressOfOp op) {
return processAddressOfOp(op); })
1670 .Case([&](spirv::BranchOp op) {
return processBranchOp(op); })
1671 .Case([&](spirv::BranchConditionalOp op) {
1672 return processBranchConditionalOp(op);
1674 .Case([&](spirv::ConstantOp op) {
return processConstantOp(op); })
1675 .Case([&](spirv::CompositeConstructOp op) {
1676 return processCompositeConstructOp(op);
1678 .Case([&](spirv::EXTConstantCompositeReplicateOp op) {
1679 return processConstantCompositeReplicateOp(op);
1681 .Case([&](spirv::FuncOp op) {
return processFuncOp(op); })
1682 .Case([&](spirv::GraphARMOp op) {
return processGraphARMOp(op); })
1683 .Case([&](spirv::GraphEntryPointARMOp op) {
1684 return processGraphEntryPointARMOp(op);
1686 .Case([&](spirv::GraphOutputsARMOp op) {
1687 return processGraphOutputsARMOp(op);
1689 .Case([&](spirv::GlobalVariableOp op) {
1690 return processGlobalVariableOp(op);
1692 .Case([&](spirv::GraphConstantARMOp op) {
1693 return processGraphConstantARMOp(op);
1695 .Case([&](spirv::LoopOp op) {
return processLoopOp(op); })
1696 .Case([&](spirv::ReferenceOfOp op) {
return processReferenceOfOp(op); })
1697 .Case([&](spirv::SelectionOp op) {
return processSelectionOp(op); })
1698 .Case([&](spirv::SpecConstantOp op) {
return processSpecConstantOp(op); })
1699 .Case([&](spirv::SpecConstantCompositeOp op) {
1700 return processSpecConstantCompositeOp(op);
1702 .Case([&](spirv::EXTSpecConstantCompositeReplicateOp op) {
1703 return processSpecConstantCompositeReplicateOp(op);
1705 .Case([&](spirv::SpecConstantOperationOp op) {
1706 return processSpecConstantOperationOp(op);
1708 .Case([&](spirv::SwitchOp op) {
return processSwitchOp(op); })
1709 .Case([&](spirv::UndefOp op) {
return processUndefOp(op); })
1710 .Case([&](spirv::VariableOp op) {
return processVariableOp(op); })
1715 [&](Operation *op) {
return dispatchToAutogenSerialization(op); });
1719Serializer::processCompositeConstructOp(spirv::CompositeConstructOp op) {
1720 Location loc = op.getLoc();
1722 uint32_t resultTypeID = 0;
1723 if (
failed(processType(loc, op.getType(), resultTypeID)))
1726 uint32_t resultID = getNextID();
1727 valueIDMap[op.getResult()] = resultID;
1729 SmallVector<uint32_t, 8> operands;
1730 operands.reserve(2 + op.getConstituents().size());
1731 operands.push_back(resultTypeID);
1732 operands.push_back(resultID);
1733 for (Value constituent : op.getConstituents()) {
1734 uint32_t
id = getValueID(constituent);
1735 assert(
id &&
"use before def!");
1736 operands.push_back(
id);
1739 if (
failed(emitDebugLine(functionBody, loc)))
1742 encodeInstructionWithContinuationInto(
1743 functionBody, spirv::Opcode::OpCompositeConstruct, operands);
1745 for (
auto attr : op->getDiscardableAttrDictionary().getValue()) {
1746 if (
failed(processDecoration(loc, resultID, attr)))
1753LogicalResult Serializer::processOpWithoutGrammarAttr(Operation *op,
1754 StringRef extInstSet,
1756 SmallVector<uint32_t, 4> operands;
1757 Location loc = op->
getLoc();
1759 uint32_t resultID = 0;
1761 uint32_t resultTypeID = 0;
1764 operands.push_back(resultTypeID);
1766 resultID = getNextID();
1767 operands.push_back(resultID);
1768 valueIDMap[op->
getResult(0)] = resultID;
1772 operands.push_back(getValueID(operand));
1776 if (
failed(emitDebugLine(functionBody, loc)))
1779 if (extInstSet.empty()) {
1783 if (
failed(encodeExtensionInstruction(op, extInstSet, opcode, operands)))
1789 if (
failed(processDecoration(loc, resultID, attr)))
1797void Serializer::updateTosaOpsMap(Operation *op) {
1798 if (!options.emitDebugInfo)
1801 if (
auto graphOp = dyn_cast<spirv::GraphARMOp>(op->
getParentOp())) {
1802 if (uint32_t graphID = getFunctionID(graphOp.getName()))
1803 tosaOpsMap[graphID][op->
getLoc()].insert(op);
1807LogicalResult Serializer::emitDecoration(uint32_t
target,
1808 spirv::Decoration decoration,
1809 ArrayRef<uint32_t> params) {
1810 uint32_t wordCount = 3 + params.size();
1811 llvm::append_values(
1814 static_cast<uint32_t
>(decoration));
1815 llvm::append_range(decorations, params);
1819LogicalResult Serializer::emitDecorationId(uint32_t
target,
1820 spirv::Decoration decoration,
1821 ArrayRef<uint32_t> operandIds) {
1822 uint32_t wordCount = 3 + operandIds.size();
1823 llvm::append_values(
1826 static_cast<uint32_t
>(decoration));
1827 llvm::append_range(decorations, operandIds);
1831LogicalResult Serializer::emitDebugLine(SmallVectorImpl<uint32_t> &binary,
1833 if (!options.emitDebugInfo)
1836 if (lastProcessedWasMergeInst) {
1837 lastProcessedWasMergeInst =
false;
1841 auto fileLoc = dyn_cast<FileLineColLoc>(loc);
1844 {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.
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.
DictionaryAttr getDiscardableAttrDictionary()
Return all of the discardable attributes on this operation as a DictionaryAttr.
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