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::Binding:
375 case spirv::Decoration::DescriptorSet:
376 case spirv::Decoration::Location:
377 case spirv::Decoration::Index:
378 case spirv::Decoration::Offset:
379 case spirv::Decoration::XfbBuffer:
380 case spirv::Decoration::XfbStride:
381 if (
auto intAttr = dyn_cast<IntegerAttr>(attr)) {
382 args.push_back(intAttr.getValue().getZExtValue());
385 return emitError(loc,
"expected integer attribute for ")
386 << stringifyDecoration(decoration);
387 case spirv::Decoration::BuiltIn:
388 if (
auto strAttr = dyn_cast<StringAttr>(attr)) {
389 auto enumVal = spirv::symbolizeBuiltIn(strAttr.getValue());
391 args.push_back(
static_cast<uint32_t
>(*enumVal));
395 << stringifyDecoration(decoration) <<
" decoration attribute "
396 << strAttr.getValue();
398 return emitError(loc,
"expected string attribute for ")
399 << stringifyDecoration(decoration);
400 case spirv::Decoration::Aliased:
401 case spirv::Decoration::AliasedPointer:
402 case spirv::Decoration::Flat:
403 case spirv::Decoration::NonReadable:
404 case spirv::Decoration::NonWritable:
405 case spirv::Decoration::NoPerspective:
406 case spirv::Decoration::NoSignedWrap:
407 case spirv::Decoration::NoUnsignedWrap:
408 case spirv::Decoration::RelaxedPrecision:
409 case spirv::Decoration::Restrict:
410 case spirv::Decoration::RestrictPointer:
411 case spirv::Decoration::NoContraction:
412 case spirv::Decoration::Constant:
413 case spirv::Decoration::Block:
414 case spirv::Decoration::BufferBlock:
415 case spirv::Decoration::Invariant:
416 case spirv::Decoration::Patch:
417 case spirv::Decoration::Coherent:
418 case spirv::Decoration::Volatile:
421 if (isa<UnitAttr, DecorationAttr>(attr))
424 "expected unit attribute or decoration attribute for ")
425 << stringifyDecoration(decoration);
426 case spirv::Decoration::CacheControlLoadINTEL:
428 loc, decoration, attr,
"CacheControlLoadINTEL",
429 [&](CacheControlLoadINTELAttr attr) {
430 unsigned cacheLevel = attr.getCacheLevel();
431 LoadCacheControl loadCacheControl = attr.getLoadCacheControl();
432 return emitDecoration(
433 resultID, decoration,
434 {cacheLevel,
static_cast<uint32_t
>(loadCacheControl)});
436 case spirv::Decoration::CacheControlStoreINTEL:
438 loc, decoration, attr,
"CacheControlStoreINTEL",
439 [&](CacheControlStoreINTELAttr attr) {
440 unsigned cacheLevel = attr.getCacheLevel();
441 StoreCacheControl storeCacheControl = attr.getStoreCacheControl();
442 return emitDecoration(
443 resultID, decoration,
444 {cacheLevel,
static_cast<uint32_t
>(storeCacheControl)});
446 case spirv::Decoration::AlignmentId:
447 case spirv::Decoration::MaxByteOffsetId:
448 case spirv::Decoration::CounterBuffer: {
449 auto symRef = dyn_cast<FlatSymbolRefAttr>(attr);
451 return emitError(loc,
"expected symbol reference for ")
452 << stringifyDecoration(decoration);
453 StringRef symName = symRef.getValue();
454 uint32_t operandID = getVariableID(symName);
456 operandID = getSpecConstID(symName);
458 return emitError(loc,
"could not find <id> for symbol '")
459 << symName <<
"' referenced by "
460 << stringifyDecoration(decoration);
461 return emitDecorationId(resultID, decoration, {operandID});
464 return emitError(loc,
"unhandled decoration ")
465 << stringifyDecoration(decoration);
467 return emitDecoration(resultID, decoration, args);
470LogicalResult Serializer::processDecoration(Location loc, uint32_t resultID,
471 NamedAttribute attr) {
472 StringRef attrName = attr.
getName().strref();
474 std::optional<Decoration> decoration =
475 spirv::symbolizeDecoration(decorationName);
478 loc,
"non-argument attributes expected to have snake-case-ified "
479 "decoration name, unhandled attribute with name : ")
482 return processDecorationAttr(loc, resultID, *decoration, attr.
getValue());
485LogicalResult Serializer::processName(uint32_t resultID, StringRef name) {
486 assert(!name.empty() &&
"unexpected empty string for OpName");
487 if (!options.emitSymbolName)
490 SmallVector<uint32_t, 4> nameOperands;
491 nameOperands.push_back(resultID);
498LogicalResult Serializer::processTypeDecoration<spirv::ArrayType>(
502 return emitDecoration(resultID, spirv::Decoration::ArrayStride, {stride});
508LogicalResult Serializer::processTypeDecoration<spirv::RuntimeArrayType>(
512 return emitDecoration(resultID, spirv::Decoration::ArrayStride, {stride});
517LogicalResult Serializer::processMemberDecoration(
522 static_cast<uint32_t
>(memberDecoration.
decoration)});
538bool Serializer::isInterfaceStructPtrType(Type type)
const {
539 if (
auto ptrType = dyn_cast<spirv::PointerType>(type)) {
540 switch (ptrType.getStorageClass()) {
541 case spirv::StorageClass::PhysicalStorageBuffer:
542 case spirv::StorageClass::PushConstant:
543 case spirv::StorageClass::StorageBuffer:
544 case spirv::StorageClass::Uniform:
545 return isa<spirv::StructType>(ptrType.getPointeeType());
553LogicalResult Serializer::processType(Location loc, Type type,
558 return processTypeImpl(loc, type, typeID, serializationCtx);
562Serializer::processTypeImpl(Location loc, Type type, uint32_t &typeID,
574 IntegerType::SignednessSemantics::Signless);
577 typeID = getTypeID(type);
581 typeID = getNextID();
582 SmallVector<uint32_t, 4> operands;
584 operands.push_back(typeID);
585 auto typeEnum = spirv::Opcode::OpTypeVoid;
586 bool deferSerialization =
false;
588 if ((isa<FunctionType>(type) &&
589 succeeded(prepareFunctionType(loc, cast<FunctionType>(type), typeEnum,
591 (isa<GraphType>(type) &&
593 prepareGraphType(loc, cast<GraphType>(type), typeEnum, operands))) ||
594 succeeded(prepareBasicType(loc, type, typeID, typeEnum, operands,
595 deferSerialization, serializationCtx))) {
596 if (deferSerialization)
599 typeIDMap[type] = typeID;
601 if (typeEnum == spirv::Opcode::OpTypeStruct)
602 encodeInstructionWithContinuationInto(typesGlobalValues, typeEnum,
607 if (recursiveStructInfos.count(type) != 0) {
610 for (
auto &ptrInfo : recursiveStructInfos[type]) {
613 SmallVector<uint32_t, 4> ptrOperands;
614 ptrOperands.push_back(ptrInfo.pointerTypeID);
615 ptrOperands.push_back(
static_cast<uint32_t
>(ptrInfo.storageClass));
616 ptrOperands.push_back(typeIDMap[type]);
622 recursiveStructInfos[type].clear();
628 return emitError(loc,
"failed to process type: ") << type;
631LogicalResult Serializer::prepareBasicType(
632 Location loc, Type type, uint32_t resultID, spirv::Opcode &typeEnum,
633 SmallVectorImpl<uint32_t> &operands,
bool &deferSerialization,
635 deferSerialization =
false;
637 if (isVoidType(type)) {
638 typeEnum = spirv::Opcode::OpTypeVoid;
642 if (
auto intType = dyn_cast<IntegerType>(type)) {
643 if (intType.getWidth() == 1) {
644 typeEnum = spirv::Opcode::OpTypeBool;
648 typeEnum = spirv::Opcode::OpTypeInt;
649 operands.push_back(intType.getWidth());
654 operands.push_back(intType.isSigned() ? 1 : 0);
658 if (
auto floatType = dyn_cast<FloatType>(type)) {
659 typeEnum = spirv::Opcode::OpTypeFloat;
660 operands.push_back(floatType.getWidth());
661 if (floatType.isBF16()) {
662 operands.push_back(
static_cast<uint32_t
>(spirv::FPEncoding::BFloat16KHR));
664 if (floatType.isF8E4M3FN()) {
666 static_cast<uint32_t
>(spirv::FPEncoding::Float8E4M3EXT));
668 if (floatType.isF8E5M2()) {
670 static_cast<uint32_t
>(spirv::FPEncoding::Float8E5M2EXT));
676 if (
auto vectorType = dyn_cast<VectorType>(type)) {
677 uint32_t elementTypeID = 0;
678 if (
failed(processTypeImpl(loc, vectorType.getElementType(), elementTypeID,
679 serializationCtx))) {
682 typeEnum = spirv::Opcode::OpTypeVector;
683 operands.push_back(elementTypeID);
684 operands.push_back(vectorType.getNumElements());
688 if (
auto imageType = dyn_cast<spirv::ImageType>(type)) {
689 typeEnum = spirv::Opcode::OpTypeImage;
690 uint32_t sampledTypeID = 0;
691 if (
failed(processType(loc, imageType.getElementType(), sampledTypeID)))
694 llvm::append_values(operands, sampledTypeID,
695 static_cast<uint32_t
>(imageType.getDim()),
696 static_cast<uint32_t
>(imageType.getDepthInfo()),
697 static_cast<uint32_t
>(imageType.getArrayedInfo()),
698 static_cast<uint32_t
>(imageType.getSamplingInfo()),
699 static_cast<uint32_t
>(imageType.getSamplerUseInfo()),
700 static_cast<uint32_t
>(imageType.getImageFormat()));
704 if (
auto arrayType = dyn_cast<spirv::ArrayType>(type)) {
705 typeEnum = spirv::Opcode::OpTypeArray;
706 uint32_t elementTypeID = 0;
707 if (
failed(processTypeImpl(loc, arrayType.getElementType(), elementTypeID,
708 serializationCtx))) {
711 operands.push_back(elementTypeID);
712 if (
auto elementCountID = prepareConstantInt(
713 loc, mlirBuilder.getI32IntegerAttr(arrayType.getNumElements()))) {
714 operands.push_back(elementCountID);
716 return processTypeDecoration(loc, arrayType, resultID);
719 if (
auto ptrType = dyn_cast<spirv::PointerType>(type)) {
720 uint32_t pointeeTypeID = 0;
721 spirv::StructType pointeeStruct =
722 dyn_cast<spirv::StructType>(ptrType.getPointeeType());
725 serializationCtx.count(pointeeStruct.
getIdentifier()) != 0) {
730 SmallVector<uint32_t, 2> forwardPtrOperands;
731 forwardPtrOperands.push_back(resultID);
732 forwardPtrOperands.push_back(
733 static_cast<uint32_t
>(ptrType.getStorageClass()));
736 spirv::Opcode::OpTypeForwardPointer,
748 deferSerialization =
true;
752 recursiveStructInfos[structType].push_back(
753 {resultID, ptrType.getStorageClass()});
755 if (
failed(processTypeImpl(loc, ptrType.getPointeeType(), pointeeTypeID,
760 typeEnum = spirv::Opcode::OpTypePointer;
761 operands.push_back(
static_cast<uint32_t
>(ptrType.getStorageClass()));
762 operands.push_back(pointeeTypeID);
767 if (isInterfaceStructPtrType(ptrType)) {
768 auto structType = cast<spirv::StructType>(ptrType.getPointeeType());
769 if (!structType.hasDecoration(spirv::Decoration::Block) &&
770 !structType.hasDecoration(spirv::Decoration::BufferBlock))
771 if (
failed(emitDecoration(getTypeID(pointeeStruct),
772 spirv::Decoration::Block)))
773 return emitError(loc,
"cannot decorate ")
774 << pointeeStruct <<
" with Block decoration";
780 if (
auto runtimeArrayType = dyn_cast<spirv::RuntimeArrayType>(type)) {
781 uint32_t elementTypeID = 0;
782 if (
failed(processTypeImpl(loc, runtimeArrayType.getElementType(),
783 elementTypeID, serializationCtx))) {
786 typeEnum = spirv::Opcode::OpTypeRuntimeArray;
787 operands.push_back(elementTypeID);
788 return processTypeDecoration(loc, runtimeArrayType, resultID);
791 if (isa<spirv::SamplerType>(type)) {
792 typeEnum = spirv::Opcode::OpTypeSampler;
796 if (isa<spirv::NamedBarrierType>(type)) {
797 typeEnum = spirv::Opcode::OpTypeNamedBarrier;
801 if (
auto sampledImageType = dyn_cast<spirv::SampledImageType>(type)) {
802 typeEnum = spirv::Opcode::OpTypeSampledImage;
803 uint32_t imageTypeID = 0;
805 processType(loc, sampledImageType.getImageType(), imageTypeID))) {
808 operands.push_back(imageTypeID);
812 if (
auto structType = dyn_cast<spirv::StructType>(type)) {
813 if (structType.isIdentified()) {
814 if (
failed(processName(resultID, structType.getIdentifier())))
816 serializationCtx.insert(structType.getIdentifier());
819 bool hasOffset = structType.hasOffset();
820 for (
auto elementIndex :
821 llvm::seq<uint32_t>(0, structType.getNumElements())) {
822 uint32_t elementTypeID = 0;
823 if (
failed(processTypeImpl(loc, structType.getElementType(elementIndex),
824 elementTypeID, serializationCtx))) {
827 operands.push_back(elementTypeID);
829 auto intType = IntegerType::get(structType.getContext(), 32);
831 spirv::StructType::MemberDecorationInfo offsetDecoration{
832 elementIndex, spirv::Decoration::Offset,
833 IntegerAttr::get(intType,
834 structType.getMemberOffset(elementIndex))};
835 if (
failed(processMemberDecoration(resultID, offsetDecoration))) {
836 return emitError(loc,
"cannot decorate ")
837 << elementIndex <<
"-th member of " << structType
838 <<
" with its offset";
842 SmallVector<spirv::StructType::MemberDecorationInfo, 4> memberDecorations;
843 structType.getMemberDecorations(memberDecorations);
845 for (
auto &memberDecoration : memberDecorations) {
846 if (
failed(processMemberDecoration(resultID, memberDecoration))) {
847 return emitError(loc,
"cannot decorate ")
848 <<
static_cast<uint32_t
>(memberDecoration.
memberIndex)
849 <<
"-th member of " << structType <<
" with "
850 << stringifyDecoration(memberDecoration.
decoration);
854 SmallVector<spirv::StructType::StructDecorationInfo, 1> structDecorations;
855 structType.getStructDecorations(structDecorations);
857 for (spirv::StructType::StructDecorationInfo &structDecoration :
859 if (
failed(processDecorationAttr(loc, resultID,
860 structDecoration.decoration,
861 structDecoration.decorationValue))) {
862 return emitError(loc,
"cannot decorate struct ")
863 << structType <<
" with "
864 << stringifyDecoration(structDecoration.decoration);
868 typeEnum = spirv::Opcode::OpTypeStruct;
870 if (structType.isIdentified())
871 serializationCtx.remove(structType.getIdentifier());
876 if (
auto cooperativeMatrixType =
877 dyn_cast<spirv::CooperativeMatrixType>(type)) {
878 uint32_t elementTypeID = 0;
879 if (
failed(processTypeImpl(loc, cooperativeMatrixType.getElementType(),
880 elementTypeID, serializationCtx))) {
883 typeEnum = spirv::Opcode::OpTypeCooperativeMatrixKHR;
884 auto getConstantOp = [&](uint32_t id) {
885 auto attr = IntegerAttr::get(IntegerType::get(type.
getContext(), 32),
id);
886 return prepareConstantInt(loc, attr);
889 operands, elementTypeID,
890 getConstantOp(
static_cast<uint32_t
>(cooperativeMatrixType.getScope())),
891 getConstantOp(cooperativeMatrixType.getRows()),
892 getConstantOp(cooperativeMatrixType.getColumns()),
893 getConstantOp(
static_cast<uint32_t
>(cooperativeMatrixType.getUse())));
897 if (
auto matrixType = dyn_cast<spirv::MatrixType>(type)) {
898 uint32_t elementTypeID = 0;
899 if (
failed(processTypeImpl(loc, matrixType.getColumnType(), elementTypeID,
900 serializationCtx))) {
903 typeEnum = spirv::Opcode::OpTypeMatrix;
904 llvm::append_values(operands, elementTypeID, matrixType.getNumColumns());
908 if (
auto tensorArmType = dyn_cast<TensorArmType>(type)) {
909 uint32_t elementTypeID = 0;
911 uint32_t shapeID = 0;
913 if (
failed(processTypeImpl(loc, tensorArmType.getElementType(),
914 elementTypeID, serializationCtx))) {
917 if (tensorArmType.hasRank()) {
918 ArrayRef<int64_t> dims = tensorArmType.getShape();
920 rankID = prepareConstantInt(loc, mlirBuilder.getI32IntegerAttr(rank));
925 bool shaped = llvm::all_of(dims, [](
const auto &dim) {
return dim > 0; });
926 if (rank > 0 && shaped) {
927 auto I32Type = IntegerType::get(type.
getContext(), 32);
930 SmallVector<uint64_t, 1> index(rank);
931 shapeID = prepareDenseElementsConstant(
933 mlirBuilder.getI32TensorAttr(SmallVector<int32_t>(dims)), 0,
936 shapeID = prepareArrayConstant(
938 mlirBuilder.getI32ArrayAttr(SmallVector<int32_t>(dims)));
945 typeEnum = spirv::Opcode::OpTypeTensorARM;
946 operands.push_back(elementTypeID);
949 operands.push_back(rankID);
952 operands.push_back(shapeID);
957 return emitError(loc,
"unhandled type in serialization: ") << type;
961Serializer::prepareFunctionType(Location loc, FunctionType type,
962 spirv::Opcode &typeEnum,
963 SmallVectorImpl<uint32_t> &operands) {
964 typeEnum = spirv::Opcode::OpTypeFunction;
965 assert(type.getNumResults() <= 1 &&
966 "serialization supports only a single return value");
967 uint32_t resultID = 0;
969 loc, type.getNumResults() == 1 ? type.getResult(0) : getVoidType(),
973 operands.push_back(resultID);
974 for (
auto &res : type.getInputs()) {
975 uint32_t argTypeID = 0;
976 if (
failed(processType(loc, res, argTypeID))) {
979 operands.push_back(argTypeID);
985Serializer::prepareGraphType(Location loc, GraphType type,
986 spirv::Opcode &typeEnum,
987 SmallVectorImpl<uint32_t> &operands) {
988 typeEnum = spirv::Opcode::OpTypeGraphARM;
989 assert(type.getNumResults() >= 1 &&
990 "serialization requires at least a return value");
992 operands.push_back(type.getNumInputs());
994 for (Type argType : type.getInputs()) {
995 uint32_t argTypeID = 0;
996 if (
failed(processType(loc, argType, argTypeID)))
998 operands.push_back(argTypeID);
1001 for (Type resType : type.getResults()) {
1002 uint32_t resTypeID = 0;
1003 if (
failed(processType(loc, resType, resTypeID)))
1005 operands.push_back(resTypeID);
1015uint32_t Serializer::prepareConstant(Location loc, Type constType,
1016 Attribute valueAttr) {
1017 if (
auto id = prepareConstantScalar(loc, valueAttr)) {
1024 if (
auto id = getConstantID(valueAttr)) {
1028 uint32_t typeID = 0;
1029 if (
failed(processType(loc, constType, typeID))) {
1033 uint32_t resultID = 0;
1034 if (
auto attr = dyn_cast<DenseElementsAttr>(valueAttr)) {
1035 int rank = dyn_cast<ShapedType>(attr.getType()).getRank();
1036 SmallVector<uint64_t, 4> index(rank);
1037 resultID = prepareDenseElementsConstant(loc, constType, attr,
1039 }
else if (
auto arrayAttr = dyn_cast<ArrayAttr>(valueAttr)) {
1040 resultID = prepareArrayConstant(loc, constType, arrayAttr);
1043 if (resultID == 0) {
1044 emitError(loc,
"cannot serialize attribute: ") << valueAttr;
1048 constIDMap[valueAttr] = resultID;
1052uint32_t Serializer::prepareArrayConstant(Location loc, Type constType,
1054 uint32_t typeID = 0;
1055 if (
failed(processType(loc, constType, typeID))) {
1059 uint32_t resultID = getNextID();
1060 SmallVector<uint32_t, 4> operands = {typeID, resultID};
1061 operands.reserve(attr.size() + 2);
1062 spirv::CompositeType compositeType = cast<spirv::CompositeType>(constType);
1063 for (
auto [idx, elementAttr] : llvm::enumerate(attr)) {
1064 if (uint32_t elementID = prepareConstant(
1066 operands.push_back(elementID);
1071 encodeInstructionWithContinuationInto(
1072 typesGlobalValues, spirv::Opcode::OpConstantComposite, operands);
1080Serializer::prepareDenseElementsConstant(Location loc, Type constType,
1081 DenseElementsAttr valueAttr,
int dim,
1082 MutableArrayRef<uint64_t> index) {
1083 auto shapedType = dyn_cast<ShapedType>(valueAttr.
getType());
1084 assert(dim <= shapedType.getRank());
1085 if (shapedType.getRank() == dim) {
1086 if (
auto attr = dyn_cast<DenseIntElementsAttr>(valueAttr)) {
1087 return attr.getType().getElementType().isInteger(1)
1088 ? prepareConstantBool(loc, attr.getValues<BoolAttr>()[index])
1089 : prepareConstantInt(loc,
1090 attr.getValues<IntegerAttr>()[index]);
1092 if (
auto attr = dyn_cast<DenseFPElementsAttr>(valueAttr)) {
1093 return prepareConstantFp(loc, attr.getValues<FloatAttr>()[index]);
1098 uint32_t typeID = 0;
1099 if (
failed(processType(loc, constType, typeID))) {
1103 int64_t numberOfConstituents = shapedType.getDimSize(dim);
1104 uint32_t resultID = getNextID();
1105 SmallVector<uint32_t, 4> operands = {typeID, resultID};
1106 auto elementType = cast<spirv::CompositeType>(constType).getElementType(0);
1107 if (
auto tensorArmType = dyn_cast<spirv::TensorArmType>(constType)) {
1108 ArrayRef<int64_t> innerShape = tensorArmType.getShape().drop_front();
1109 if (!innerShape.empty())
1117 if (isa<spirv::CooperativeMatrixType>(constType)) {
1121 "cannot serialize a non-splat value for a cooperative matrix type");
1126 operands.reserve(3);
1129 if (
auto elementID = prepareDenseElementsConstant(
1130 loc, elementType, valueAttr, shapedType.getRank(), index)) {
1131 operands.push_back(elementID);
1135 }
else if (isa<spirv::TensorArmType>(constType) &&
isZeroValue(valueAttr)) {
1137 {typeID, resultID});
1140 operands.reserve(numberOfConstituents + 2);
1141 for (
int i = 0; i < numberOfConstituents; ++i) {
1143 if (
auto elementID = prepareDenseElementsConstant(
1144 loc, elementType, valueAttr, dim + 1, index)) {
1145 operands.push_back(elementID);
1151 encodeInstructionWithContinuationInto(
1152 typesGlobalValues, spirv::Opcode::OpConstantComposite, operands);
1157uint32_t Serializer::prepareConstantScalar(Location loc, Attribute valueAttr,
1159 if (
auto floatAttr = dyn_cast<FloatAttr>(valueAttr)) {
1160 return prepareConstantFp(loc, floatAttr, isSpec);
1162 if (
auto boolAttr = dyn_cast<BoolAttr>(valueAttr)) {
1163 return prepareConstantBool(loc, boolAttr, isSpec);
1165 if (
auto intAttr = dyn_cast<IntegerAttr>(valueAttr)) {
1166 return prepareConstantInt(loc, intAttr, isSpec);
1172uint32_t Serializer::prepareConstantBool(Location loc, BoolAttr boolAttr,
1176 if (
auto id = getConstantID(boolAttr)) {
1182 uint32_t typeID = 0;
1183 if (
failed(processType(loc, cast<IntegerAttr>(boolAttr).
getType(), typeID))) {
1187 auto resultID = getNextID();
1189 ? (isSpec ? spirv::Opcode::OpSpecConstantTrue
1190 : spirv::Opcode::OpConstantTrue)
1191 : (isSpec ? spirv::Opcode::OpSpecConstantFalse
1192 : spirv::Opcode::OpConstantFalse);
1196 constIDMap[boolAttr] = resultID;
1201uint32_t Serializer::prepareConstantInt(Location loc, IntegerAttr intAttr,
1205 if (
auto id = getConstantID(intAttr)) {
1211 uint32_t typeID = 0;
1212 if (
failed(processType(loc, intAttr.getType(), typeID))) {
1216 auto resultID = getNextID();
1217 APInt value = intAttr.getValue();
1218 unsigned bitwidth = value.getBitWidth();
1219 bool isSigned = intAttr.getType().isSignedInteger();
1221 isSpec ? spirv::Opcode::OpSpecConstant : spirv::Opcode::OpConstant;
1234 word =
static_cast<int32_t
>(value.getSExtValue());
1236 word =
static_cast<uint32_t
>(value.getZExtValue());
1248 words = llvm::bit_cast<DoubleWord>(value.getSExtValue());
1250 words = llvm::bit_cast<DoubleWord>(value.getZExtValue());
1253 {typeID, resultID, words.word1, words.word2});
1256 std::string valueStr;
1257 llvm::raw_string_ostream rss(valueStr);
1258 value.print(rss,
false);
1261 << bitwidth <<
"-bit integer literal: " << valueStr;
1267 constIDMap[intAttr] = resultID;
1272uint32_t Serializer::prepareGraphConstantId(Location loc, Type graphConstType,
1273 IntegerAttr intAttr) {
1275 if (uint32_t
id = getGraphConstantARMId(intAttr)) {
1280 uint32_t typeID = 0;
1281 if (
failed(processType(loc, graphConstType, typeID))) {
1285 uint32_t resultID = getNextID();
1286 APInt value = intAttr.getValue();
1287 unsigned bitwidth = value.getBitWidth();
1288 if (bitwidth > 32) {
1289 emitError(loc,
"Too wide attribute for OpGraphConstantARM: ")
1290 << bitwidth <<
" bits";
1293 bool isSigned = value.isSignedIntN(bitwidth);
1297 word =
static_cast<int32_t
>(value.getSExtValue());
1299 word =
static_cast<uint32_t
>(value.getZExtValue());
1302 {typeID, resultID, word});
1303 graphConstIDMap[intAttr] = resultID;
1307uint32_t Serializer::prepareConstantFp(Location loc, FloatAttr floatAttr,
1311 if (
auto id = getConstantID(floatAttr)) {
1317 uint32_t typeID = 0;
1318 if (
failed(processType(loc, floatAttr.getType(), typeID))) {
1322 auto resultID = getNextID();
1323 APFloat value = floatAttr.getValue();
1324 const llvm::fltSemantics *semantics = &value.getSemantics();
1327 isSpec ? spirv::Opcode::OpSpecConstant : spirv::Opcode::OpConstant;
1329 if (semantics == &APFloat::IEEEsingle()) {
1330 uint32_t word = llvm::bit_cast<uint32_t>(value.convertToFloat());
1332 }
else if (semantics == &APFloat::IEEEdouble()) {
1336 } words = llvm::bit_cast<DoubleWord>(value.convertToDouble());
1338 {typeID, resultID, words.word1, words.word2});
1339 }
else if (llvm::is_contained({&APFloat::IEEEhalf(), &APFloat::BFloat(),
1340 &APFloat::Float8E4M3FN(),
1341 &APFloat::Float8E5M2()},
1344 static_cast<uint32_t
>(value.bitcastToAPInt().getZExtValue());
1347 std::string valueStr;
1348 llvm::raw_string_ostream rss(valueStr);
1352 << floatAttr.getType() <<
"-typed float literal: " << valueStr;
1357 constIDMap[floatAttr] = resultID;
1366 if (
auto typedAttr = dyn_cast<TypedAttr>(attr)) {
1367 return typedAttr.getType();
1370 if (
auto arrayAttr = dyn_cast<ArrayAttr>(attr)) {
1377uint32_t Serializer::prepareConstantCompositeReplicate(
Location loc,
1380 std::pair<Attribute, Type> valueTypePair{valueAttr, resultType};
1381 if (uint32_t
id = getConstantCompositeReplicateID(valueTypePair)) {
1385 uint32_t typeID = 0;
1386 if (
failed(processType(loc, resultType, typeID))) {
1394 auto compositeType = dyn_cast<CompositeType>(resultType);
1399 uint32_t constandID;
1400 if (elementType == valueType) {
1401 constandID = prepareConstant(loc, elementType, valueAttr);
1403 constandID = prepareConstantCompositeReplicate(loc, elementType, valueAttr);
1406 uint32_t resultID = getNextID();
1407 if (dyn_cast<spirv::TensorArmType>(resultType) &&
isZeroValue(valueAttr)) {
1409 {typeID, resultID});
1412 spirv::Opcode::OpConstantCompositeReplicateEXT,
1413 {typeID, resultID, constandID});
1416 constCompositeReplicateIDMap[valueTypePair] = resultID;
1424uint32_t Serializer::getOrCreateBlockID(
Block *block) {
1425 if (uint32_t
id = getBlockID(block))
1427 return blockIDMap[block] = getNextID();
1431void Serializer::printBlock(
Block *block, raw_ostream &os) {
1432 os <<
"block " << block <<
" (id = ";
1433 if (uint32_t
id = getBlockID(block))
1442Serializer::processBlock(
Block *block,
bool omitLabel,
1444 LLVM_DEBUG(llvm::dbgs() <<
"processing block " << block <<
":\n");
1445 LLVM_DEBUG(block->
print(llvm::dbgs()));
1446 LLVM_DEBUG(llvm::dbgs() <<
'\n');
1448 uint32_t blockID = getOrCreateBlockID(block);
1449 LLVM_DEBUG(printBlock(block, llvm::dbgs()));
1456 if (
failed(emitPhiForBlockArguments(block)))
1466 llvm::IsaPred<spirv::LoopOp, spirv::SelectionOp>)) {
1469 emitMerge =
nullptr;
1472 uint32_t blockID = getNextID();
1478 for (Operation &op : llvm::drop_end(*block)) {
1479 if (
failed(processOperation(&op)))
1487 if (
failed(processOperation(&block->
back())))
1493LogicalResult Serializer::emitPhiForBlockArguments(
Block *block) {
1499 LLVM_DEBUG(llvm::dbgs() <<
"emitting phi instructions..\n");
1506 SmallVector<std::pair<Block *, OperandRange>, 4> predecessors;
1508 auto *terminator = mlirPredecessor->getTerminator();
1509 LLVM_DEBUG(llvm::dbgs() <<
" mlir predecessor ");
1510 LLVM_DEBUG(printBlock(mlirPredecessor, llvm::dbgs()));
1511 LLVM_DEBUG(llvm::dbgs() <<
" terminator: " << *terminator <<
"\n");
1520 LLVM_DEBUG(llvm::dbgs() <<
" spirv predecessor ");
1521 LLVM_DEBUG(printBlock(spirvPredecessor, llvm::dbgs()));
1522 if (
auto branchOp = dyn_cast<spirv::BranchOp>(terminator)) {
1523 predecessors.emplace_back(spirvPredecessor, branchOp.getOperands());
1524 }
else if (
auto branchCondOp =
1525 dyn_cast<spirv::BranchConditionalOp>(terminator)) {
1526 std::optional<OperandRange> blockOperands;
1527 if (branchCondOp.getTrueTarget() == block) {
1528 blockOperands = branchCondOp.getTrueTargetOperands();
1530 assert(branchCondOp.getFalseTarget() == block);
1531 blockOperands = branchCondOp.getFalseTargetOperands();
1533 assert(!blockOperands->empty() &&
1534 "expected non-empty block operand range");
1535 predecessors.emplace_back(spirvPredecessor, *blockOperands);
1536 }
else if (
auto switchOp = dyn_cast<spirv::SwitchOp>(terminator)) {
1537 std::optional<OperandRange> blockOperands;
1538 if (block == switchOp.getDefaultTarget()) {
1539 blockOperands = switchOp.getDefaultOperands();
1541 SuccessorRange targets = switchOp.getTargets();
1542 auto it = llvm::find(targets, block);
1543 assert(it != targets.end());
1544 size_t index = std::distance(targets.begin(), it);
1545 blockOperands = switchOp.getTargetOperands(index);
1547 assert(!blockOperands->empty() &&
1548 "expected non-empty block operand range");
1549 predecessors.emplace_back(spirvPredecessor, *blockOperands);
1551 return terminator->emitError(
"unimplemented terminator for Phi creation");
1554 llvm::dbgs() <<
" block arguments:\n";
1555 for (Value v : predecessors.back().second)
1556 llvm::dbgs() <<
" " << v <<
"\n";
1561 for (
auto argIndex : llvm::seq<unsigned>(0, block->
getNumArguments())) {
1565 uint32_t phiTypeID = 0;
1568 uint32_t phiID = getNextID();
1570 LLVM_DEBUG(llvm::dbgs() <<
"[phi] for block argument #" << argIndex <<
' '
1571 << arg <<
" (id = " << phiID <<
")\n");
1574 SmallVector<uint32_t, 8> phiArgs;
1575 phiArgs.push_back(phiTypeID);
1576 phiArgs.push_back(phiID);
1578 for (
auto predIndex : llvm::seq<unsigned>(0, predecessors.size())) {
1579 Value value = predecessors[predIndex].second[argIndex];
1580 uint32_t predBlockId = getOrCreateBlockID(predecessors[predIndex].first);
1581 LLVM_DEBUG(llvm::dbgs() <<
"[phi] use predecessor (id = " << predBlockId
1582 <<
") value " << value <<
' ');
1584 uint32_t valueId = getValueID(value);
1588 LLVM_DEBUG(llvm::dbgs() <<
"(need to fix)\n");
1589 deferredPhiValues[value].push_back(functionBody.size() + 1 +
1592 LLVM_DEBUG(llvm::dbgs() <<
"(id = " << valueId <<
")\n");
1594 phiArgs.push_back(valueId);
1596 phiArgs.push_back(predBlockId);
1600 valueIDMap[arg] = phiID;
1610LogicalResult Serializer::encodeExtensionInstruction(
1611 Operation *op, StringRef extensionSetName, uint32_t extensionOpcode,
1612 ArrayRef<uint32_t> operands, SmallVectorImpl<uint32_t> &binary) {
1614 auto &setID = extendedInstSetIDMap[extensionSetName];
1616 setID = getNextID();
1617 SmallVector<uint32_t, 16> importOperands;
1618 importOperands.push_back(setID);
1626 if (operands.size() < 2) {
1627 return op->
emitError(
"extended instructions must have a result encoding");
1629 SmallVector<uint32_t, 8> extInstOperands;
1630 extInstOperands.reserve(operands.size() + 2);
1631 extInstOperands.append(operands.begin(), std::next(operands.begin(), 2));
1632 extInstOperands.push_back(setID);
1633 extInstOperands.push_back(extensionOpcode);
1634 extInstOperands.append(std::next(operands.begin(), 2), operands.end());
1639LogicalResult Serializer::encodeExtensionInstruction(
1640 Operation *op, StringRef extensionSetName, uint32_t extensionOpcode,
1641 ArrayRef<uint32_t> operands) {
1642 if (
failed(encodeExtensionInstruction(op, extensionSetName, extensionOpcode,
1643 operands, functionBody)))
1646 if (extensionSetName ==
extTosa)
1647 updateTosaOpsMap(op);
1652LogicalResult Serializer::processOperation(Operation *opInst) {
1653 LLVM_DEBUG(llvm::dbgs() <<
"[op] '" << opInst->
getName() <<
"'\n");
1658 .Case([&](spirv::AddressOfOp op) {
return processAddressOfOp(op); })
1659 .Case([&](spirv::BranchOp op) {
return processBranchOp(op); })
1660 .Case([&](spirv::BranchConditionalOp op) {
1661 return processBranchConditionalOp(op);
1663 .Case([&](spirv::ConstantOp op) {
return processConstantOp(op); })
1664 .Case([&](spirv::CompositeConstructOp op) {
1665 return processCompositeConstructOp(op);
1667 .Case([&](spirv::EXTConstantCompositeReplicateOp op) {
1668 return processConstantCompositeReplicateOp(op);
1670 .Case([&](spirv::FuncOp op) {
return processFuncOp(op); })
1671 .Case([&](spirv::GraphARMOp op) {
return processGraphARMOp(op); })
1672 .Case([&](spirv::GraphEntryPointARMOp op) {
1673 return processGraphEntryPointARMOp(op);
1675 .Case([&](spirv::GraphOutputsARMOp op) {
1676 return processGraphOutputsARMOp(op);
1678 .Case([&](spirv::GlobalVariableOp op) {
1679 return processGlobalVariableOp(op);
1681 .Case([&](spirv::GraphConstantARMOp op) {
1682 return processGraphConstantARMOp(op);
1684 .Case([&](spirv::LoopOp op) {
return processLoopOp(op); })
1685 .Case([&](spirv::ReferenceOfOp op) {
return processReferenceOfOp(op); })
1686 .Case([&](spirv::SelectionOp op) {
return processSelectionOp(op); })
1687 .Case([&](spirv::SpecConstantOp op) {
return processSpecConstantOp(op); })
1688 .Case([&](spirv::SpecConstantCompositeOp op) {
1689 return processSpecConstantCompositeOp(op);
1691 .Case([&](spirv::EXTSpecConstantCompositeReplicateOp op) {
1692 return processSpecConstantCompositeReplicateOp(op);
1694 .Case([&](spirv::SpecConstantOperationOp op) {
1695 return processSpecConstantOperationOp(op);
1697 .Case([&](spirv::SwitchOp op) {
return processSwitchOp(op); })
1698 .Case([&](spirv::UndefOp op) {
return processUndefOp(op); })
1699 .Case([&](spirv::VariableOp op) {
return processVariableOp(op); })
1704 [&](Operation *op) {
return dispatchToAutogenSerialization(op); });
1708Serializer::processCompositeConstructOp(spirv::CompositeConstructOp op) {
1709 Location loc = op.getLoc();
1711 uint32_t resultTypeID = 0;
1712 if (
failed(processType(loc, op.getType(), resultTypeID)))
1715 uint32_t resultID = getNextID();
1716 valueIDMap[op.getResult()] = resultID;
1718 SmallVector<uint32_t, 8> operands;
1719 operands.reserve(2 + op.getConstituents().size());
1720 operands.push_back(resultTypeID);
1721 operands.push_back(resultID);
1722 for (Value constituent : op.getConstituents()) {
1723 uint32_t
id = getValueID(constituent);
1724 assert(
id &&
"use before def!");
1725 operands.push_back(
id);
1728 if (
failed(emitDebugLine(functionBody, loc)))
1731 encodeInstructionWithContinuationInto(
1732 functionBody, spirv::Opcode::OpCompositeConstruct, operands);
1734 for (
auto attr : op->getDiscardableAttrDictionary().getValue()) {
1735 if (
failed(processDecoration(loc, resultID, attr)))
1742LogicalResult Serializer::processOpWithoutGrammarAttr(Operation *op,
1743 StringRef extInstSet,
1745 SmallVector<uint32_t, 4> operands;
1746 Location loc = op->
getLoc();
1748 uint32_t resultID = 0;
1750 uint32_t resultTypeID = 0;
1753 operands.push_back(resultTypeID);
1755 resultID = getNextID();
1756 operands.push_back(resultID);
1757 valueIDMap[op->
getResult(0)] = resultID;
1761 operands.push_back(getValueID(operand));
1765 if (
failed(emitDebugLine(functionBody, loc)))
1768 if (extInstSet.empty()) {
1772 if (
failed(encodeExtensionInstruction(op, extInstSet, opcode, operands)))
1778 if (
failed(processDecoration(loc, resultID, attr)))
1786void Serializer::updateTosaOpsMap(Operation *op) {
1787 if (!options.emitDebugInfo)
1790 if (
auto graphOp = dyn_cast<spirv::GraphARMOp>(op->
getParentOp())) {
1791 if (uint32_t graphID = getFunctionID(graphOp.getName()))
1792 tosaOpsMap[graphID][op->
getLoc()].insert(op);
1796LogicalResult Serializer::emitDecoration(uint32_t
target,
1797 spirv::Decoration decoration,
1798 ArrayRef<uint32_t> params) {
1799 uint32_t wordCount = 3 + params.size();
1800 llvm::append_values(
1803 static_cast<uint32_t
>(decoration));
1804 llvm::append_range(decorations, params);
1808LogicalResult Serializer::emitDecorationId(uint32_t
target,
1809 spirv::Decoration decoration,
1810 ArrayRef<uint32_t> operandIds) {
1811 uint32_t wordCount = 3 + operandIds.size();
1812 llvm::append_values(
1815 static_cast<uint32_t
>(decoration));
1816 llvm::append_range(decorations, operandIds);
1820LogicalResult Serializer::emitDebugLine(SmallVectorImpl<uint32_t> &binary,
1822 if (!options.emitDebugInfo)
1825 if (lastProcessedWasMergeInst) {
1826 lastProcessedWasMergeInst =
false;
1830 auto fileLoc = dyn_cast<FileLineColLoc>(loc);
1833 {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