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::Binding:
383 case spirv::Decoration::DescriptorSet:
384 case spirv::Decoration::Location:
385 case spirv::Decoration::Index:
386 case spirv::Decoration::Offset:
387 case spirv::Decoration::XfbBuffer:
388 case spirv::Decoration::XfbStride:
389 if (
auto intAttr = dyn_cast<IntegerAttr>(attr)) {
390 args.push_back(intAttr.getValue().getZExtValue());
393 return emitError(loc,
"expected integer attribute for ")
394 << stringifyDecoration(decoration);
395 case spirv::Decoration::BuiltIn:
396 if (
auto strAttr = dyn_cast<StringAttr>(attr)) {
397 auto enumVal = spirv::symbolizeBuiltIn(strAttr.getValue());
399 args.push_back(
static_cast<uint32_t
>(*enumVal));
403 << stringifyDecoration(decoration) <<
" decoration attribute "
404 << strAttr.getValue();
406 return emitError(loc,
"expected string attribute for ")
407 << stringifyDecoration(decoration);
408 case spirv::Decoration::Aliased:
409 case spirv::Decoration::AliasedPointer:
410 case spirv::Decoration::Flat:
411 case spirv::Decoration::NonReadable:
412 case spirv::Decoration::NonWritable:
413 case spirv::Decoration::NoPerspective:
414 case spirv::Decoration::NoSignedWrap:
415 case spirv::Decoration::NoUnsignedWrap:
416 case spirv::Decoration::RelaxedPrecision:
417 case spirv::Decoration::Restrict:
418 case spirv::Decoration::RestrictPointer:
419 case spirv::Decoration::NoContraction:
420 case spirv::Decoration::Constant:
421 case spirv::Decoration::Block:
422 case spirv::Decoration::BufferBlock:
423 case spirv::Decoration::CPacked:
424 case spirv::Decoration::Invariant:
425 case spirv::Decoration::Patch:
426 case spirv::Decoration::Coherent:
427 case spirv::Decoration::Volatile:
428 case spirv::Decoration::SaturatedConversion:
431 if (isa<UnitAttr, DecorationAttr>(attr))
434 "expected unit attribute or decoration attribute for ")
435 << stringifyDecoration(decoration);
436 case spirv::Decoration::CacheControlLoadINTEL:
438 loc, decoration, attr,
"CacheControlLoadINTEL",
439 [&](CacheControlLoadINTELAttr attr) {
440 unsigned cacheLevel = attr.getCacheLevel();
441 LoadCacheControl loadCacheControl = attr.getLoadCacheControl();
442 return emitDecoration(
443 resultID, decoration,
444 {cacheLevel,
static_cast<uint32_t
>(loadCacheControl)});
446 case spirv::Decoration::CacheControlStoreINTEL:
448 loc, decoration, attr,
"CacheControlStoreINTEL",
449 [&](CacheControlStoreINTELAttr attr) {
450 unsigned cacheLevel = attr.getCacheLevel();
451 StoreCacheControl storeCacheControl = attr.getStoreCacheControl();
452 return emitDecoration(
453 resultID, decoration,
454 {cacheLevel,
static_cast<uint32_t
>(storeCacheControl)});
456 case spirv::Decoration::AlignmentId:
457 case spirv::Decoration::MaxByteOffsetId:
458 case spirv::Decoration::CounterBuffer: {
459 auto symRef = dyn_cast<FlatSymbolRefAttr>(attr);
461 return emitError(loc,
"expected symbol reference for ")
462 << stringifyDecoration(decoration);
463 StringRef symName = symRef.getValue();
464 uint32_t operandID = getVariableID(symName);
466 operandID = getSpecConstID(symName);
468 return emitError(loc,
"could not find <id> for symbol '")
469 << symName <<
"' referenced by "
470 << stringifyDecoration(decoration);
471 return emitDecorationId(resultID, decoration, {operandID});
474 return emitError(loc,
"unhandled decoration ")
475 << stringifyDecoration(decoration);
477 return emitDecoration(resultID, decoration, args);
480LogicalResult Serializer::processDecoration(Location loc, uint32_t resultID,
481 NamedAttribute attr) {
482 StringRef attrName = attr.
getName().strref();
484 std::optional<Decoration> decoration =
485 spirv::symbolizeDecoration(decorationName);
488 loc,
"non-argument attributes expected to have snake-case-ified "
489 "decoration name, unhandled attribute with name : ")
492 return processDecorationAttr(loc, resultID, *decoration, attr.
getValue());
495LogicalResult Serializer::processName(uint32_t resultID, StringRef name) {
496 assert(!name.empty() &&
"unexpected empty string for OpName");
497 if (!options.emitSymbolName)
500 SmallVector<uint32_t, 4> nameOperands;
501 nameOperands.push_back(resultID);
508LogicalResult Serializer::processTypeDecoration<spirv::ArrayType>(
512 return emitDecoration(resultID, spirv::Decoration::ArrayStride, {stride});
518LogicalResult Serializer::processTypeDecoration<spirv::RuntimeArrayType>(
522 return emitDecoration(resultID, spirv::Decoration::ArrayStride, {stride});
527LogicalResult Serializer::processMemberDecoration(
532 static_cast<uint32_t
>(memberDecoration.
decoration)});
548bool Serializer::isInterfaceStructPtrType(Type type)
const {
549 if (
auto ptrType = dyn_cast<spirv::PointerType>(type)) {
550 switch (ptrType.getStorageClass()) {
551 case spirv::StorageClass::PhysicalStorageBuffer:
552 case spirv::StorageClass::PushConstant:
553 case spirv::StorageClass::StorageBuffer:
554 case spirv::StorageClass::Uniform:
555 return isa<spirv::StructType>(ptrType.getPointeeType());
563LogicalResult Serializer::processType(Location loc, Type type,
568 return processTypeImpl(loc, type, typeID, serializationCtx);
572Serializer::processTypeImpl(Location loc, Type type, uint32_t &typeID,
584 IntegerType::SignednessSemantics::Signless);
587 typeID = getTypeID(type);
591 typeID = getNextID();
592 SmallVector<uint32_t, 4> operands;
594 operands.push_back(typeID);
595 auto typeEnum = spirv::Opcode::OpTypeVoid;
596 bool deferSerialization =
false;
598 if ((isa<FunctionType>(type) &&
599 succeeded(prepareFunctionType(loc, cast<FunctionType>(type), typeEnum,
601 (isa<GraphType>(type) &&
603 prepareGraphType(loc, cast<GraphType>(type), typeEnum, operands))) ||
604 succeeded(prepareBasicType(loc, type, typeID, typeEnum, operands,
605 deferSerialization, serializationCtx))) {
606 if (deferSerialization)
609 typeIDMap[type] = typeID;
611 if (typeEnum == spirv::Opcode::OpTypeStruct)
612 encodeInstructionWithContinuationInto(typesGlobalValues, typeEnum,
617 if (recursiveStructInfos.count(type) != 0) {
620 for (
auto &ptrInfo : recursiveStructInfos[type]) {
623 SmallVector<uint32_t, 4> ptrOperands;
624 ptrOperands.push_back(ptrInfo.pointerTypeID);
625 ptrOperands.push_back(
static_cast<uint32_t
>(ptrInfo.storageClass));
626 ptrOperands.push_back(typeIDMap[type]);
632 recursiveStructInfos[type].clear();
638 return emitError(loc,
"failed to process type: ") << type;
641LogicalResult Serializer::prepareBasicType(
642 Location loc, Type type, uint32_t resultID, spirv::Opcode &typeEnum,
643 SmallVectorImpl<uint32_t> &operands,
bool &deferSerialization,
645 deferSerialization =
false;
647 if (isVoidType(type)) {
648 typeEnum = spirv::Opcode::OpTypeVoid;
652 if (
auto intType = dyn_cast<IntegerType>(type)) {
653 if (intType.getWidth() == 1) {
654 typeEnum = spirv::Opcode::OpTypeBool;
658 typeEnum = spirv::Opcode::OpTypeInt;
659 operands.push_back(intType.getWidth());
664 operands.push_back(intType.isSigned() ? 1 : 0);
668 if (
auto floatType = dyn_cast<FloatType>(type)) {
669 typeEnum = spirv::Opcode::OpTypeFloat;
670 operands.push_back(floatType.getWidth());
671 if (floatType.isBF16()) {
672 operands.push_back(
static_cast<uint32_t
>(spirv::FPEncoding::BFloat16KHR));
674 if (floatType.isF8E4M3FN()) {
676 static_cast<uint32_t
>(spirv::FPEncoding::Float8E4M3EXT));
678 if (floatType.isF8E5M2()) {
680 static_cast<uint32_t
>(spirv::FPEncoding::Float8E5M2EXT));
686 if (
auto vectorType = dyn_cast<VectorType>(type)) {
687 uint32_t elementTypeID = 0;
688 if (
failed(processTypeImpl(loc, vectorType.getElementType(), elementTypeID,
689 serializationCtx))) {
692 typeEnum = spirv::Opcode::OpTypeVector;
693 operands.push_back(elementTypeID);
694 operands.push_back(vectorType.getNumElements());
698 if (
auto imageType = dyn_cast<spirv::ImageType>(type)) {
699 typeEnum = spirv::Opcode::OpTypeImage;
700 uint32_t sampledTypeID = 0;
701 if (
failed(processType(loc, imageType.getElementType(), sampledTypeID)))
704 llvm::append_values(operands, sampledTypeID,
705 static_cast<uint32_t
>(imageType.getDim()),
706 static_cast<uint32_t
>(imageType.getDepthInfo()),
707 static_cast<uint32_t
>(imageType.getArrayedInfo()),
708 static_cast<uint32_t
>(imageType.getSamplingInfo()),
709 static_cast<uint32_t
>(imageType.getSamplerUseInfo()),
710 static_cast<uint32_t
>(imageType.getImageFormat()));
714 if (
auto arrayType = dyn_cast<spirv::ArrayType>(type)) {
715 typeEnum = spirv::Opcode::OpTypeArray;
716 uint32_t elementTypeID = 0;
717 if (
failed(processTypeImpl(loc, arrayType.getElementType(), elementTypeID,
718 serializationCtx))) {
721 operands.push_back(elementTypeID);
722 if (
auto elementCountID = prepareConstantInt(
723 loc, mlirBuilder.getI32IntegerAttr(arrayType.getNumElements()))) {
724 operands.push_back(elementCountID);
726 return processTypeDecoration(loc, arrayType, resultID);
729 if (
auto ptrType = dyn_cast<spirv::PointerType>(type)) {
730 uint32_t pointeeTypeID = 0;
731 spirv::StructType pointeeStruct =
732 dyn_cast<spirv::StructType>(ptrType.getPointeeType());
735 serializationCtx.count(pointeeStruct.
getIdentifier()) != 0) {
740 SmallVector<uint32_t, 2> forwardPtrOperands;
741 forwardPtrOperands.push_back(resultID);
742 forwardPtrOperands.push_back(
743 static_cast<uint32_t
>(ptrType.getStorageClass()));
746 spirv::Opcode::OpTypeForwardPointer,
758 deferSerialization =
true;
762 recursiveStructInfos[structType].push_back(
763 {resultID, ptrType.getStorageClass()});
765 if (
failed(processTypeImpl(loc, ptrType.getPointeeType(), pointeeTypeID,
770 typeEnum = spirv::Opcode::OpTypePointer;
771 operands.push_back(
static_cast<uint32_t
>(ptrType.getStorageClass()));
772 operands.push_back(pointeeTypeID);
777 if (isInterfaceStructPtrType(ptrType)) {
778 auto structType = cast<spirv::StructType>(ptrType.getPointeeType());
779 if (!structType.hasDecoration(spirv::Decoration::Block) &&
780 !structType.hasDecoration(spirv::Decoration::BufferBlock))
781 if (
failed(emitDecoration(getTypeID(pointeeStruct),
782 spirv::Decoration::Block)))
783 return emitError(loc,
"cannot decorate ")
784 << pointeeStruct <<
" with Block decoration";
790 if (
auto runtimeArrayType = dyn_cast<spirv::RuntimeArrayType>(type)) {
791 uint32_t elementTypeID = 0;
792 if (
failed(processTypeImpl(loc, runtimeArrayType.getElementType(),
793 elementTypeID, serializationCtx))) {
796 typeEnum = spirv::Opcode::OpTypeRuntimeArray;
797 operands.push_back(elementTypeID);
798 return processTypeDecoration(loc, runtimeArrayType, resultID);
801 if (isa<spirv::SamplerType>(type)) {
802 typeEnum = spirv::Opcode::OpTypeSampler;
806 if (isa<spirv::NamedBarrierType>(type)) {
807 typeEnum = spirv::Opcode::OpTypeNamedBarrier;
811 if (
auto sampledImageType = dyn_cast<spirv::SampledImageType>(type)) {
812 typeEnum = spirv::Opcode::OpTypeSampledImage;
813 uint32_t imageTypeID = 0;
815 processType(loc, sampledImageType.getImageType(), imageTypeID))) {
818 operands.push_back(imageTypeID);
822 if (
auto structType = dyn_cast<spirv::StructType>(type)) {
823 if (structType.isIdentified()) {
824 if (
failed(processName(resultID, structType.getIdentifier())))
826 serializationCtx.insert(structType.getIdentifier());
829 bool hasOffset = structType.hasOffset();
830 for (
auto elementIndex :
831 llvm::seq<uint32_t>(0, structType.getNumElements())) {
832 uint32_t elementTypeID = 0;
833 if (
failed(processTypeImpl(loc, structType.getElementType(elementIndex),
834 elementTypeID, serializationCtx))) {
837 operands.push_back(elementTypeID);
839 auto intType = IntegerType::get(structType.getContext(), 32);
841 spirv::StructType::MemberDecorationInfo offsetDecoration{
842 elementIndex, spirv::Decoration::Offset,
843 IntegerAttr::get(intType,
844 structType.getMemberOffset(elementIndex))};
845 if (
failed(processMemberDecoration(resultID, offsetDecoration))) {
846 return emitError(loc,
"cannot decorate ")
847 << elementIndex <<
"-th member of " << structType
848 <<
" with its offset";
852 SmallVector<spirv::StructType::MemberDecorationInfo, 4> memberDecorations;
853 structType.getMemberDecorations(memberDecorations);
855 for (
auto &memberDecoration : memberDecorations) {
856 if (
failed(processMemberDecoration(resultID, memberDecoration))) {
857 return emitError(loc,
"cannot decorate ")
858 <<
static_cast<uint32_t
>(memberDecoration.
memberIndex)
859 <<
"-th member of " << structType <<
" with "
860 << stringifyDecoration(memberDecoration.
decoration);
864 SmallVector<spirv::StructType::StructDecorationInfo, 1> structDecorations;
865 structType.getStructDecorations(structDecorations);
867 for (spirv::StructType::StructDecorationInfo &structDecoration :
869 if (
failed(processDecorationAttr(loc, resultID,
870 structDecoration.decoration,
871 structDecoration.decorationValue))) {
872 return emitError(loc,
"cannot decorate struct ")
873 << structType <<
" with "
874 << stringifyDecoration(structDecoration.decoration);
878 typeEnum = spirv::Opcode::OpTypeStruct;
880 if (structType.isIdentified())
881 serializationCtx.remove(structType.getIdentifier());
886 if (
auto cooperativeMatrixType =
887 dyn_cast<spirv::CooperativeMatrixType>(type)) {
888 uint32_t elementTypeID = 0;
889 if (
failed(processTypeImpl(loc, cooperativeMatrixType.getElementType(),
890 elementTypeID, serializationCtx))) {
893 typeEnum = spirv::Opcode::OpTypeCooperativeMatrixKHR;
894 auto getConstantOp = [&](uint32_t id) {
895 auto attr = IntegerAttr::get(IntegerType::get(type.
getContext(), 32),
id);
896 return prepareConstantInt(loc, attr);
899 operands, elementTypeID,
900 getConstantOp(
static_cast<uint32_t
>(cooperativeMatrixType.getScope())),
901 getConstantOp(cooperativeMatrixType.getRows()),
902 getConstantOp(cooperativeMatrixType.getColumns()),
903 getConstantOp(
static_cast<uint32_t
>(cooperativeMatrixType.getUse())));
907 if (
auto matrixType = dyn_cast<spirv::MatrixType>(type)) {
908 uint32_t elementTypeID = 0;
909 if (
failed(processTypeImpl(loc, matrixType.getColumnType(), elementTypeID,
910 serializationCtx))) {
913 typeEnum = spirv::Opcode::OpTypeMatrix;
914 llvm::append_values(operands, elementTypeID, matrixType.getNumColumns());
918 if (
auto tensorArmType = dyn_cast<TensorArmType>(type)) {
919 uint32_t elementTypeID = 0;
921 uint32_t shapeID = 0;
923 if (
failed(processTypeImpl(loc, tensorArmType.getElementType(),
924 elementTypeID, serializationCtx))) {
927 if (tensorArmType.hasRank()) {
928 ArrayRef<int64_t> dims = tensorArmType.getShape();
930 rankID = prepareConstantInt(loc, mlirBuilder.getI32IntegerAttr(rank));
935 bool shaped = llvm::all_of(dims, [](
const auto &dim) {
return dim > 0; });
936 if (rank > 0 && shaped) {
937 auto I32Type = IntegerType::get(type.
getContext(), 32);
940 SmallVector<uint64_t, 1> index(rank);
941 shapeID = prepareDenseElementsConstant(
943 mlirBuilder.getI32TensorAttr(SmallVector<int32_t>(dims)), 0,
946 shapeID = prepareArrayConstant(
948 mlirBuilder.getI32ArrayAttr(SmallVector<int32_t>(dims)));
955 typeEnum = spirv::Opcode::OpTypeTensorARM;
956 operands.push_back(elementTypeID);
959 operands.push_back(rankID);
962 operands.push_back(shapeID);
967 return emitError(loc,
"unhandled type in serialization: ") << type;
971Serializer::prepareFunctionType(Location loc, FunctionType type,
972 spirv::Opcode &typeEnum,
973 SmallVectorImpl<uint32_t> &operands) {
974 typeEnum = spirv::Opcode::OpTypeFunction;
975 assert(type.getNumResults() <= 1 &&
976 "serialization supports only a single return value");
977 uint32_t resultID = 0;
979 loc, type.getNumResults() == 1 ? type.getResult(0) : getVoidType(),
983 operands.push_back(resultID);
984 for (
auto &res : type.getInputs()) {
985 uint32_t argTypeID = 0;
986 if (
failed(processType(loc, res, argTypeID))) {
989 operands.push_back(argTypeID);
995Serializer::prepareGraphType(Location loc, GraphType type,
996 spirv::Opcode &typeEnum,
997 SmallVectorImpl<uint32_t> &operands) {
998 typeEnum = spirv::Opcode::OpTypeGraphARM;
999 assert(type.getNumResults() >= 1 &&
1000 "serialization requires at least a return value");
1002 operands.push_back(type.getNumInputs());
1004 for (Type argType : type.getInputs()) {
1005 uint32_t argTypeID = 0;
1006 if (
failed(processType(loc, argType, argTypeID)))
1008 operands.push_back(argTypeID);
1011 for (Type resType : type.getResults()) {
1012 uint32_t resTypeID = 0;
1013 if (
failed(processType(loc, resType, resTypeID)))
1015 operands.push_back(resTypeID);
1025uint32_t Serializer::prepareConstant(Location loc, Type constType,
1026 Attribute valueAttr) {
1027 if (
auto id = prepareConstantScalar(loc, valueAttr)) {
1034 if (
auto id = getConstantID(valueAttr)) {
1038 uint32_t typeID = 0;
1039 if (
failed(processType(loc, constType, typeID))) {
1043 uint32_t resultID = 0;
1044 if (
auto attr = dyn_cast<DenseElementsAttr>(valueAttr)) {
1045 int rank = dyn_cast<ShapedType>(attr.getType()).getRank();
1046 SmallVector<uint64_t, 4> index(rank);
1047 resultID = prepareDenseElementsConstant(loc, constType, attr,
1049 }
else if (
auto arrayAttr = dyn_cast<ArrayAttr>(valueAttr)) {
1050 resultID = prepareArrayConstant(loc, constType, arrayAttr);
1053 if (resultID == 0) {
1054 emitError(loc,
"cannot serialize attribute: ") << valueAttr;
1058 constIDMap[valueAttr] = resultID;
1062uint32_t Serializer::prepareArrayConstant(Location loc, Type constType,
1064 uint32_t typeID = 0;
1065 if (
failed(processType(loc, constType, typeID))) {
1069 uint32_t resultID = getNextID();
1070 SmallVector<uint32_t, 4> operands = {typeID, resultID};
1071 operands.reserve(attr.size() + 2);
1072 spirv::CompositeType compositeType = cast<spirv::CompositeType>(constType);
1073 for (
auto [idx, elementAttr] : llvm::enumerate(attr)) {
1074 if (uint32_t elementID = prepareConstant(
1076 operands.push_back(elementID);
1081 encodeInstructionWithContinuationInto(
1082 typesGlobalValues, spirv::Opcode::OpConstantComposite, operands);
1090Serializer::prepareDenseElementsConstant(Location loc, Type constType,
1091 DenseElementsAttr valueAttr,
int dim,
1092 MutableArrayRef<uint64_t> index) {
1093 auto shapedType = dyn_cast<ShapedType>(valueAttr.
getType());
1094 assert(dim <= shapedType.getRank());
1095 if (shapedType.getRank() == dim) {
1096 if (
auto attr = dyn_cast<DenseIntElementsAttr>(valueAttr)) {
1097 return attr.getType().getElementType().isInteger(1)
1098 ? prepareConstantBool(loc, attr.getValues<BoolAttr>()[index])
1099 : prepareConstantInt(loc,
1100 attr.getValues<IntegerAttr>()[index]);
1102 if (
auto attr = dyn_cast<DenseFPElementsAttr>(valueAttr)) {
1103 return prepareConstantFp(loc, attr.getValues<FloatAttr>()[index]);
1108 uint32_t typeID = 0;
1109 if (
failed(processType(loc, constType, typeID))) {
1113 int64_t numberOfConstituents = shapedType.getDimSize(dim);
1114 uint32_t resultID = getNextID();
1115 SmallVector<uint32_t, 4> operands = {typeID, resultID};
1116 auto elementType = cast<spirv::CompositeType>(constType).getElementType(0);
1117 if (
auto tensorArmType = dyn_cast<spirv::TensorArmType>(constType)) {
1118 ArrayRef<int64_t> innerShape = tensorArmType.getShape().drop_front();
1119 if (!innerShape.empty())
1127 if (isa<spirv::CooperativeMatrixType>(constType)) {
1131 "cannot serialize a non-splat value for a cooperative matrix type");
1136 operands.reserve(3);
1139 if (
auto elementID = prepareDenseElementsConstant(
1140 loc, elementType, valueAttr, shapedType.getRank(), index)) {
1141 operands.push_back(elementID);
1145 }
else if (isa<spirv::TensorArmType>(constType) &&
isZeroValue(valueAttr)) {
1147 {typeID, resultID});
1150 operands.reserve(numberOfConstituents + 2);
1151 for (
int i = 0; i < numberOfConstituents; ++i) {
1153 if (
auto elementID = prepareDenseElementsConstant(
1154 loc, elementType, valueAttr, dim + 1, index)) {
1155 operands.push_back(elementID);
1161 encodeInstructionWithContinuationInto(
1162 typesGlobalValues, spirv::Opcode::OpConstantComposite, operands);
1167uint32_t Serializer::prepareConstantScalar(Location loc, Attribute valueAttr,
1169 if (
auto floatAttr = dyn_cast<FloatAttr>(valueAttr)) {
1170 return prepareConstantFp(loc, floatAttr, isSpec);
1172 if (
auto boolAttr = dyn_cast<BoolAttr>(valueAttr)) {
1173 return prepareConstantBool(loc, boolAttr, isSpec);
1175 if (
auto intAttr = dyn_cast<IntegerAttr>(valueAttr)) {
1176 return prepareConstantInt(loc, intAttr, isSpec);
1182uint32_t Serializer::prepareConstantBool(Location loc, BoolAttr boolAttr,
1186 if (
auto id = getConstantID(boolAttr)) {
1192 uint32_t typeID = 0;
1193 if (
failed(processType(loc, cast<IntegerAttr>(boolAttr).
getType(), typeID))) {
1197 auto resultID = getNextID();
1199 ? (isSpec ? spirv::Opcode::OpSpecConstantTrue
1200 : spirv::Opcode::OpConstantTrue)
1201 : (isSpec ? spirv::Opcode::OpSpecConstantFalse
1202 : spirv::Opcode::OpConstantFalse);
1206 constIDMap[boolAttr] = resultID;
1211uint32_t Serializer::prepareConstantInt(Location loc, IntegerAttr intAttr,
1215 if (
auto id = getConstantID(intAttr)) {
1221 uint32_t typeID = 0;
1222 if (
failed(processType(loc, intAttr.getType(), typeID))) {
1226 auto resultID = getNextID();
1227 APInt value = intAttr.getValue();
1228 unsigned bitwidth = value.getBitWidth();
1229 bool isSigned = intAttr.getType().isSignedInteger();
1231 isSpec ? spirv::Opcode::OpSpecConstant : spirv::Opcode::OpConstant;
1244 word =
static_cast<int32_t
>(value.getSExtValue());
1246 word =
static_cast<uint32_t
>(value.getZExtValue());
1258 words = llvm::bit_cast<DoubleWord>(value.getSExtValue());
1260 words = llvm::bit_cast<DoubleWord>(value.getZExtValue());
1263 {typeID, resultID, words.word1, words.word2});
1266 std::string valueStr;
1267 llvm::raw_string_ostream rss(valueStr);
1268 value.print(rss,
false);
1271 << bitwidth <<
"-bit integer literal: " << valueStr;
1277 constIDMap[intAttr] = resultID;
1282uint32_t Serializer::prepareGraphConstantId(Location loc, Type graphConstType,
1283 IntegerAttr intAttr) {
1285 if (uint32_t
id = getGraphConstantARMId(intAttr)) {
1290 uint32_t typeID = 0;
1291 if (
failed(processType(loc, graphConstType, typeID))) {
1295 uint32_t resultID = getNextID();
1296 APInt value = intAttr.getValue();
1297 unsigned bitwidth = value.getBitWidth();
1298 if (bitwidth > 32) {
1299 emitError(loc,
"Too wide attribute for OpGraphConstantARM: ")
1300 << bitwidth <<
" bits";
1303 bool isSigned = value.isSignedIntN(bitwidth);
1307 word =
static_cast<int32_t
>(value.getSExtValue());
1309 word =
static_cast<uint32_t
>(value.getZExtValue());
1312 {typeID, resultID, word});
1313 graphConstIDMap[intAttr] = resultID;
1317uint32_t Serializer::prepareConstantFp(Location loc, FloatAttr floatAttr,
1321 if (
auto id = getConstantID(floatAttr)) {
1327 uint32_t typeID = 0;
1328 if (
failed(processType(loc, floatAttr.getType(), typeID))) {
1332 auto resultID = getNextID();
1333 APFloat value = floatAttr.getValue();
1334 const llvm::fltSemantics *semantics = &value.getSemantics();
1337 isSpec ? spirv::Opcode::OpSpecConstant : spirv::Opcode::OpConstant;
1339 if (semantics == &APFloat::IEEEsingle()) {
1340 uint32_t word = llvm::bit_cast<uint32_t>(value.convertToFloat());
1342 }
else if (semantics == &APFloat::IEEEdouble()) {
1346 } words = llvm::bit_cast<DoubleWord>(value.convertToDouble());
1348 {typeID, resultID, words.word1, words.word2});
1349 }
else if (llvm::is_contained({&APFloat::IEEEhalf(), &APFloat::BFloat(),
1350 &APFloat::Float8E4M3FN(),
1351 &APFloat::Float8E5M2()},
1354 static_cast<uint32_t
>(value.bitcastToAPInt().getZExtValue());
1357 std::string valueStr;
1358 llvm::raw_string_ostream rss(valueStr);
1362 << floatAttr.getType() <<
"-typed float literal: " << valueStr;
1367 constIDMap[floatAttr] = resultID;
1376 if (
auto typedAttr = dyn_cast<TypedAttr>(attr)) {
1377 return typedAttr.getType();
1380 if (
auto arrayAttr = dyn_cast<ArrayAttr>(attr)) {
1387uint32_t Serializer::prepareConstantCompositeReplicate(
Location loc,
1390 std::pair<Attribute, Type> valueTypePair{valueAttr, resultType};
1391 if (uint32_t
id = getConstantCompositeReplicateID(valueTypePair)) {
1395 uint32_t typeID = 0;
1396 if (
failed(processType(loc, resultType, typeID))) {
1404 auto compositeType = dyn_cast<CompositeType>(resultType);
1409 uint32_t constandID;
1410 if (elementType == valueType) {
1411 constandID = prepareConstant(loc, elementType, valueAttr);
1413 constandID = prepareConstantCompositeReplicate(loc, elementType, valueAttr);
1416 uint32_t resultID = getNextID();
1417 if (dyn_cast<spirv::TensorArmType>(resultType) &&
isZeroValue(valueAttr)) {
1419 {typeID, resultID});
1422 spirv::Opcode::OpConstantCompositeReplicateEXT,
1423 {typeID, resultID, constandID});
1426 constCompositeReplicateIDMap[valueTypePair] = resultID;
1434uint32_t Serializer::getOrCreateBlockID(
Block *block) {
1435 if (uint32_t
id = getBlockID(block))
1437 return blockIDMap[block] = getNextID();
1441void Serializer::printBlock(
Block *block, raw_ostream &os) {
1442 os <<
"block " << block <<
" (id = ";
1443 if (uint32_t
id = getBlockID(block))
1452Serializer::processBlock(
Block *block,
bool omitLabel,
1454 LLVM_DEBUG(llvm::dbgs() <<
"processing block " << block <<
":\n");
1455 LLVM_DEBUG(block->
print(llvm::dbgs()));
1456 LLVM_DEBUG(llvm::dbgs() <<
'\n');
1458 uint32_t blockID = getOrCreateBlockID(block);
1459 LLVM_DEBUG(printBlock(block, llvm::dbgs()));
1466 if (
failed(emitPhiForBlockArguments(block)))
1476 llvm::IsaPred<spirv::LoopOp, spirv::SelectionOp>)) {
1479 emitMerge =
nullptr;
1482 uint32_t blockID = getNextID();
1488 for (Operation &op : llvm::drop_end(*block)) {
1489 if (
failed(processOperation(&op)))
1497 if (
failed(processOperation(&block->
back())))
1503LogicalResult Serializer::emitPhiForBlockArguments(
Block *block) {
1509 LLVM_DEBUG(llvm::dbgs() <<
"emitting phi instructions..\n");
1516 SmallVector<std::pair<Block *, OperandRange>, 4> predecessors;
1518 auto *terminator = mlirPredecessor->getTerminator();
1519 LLVM_DEBUG(llvm::dbgs() <<
" mlir predecessor ");
1520 LLVM_DEBUG(printBlock(mlirPredecessor, llvm::dbgs()));
1521 LLVM_DEBUG(llvm::dbgs() <<
" terminator: " << *terminator <<
"\n");
1530 LLVM_DEBUG(llvm::dbgs() <<
" spirv predecessor ");
1531 LLVM_DEBUG(printBlock(spirvPredecessor, llvm::dbgs()));
1532 if (
auto branchOp = dyn_cast<spirv::BranchOp>(terminator)) {
1533 predecessors.emplace_back(spirvPredecessor, branchOp.getOperands());
1534 }
else if (
auto branchCondOp =
1535 dyn_cast<spirv::BranchConditionalOp>(terminator)) {
1536 std::optional<OperandRange> blockOperands;
1537 if (branchCondOp.getTrueTarget() == block) {
1538 blockOperands = branchCondOp.getTrueTargetOperands();
1540 assert(branchCondOp.getFalseTarget() == block);
1541 blockOperands = branchCondOp.getFalseTargetOperands();
1543 assert(!blockOperands->empty() &&
1544 "expected non-empty block operand range");
1545 predecessors.emplace_back(spirvPredecessor, *blockOperands);
1546 }
else if (
auto switchOp = dyn_cast<spirv::SwitchOp>(terminator)) {
1547 std::optional<OperandRange> blockOperands;
1548 if (block == switchOp.getDefaultTarget()) {
1549 blockOperands = switchOp.getDefaultOperands();
1551 SuccessorRange targets = switchOp.getTargets();
1552 auto it = llvm::find(targets, block);
1553 assert(it != targets.end());
1554 size_t index = std::distance(targets.begin(), it);
1555 blockOperands = switchOp.getTargetOperands(index);
1557 assert(!blockOperands->empty() &&
1558 "expected non-empty block operand range");
1559 predecessors.emplace_back(spirvPredecessor, *blockOperands);
1561 return terminator->emitError(
"unimplemented terminator for Phi creation");
1564 llvm::dbgs() <<
" block arguments:\n";
1565 for (Value v : predecessors.back().second)
1566 llvm::dbgs() <<
" " << v <<
"\n";
1571 for (
auto argIndex : llvm::seq<unsigned>(0, block->
getNumArguments())) {
1575 uint32_t phiTypeID = 0;
1578 uint32_t phiID = getNextID();
1580 LLVM_DEBUG(llvm::dbgs() <<
"[phi] for block argument #" << argIndex <<
' '
1581 << arg <<
" (id = " << phiID <<
")\n");
1584 SmallVector<uint32_t, 8> phiArgs;
1585 phiArgs.push_back(phiTypeID);
1586 phiArgs.push_back(phiID);
1588 for (
auto predIndex : llvm::seq<unsigned>(0, predecessors.size())) {
1589 Value value = predecessors[predIndex].second[argIndex];
1590 uint32_t predBlockId = getOrCreateBlockID(predecessors[predIndex].first);
1591 LLVM_DEBUG(llvm::dbgs() <<
"[phi] use predecessor (id = " << predBlockId
1592 <<
") value " << value <<
' ');
1594 uint32_t valueId = getValueID(value);
1598 LLVM_DEBUG(llvm::dbgs() <<
"(need to fix)\n");
1599 deferredPhiValues[value].push_back(functionBody.size() + 1 +
1602 LLVM_DEBUG(llvm::dbgs() <<
"(id = " << valueId <<
")\n");
1604 phiArgs.push_back(valueId);
1606 phiArgs.push_back(predBlockId);
1610 valueIDMap[arg] = phiID;
1620LogicalResult Serializer::encodeExtensionInstruction(
1621 Operation *op, StringRef extensionSetName, uint32_t extensionOpcode,
1622 ArrayRef<uint32_t> operands, SmallVectorImpl<uint32_t> &binary) {
1624 auto &setID = extendedInstSetIDMap[extensionSetName];
1626 setID = getNextID();
1627 SmallVector<uint32_t, 16> importOperands;
1628 importOperands.push_back(setID);
1636 if (operands.size() < 2) {
1637 return op->
emitError(
"extended instructions must have a result encoding");
1639 SmallVector<uint32_t, 8> extInstOperands;
1640 extInstOperands.reserve(operands.size() + 2);
1641 extInstOperands.append(operands.begin(), std::next(operands.begin(), 2));
1642 extInstOperands.push_back(setID);
1643 extInstOperands.push_back(extensionOpcode);
1644 extInstOperands.append(std::next(operands.begin(), 2), operands.end());
1649LogicalResult Serializer::encodeExtensionInstruction(
1650 Operation *op, StringRef extensionSetName, uint32_t extensionOpcode,
1651 ArrayRef<uint32_t> operands) {
1652 if (
failed(encodeExtensionInstruction(op, extensionSetName, extensionOpcode,
1653 operands, functionBody)))
1656 if (extensionSetName ==
extTosa)
1657 updateTosaOpsMap(op);
1662LogicalResult Serializer::processOperation(Operation *opInst) {
1663 LLVM_DEBUG(llvm::dbgs() <<
"[op] '" << opInst->
getName() <<
"'\n");
1668 .Case([&](spirv::AddressOfOp op) {
return processAddressOfOp(op); })
1669 .Case([&](spirv::BranchOp op) {
return processBranchOp(op); })
1670 .Case([&](spirv::BranchConditionalOp op) {
1671 return processBranchConditionalOp(op);
1673 .Case([&](spirv::ConstantOp op) {
return processConstantOp(op); })
1674 .Case([&](spirv::CompositeConstructOp op) {
1675 return processCompositeConstructOp(op);
1677 .Case([&](spirv::EXTConstantCompositeReplicateOp op) {
1678 return processConstantCompositeReplicateOp(op);
1680 .Case([&](spirv::FuncOp op) {
return processFuncOp(op); })
1681 .Case([&](spirv::GraphARMOp op) {
return processGraphARMOp(op); })
1682 .Case([&](spirv::GraphEntryPointARMOp op) {
1683 return processGraphEntryPointARMOp(op);
1685 .Case([&](spirv::GraphOutputsARMOp op) {
1686 return processGraphOutputsARMOp(op);
1688 .Case([&](spirv::GlobalVariableOp op) {
1689 return processGlobalVariableOp(op);
1691 .Case([&](spirv::GraphConstantARMOp op) {
1692 return processGraphConstantARMOp(op);
1694 .Case([&](spirv::LoopOp op) {
return processLoopOp(op); })
1695 .Case([&](spirv::ReferenceOfOp op) {
return processReferenceOfOp(op); })
1696 .Case([&](spirv::SelectionOp op) {
return processSelectionOp(op); })
1697 .Case([&](spirv::SpecConstantOp op) {
return processSpecConstantOp(op); })
1698 .Case([&](spirv::SpecConstantCompositeOp op) {
1699 return processSpecConstantCompositeOp(op);
1701 .Case([&](spirv::EXTSpecConstantCompositeReplicateOp op) {
1702 return processSpecConstantCompositeReplicateOp(op);
1704 .Case([&](spirv::SpecConstantOperationOp op) {
1705 return processSpecConstantOperationOp(op);
1707 .Case([&](spirv::SwitchOp op) {
return processSwitchOp(op); })
1708 .Case([&](spirv::UndefOp op) {
return processUndefOp(op); })
1709 .Case([&](spirv::VariableOp op) {
return processVariableOp(op); })
1714 [&](Operation *op) {
return dispatchToAutogenSerialization(op); });
1718Serializer::processCompositeConstructOp(spirv::CompositeConstructOp op) {
1719 Location loc = op.getLoc();
1721 uint32_t resultTypeID = 0;
1722 if (
failed(processType(loc, op.getType(), resultTypeID)))
1725 uint32_t resultID = getNextID();
1726 valueIDMap[op.getResult()] = resultID;
1728 SmallVector<uint32_t, 8> operands;
1729 operands.reserve(2 + op.getConstituents().size());
1730 operands.push_back(resultTypeID);
1731 operands.push_back(resultID);
1732 for (Value constituent : op.getConstituents()) {
1733 uint32_t
id = getValueID(constituent);
1734 assert(
id &&
"use before def!");
1735 operands.push_back(
id);
1738 if (
failed(emitDebugLine(functionBody, loc)))
1741 encodeInstructionWithContinuationInto(
1742 functionBody, spirv::Opcode::OpCompositeConstruct, operands);
1744 for (
auto attr : op->getDiscardableAttrDictionary().getValue()) {
1745 if (
failed(processDecoration(loc, resultID, attr)))
1752LogicalResult Serializer::processOpWithoutGrammarAttr(Operation *op,
1753 StringRef extInstSet,
1755 SmallVector<uint32_t, 4> operands;
1756 Location loc = op->
getLoc();
1758 uint32_t resultID = 0;
1760 uint32_t resultTypeID = 0;
1763 operands.push_back(resultTypeID);
1765 resultID = getNextID();
1766 operands.push_back(resultID);
1767 valueIDMap[op->
getResult(0)] = resultID;
1771 operands.push_back(getValueID(operand));
1775 if (
failed(emitDebugLine(functionBody, loc)))
1778 if (extInstSet.empty()) {
1782 if (
failed(encodeExtensionInstruction(op, extInstSet, opcode, operands)))
1788 if (
failed(processDecoration(loc, resultID, attr)))
1796void Serializer::updateTosaOpsMap(Operation *op) {
1797 if (!options.emitDebugInfo)
1800 if (
auto graphOp = dyn_cast<spirv::GraphARMOp>(op->
getParentOp())) {
1801 if (uint32_t graphID = getFunctionID(graphOp.getName()))
1802 tosaOpsMap[graphID][op->
getLoc()].insert(op);
1806LogicalResult Serializer::emitDecoration(uint32_t
target,
1807 spirv::Decoration decoration,
1808 ArrayRef<uint32_t> params) {
1809 uint32_t wordCount = 3 + params.size();
1810 llvm::append_values(
1813 static_cast<uint32_t
>(decoration));
1814 llvm::append_range(decorations, params);
1818LogicalResult Serializer::emitDecorationId(uint32_t
target,
1819 spirv::Decoration decoration,
1820 ArrayRef<uint32_t> operandIds) {
1821 uint32_t wordCount = 3 + operandIds.size();
1822 llvm::append_values(
1825 static_cast<uint32_t
>(decoration));
1826 llvm::append_range(decorations, operandIds);
1830LogicalResult Serializer::emitDebugLine(SmallVectorImpl<uint32_t> &binary,
1832 if (!options.emitDebugInfo)
1835 if (lastProcessedWasMergeInst) {
1836 lastProcessedWasMergeInst =
false;
1840 auto fileLoc = dyn_cast<FileLineColLoc>(loc);
1843 {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