21#include "llvm/ADT/DepthFirstIterator.h"
22#include "llvm/ADT/StringExtras.h"
23#include "llvm/Support/Debug.h"
24#include "llvm/Support/FormatVariadic.h"
26#define DEBUG_TYPE "spirv-serialization"
35std::string getDebugInfoStringFromLoc(
Location loc) {
36 if (
auto fileLineCol = dyn_cast<FileLineColLoc>(loc)) {
37 return llvm::formatv(
"{0}:{1}:{2}", fileLineCol.getFilename(),
38 fileLineCol.getLine(), fileLineCol.getColumn());
40 if (
auto nameLoc = dyn_cast<NameLoc>(loc)) {
41 return nameLoc.getName().str();
43 if (
auto fusedLoc = dyn_cast<FusedLoc>(loc)) {
45 llvm::raw_string_ostream os(
result);
47 map_range(fusedLoc.getLocations(), getDebugInfoStringFromLoc), os,
";");
72 bool skipHeader =
false,
BlockRange skipBlocks = {}) {
73 llvm::df_iterator_default_set<Block *, 4> doneBlocks;
74 doneBlocks.insert(skipBlocks.begin(), skipBlocks.end());
76 for (
Block *block : llvm::depth_first_ext(headerBlock, doneBlocks)) {
77 if (skipHeader && block == headerBlock)
79 if (
failed(blockHandler(block)))
87LogicalResult Serializer::processConstantOp(spirv::ConstantOp op) {
89 prepareConstant(op.getLoc(), op.getType(), op.getValue())) {
90 valueIDMap[op.getResult()] = resultID;
91 if (isa<spirv::TensorArmType>(op.getType()) &&
92 failed(encodeDebugInfoTensorInst(op.getResult())))
99LogicalResult Serializer::processConstantCompositeReplicateOp(
100 spirv::EXTConstantCompositeReplicateOp op) {
101 if (uint32_t resultID = prepareConstantCompositeReplicate(
102 op.getLoc(), op.getType(), op.getValue())) {
103 valueIDMap[op.getResult()] = resultID;
109LogicalResult Serializer::processSpecConstantOp(spirv::SpecConstantOp op) {
110 if (
auto resultID = prepareConstantScalar(op.getLoc(), op.getDefaultValue(),
113 if (
auto specID = op->getDiscardableAttrOfType<IntegerAttr>(
"spec_id")) {
114 auto val =
static_cast<uint32_t
>(specID.getInt());
115 if (failed(emitDecoration(resultID, spirv::Decoration::SpecId, {val})))
119 specConstIDMap[op.getSymName()] = resultID;
120 return processName(resultID, op.getSymName());
126Serializer::processSpecConstantCompositeOp(spirv::SpecConstantCompositeOp op) {
128 if (failed(processType(op.getLoc(), op.getType(), typeID))) {
132 auto resultID = getNextID();
135 operands.push_back(typeID);
136 operands.push_back(resultID);
138 auto constituents = op.getConstituents();
140 for (
auto index : llvm::seq<uint32_t>(0, constituents.size())) {
141 auto constituent = dyn_cast<FlatSymbolRefAttr>(constituents[
index]);
143 auto constituentName = constituent.getValue();
144 auto constituentID = getSpecConstID(constituentName);
146 if (!constituentID) {
147 return op.emitError(
"unknown result <id> for specialization constant ")
151 operands.push_back(constituentID);
154 encodeInstructionWithContinuationInto(
155 typesGlobalValues, spirv::Opcode::OpSpecConstantComposite, operands);
156 specConstIDMap[op.getSymName()] = resultID;
158 return processName(resultID, op.getSymName());
161LogicalResult Serializer::processSpecConstantCompositeReplicateOp(
162 spirv::EXTSpecConstantCompositeReplicateOp op) {
164 if (
failed(processType(op.getLoc(), op.getType(), typeID))) {
168 auto constituent = dyn_cast<FlatSymbolRefAttr>(op.getConstituent());
171 "expected flat symbol reference for constituent instead of ")
172 << op.getConstituent();
174 StringRef constituentName = constituent.getValue();
175 uint32_t constituentID = getSpecConstID(constituentName);
176 if (!constituentID) {
177 return op.emitError(
"unknown result <id> for replicated spec constant ")
181 uint32_t resultID = getNextID();
182 uint32_t operands[] = {typeID, resultID, constituentID};
185 spirv::Opcode::OpSpecConstantCompositeReplicateEXT,
188 specConstIDMap[op.getSymName()] = resultID;
190 return processName(resultID, op.getSymName());
194Serializer::processSpecConstantOperationOp(spirv::SpecConstantOperationOp op) {
196 if (
failed(processType(op.getLoc(), op.getType(), typeID))) {
200 auto resultID = getNextID();
202 SmallVector<uint32_t, 8> operands;
203 operands.push_back(typeID);
204 operands.push_back(resultID);
206 Block &block = op.getRegion().getBlocks().front();
209 std::string enclosedOpName;
210 llvm::raw_string_ostream rss(enclosedOpName);
212 auto enclosedOpcode = spirv::symbolizeOpcode(enclosedOpName);
214 if (!enclosedOpcode) {
215 op.emitError(
"Couldn't find op code for op ")
220 operands.push_back(
static_cast<uint32_t
>(*enclosedOpcode));
224 uint32_t
id = getValueID(operand);
225 assert(
id &&
"use before def!");
226 operands.push_back(
id);
231 valueIDMap[op.getResult()] = resultID;
237Serializer::processGraphConstantARMOp(spirv::GraphConstantARMOp op) {
238 if (uint32_t resultID = prepareGraphConstantId(op.getLoc(), op.getType(),
239 op.getGraphConstantIdAttr())) {
240 valueIDMap[op.getResult()] = resultID;
246LogicalResult Serializer::processUndefOp(spirv::UndefOp op) {
247 auto undefType = op.getType();
248 auto &
id = undefValIDMap[undefType];
252 if (failed(processType(op.getLoc(), undefType, typeID)))
257 valueIDMap[op.getResult()] = id;
261LogicalResult Serializer::processFuncParameter(spirv::FuncOp op) {
262 for (
auto [idx, arg] : llvm::enumerate(op.getArguments())) {
263 uint32_t argTypeID = 0;
264 if (failed(processType(op.getLoc(), arg.getType(), argTypeID))) {
267 auto argValueID = getNextID();
270 auto funcOp = cast<FunctionOpInterface>(*op);
271 for (
auto argAttr : funcOp.getArgAttrs(idx)) {
276 ? Decoration::Alignment
277 : Decoration::FuncParamAttr;
278 if (
failed(processDecorationAttr(op.getLoc(), argValueID, decoration,
279 argAttr.getValue())))
283 if (argAttr.getName() != DecorationAttr::name)
286 if (
auto decAttr = dyn_cast<DecorationAttr>(argAttr.getValue())) {
287 if (
failed(processDecorationAttr(op->getLoc(), argValueID,
288 decAttr.getValue(), decAttr)))
293 valueIDMap[arg] = argValueID;
295 {argTypeID, argValueID});
300LogicalResult Serializer::processFuncOp(spirv::FuncOp op) {
301 LLVM_DEBUG(llvm::dbgs() <<
"-- start function '" << op.getName() <<
"' --\n");
302 assert(functionHeader.empty() && functionBody.empty());
304 uint32_t fnTypeID = 0;
306 if (failed(processType(op.getLoc(), op.getFunctionType(), fnTypeID)))
311 uint32_t resTypeID = 0;
312 auto resultTypes = op.getFunctionType().getResults();
313 if (resultTypes.size() > 1) {
314 return op.emitError(
"cannot serialize function with multiple return types");
316 if (failed(processType(op.getLoc(),
317 (resultTypes.empty() ? getVoidType() : resultTypes[0]),
321 operands.push_back(resTypeID);
322 auto funcID = getOrCreateFunctionID(op.getName());
323 operands.push_back(funcID);
324 operands.push_back(
static_cast<uint32_t
>(op.getFunctionControl()));
325 operands.push_back(fnTypeID);
328 if (!resultTypes.empty()) {
330 if (failed(processDecorationAttr(op.getLoc(), funcID,
331 Decoration::FuncParamAttr, attr)))
336 if (
failed(processName(funcID, op.getName()))) {
341 auto linkageAttr = op.getLinkageAttributes();
342 auto hasImportLinkage =
343 linkageAttr && (linkageAttr.value().getLinkageType().getValue() ==
344 spirv::LinkageType::Import);
345 if (op.isExternal() && !hasImportLinkage) {
347 "'spirv.module' cannot contain external functions "
348 "without 'Import' linkage_attributes (LinkageAttributes)");
350 if (op.isExternal() && hasImportLinkage) {
360 if (failed(processFuncParameter(op)))
367 for (
Value arg : op.getArguments())
368 valueIDMap.erase(arg);
375 if (failed(processFuncParameter(op)))
387 {getOrCreateBlockID(&op.front())});
388 if (failed(processBlock(&op.front(),
true)))
391 &op.front(), [&](
Block *block) { return processBlock(block); },
398 for (
const auto &deferredValue : deferredPhiValues) {
399 Value value = deferredValue.first;
400 uint32_t
id = getValueID(value);
401 LLVM_DEBUG(llvm::dbgs() <<
"[phi] fix reference of value " << value
402 <<
" to id = " <<
id <<
'\n');
403 assert(
id &&
"OpPhi references undefined value!");
404 for (
size_t offset : deferredValue.second)
405 functionBody[offset] = id;
407 deferredPhiValues.clear();
409 LLVM_DEBUG(llvm::dbgs() <<
"-- completed function '" << op.getName()
415 NamedAttrList attrs(op->getDiscardableAttrDictionary().getValue());
416 op->getName().populateInherentAttrs(op, attrs);
417 for (
auto attr : attrs) {
419 auto isValidDecoration = mlir::spirv::symbolizeEnum<spirv::Decoration>(
420 llvm::convertToCamelFromSnakeCase(attr.getName().strref(),
422 if (isValidDecoration != std::nullopt) {
423 if (failed(processDecoration(op.getLoc(), funcID, attr))) {
431 functions.append(functionHeader.begin(), functionHeader.end());
432 functions.append(functionBody.begin(), functionBody.end());
433 functionHeader.clear();
434 functionBody.clear();
441uint32_t Serializer::encodeDebugStringInst(StringRef str) {
442 uint32_t stringID = debugStringIDMap.lookup(str);
448 stringID = getNextID();
449 debugStringIDMap[str] = stringID;
450 operands.push_back(stringID);
457LogicalResult Serializer::encodeDebugInfoGraphInst(spirv::GraphARMOp op,
458 uint32_t &debugGraphID) {
459 if (!options.emitDebugInfo)
462 uint32_t voidTypeID = 0;
463 if (
failed(processType(op.getLoc(), getVoidType(), voidTypeID)))
467 encodeDebugStringInst(getDebugInfoStringFromLoc(op.getLoc()));
469 SmallVector<uint32_t, 6> operands;
470 operands.push_back(voidTypeID);
471 debugGraphID = getNextID();
472 operands.push_back(debugGraphID);
473 uint32_t graphID = getOrCreateFunctionID(op.getName());
474 operands.push_back(graphID);
475 operands.push_back(stringID);
477 if (
failed(encodeExtensionInstruction(
487Serializer::encodeDebugInfoOperationInst(uint32_t debugGraphID,
498 instructionIDs.push_back(getValueID(
result));
500 if (instructionIDs.empty())
503 uint32_t voidTypeID = 0;
504 if (failed(processType(ops[0]->getLoc(), getVoidType(), voidTypeID)))
508 encodeDebugStringInst(getDebugInfoStringFromLoc(ops[0]->getLoc()));
511 operands.push_back(voidTypeID);
512 operands.push_back(getNextID());
513 operands.push_back(debugGraphID);
514 operands.push_back(stringID);
515 operands.append(instructionIDs);
517 if (failed(encodeExtensionInstruction(
520 operands, graphsDebugInfo)))
526LogicalResult Serializer::encodeDebugInfoTensorInst(
Value tensor) {
530 uint32_t voidTypeID = 0;
531 if (failed(processType(
tensor.getLoc(), getVoidType(), voidTypeID)))
534 uint32_t tensorID = valueIDMap.lookup(
tensor);
539 encodeDebugStringInst(getDebugInfoStringFromLoc(
tensor.getLoc()));
542 operands.push_back(voidTypeID);
543 operands.push_back(getNextID());
544 operands.push_back(tensorID);
545 operands.push_back(stringID);
547 if (failed(encodeExtensionInstruction(
556LogicalResult Serializer::processGraphARMOp(spirv::GraphARMOp op) {
557 if (op.getNumResults() < 1) {
558 return op.emitError(
"cannot serialize graph with no return types");
561 LLVM_DEBUG(llvm::dbgs() <<
"-- start graph '" << op.getName() <<
"' --\n");
562 assert(functionHeader.empty() && functionBody.empty());
564 uint32_t funcID = getOrCreateFunctionID(op.getName());
565 uint32_t fnTypeID = 0;
567 if (failed(processType(op.getLoc(), op.getFunctionType(), fnTypeID)))
573 for (
auto [idx, arg] : llvm::enumerate(op.getArguments())) {
574 uint32_t argTypeID = 0;
575 SmallVector<uint32_t, 3> inputOperands;
577 if (
failed(processType(op.getLoc(), arg.getType(), argTypeID))) {
581 uint32_t argValueID = getNextID();
582 valueIDMap[arg] = argValueID;
584 auto attr = IntegerAttr::get(IntegerType::get(op.getContext(), 32), idx);
585 uint32_t indexID = prepareConstantInt(op.getLoc(), attr,
false);
587 inputOperands.push_back(argTypeID);
588 inputOperands.push_back(argValueID);
589 inputOperands.push_back(indexID);
594 if (failed(encodeDebugInfoTensorInst(arg)))
598 if (failed(processBlock(&op.front(),
true)))
601 &op.front(), [&](
Block *block) { return processBlock(block); },
606 LLVM_DEBUG(llvm::dbgs() <<
"-- completed graph '" << op.getName()
611 llvm::append_range(graphs, functionHeader);
612 llvm::append_range(graphs, functionBody);
613 functionHeader.clear();
614 functionBody.clear();
616 uint32_t debugGraphID = 0;
617 if (
failed(encodeDebugInfoGraphInst(op, debugGraphID)))
620 for (
const auto &debugEntry : tosaOpsMap[funcID]) {
621 if (
failed(encodeDebugInfoOperationInst(debugGraphID, debugEntry.second)))
629Serializer::processGraphEntryPointARMOp(spirv::GraphEntryPointARMOp op) {
630 SmallVector<uint32_t, 4> operands;
631 StringRef graph = op.getFn();
633 uint32_t graphID = getOrCreateFunctionID(graph);
634 operands.push_back(graphID);
639 if (ArrayAttr interface = op.getInterface()) {
640 for (
Attribute var : interface.getValue()) {
641 StringRef value = cast<FlatSymbolRefAttr>(var).getValue();
642 if (uint32_t
id = getVariableID(value)) {
643 operands.push_back(
id);
646 "referencing undefined global variable."
647 "spirv.GraphEntryPointARM is at the end of spirv.module. All "
648 "referenced variables should already be defined");
657Serializer::processGraphOutputsARMOp(spirv::GraphOutputsARMOp op) {
658 for (
auto [idx, value] : llvm::enumerate(op->getOperands())) {
661 Type resType = value.getType();
662 uint32_t resTypeID = 0;
663 if (failed(processType(op.getLoc(), resType, resTypeID))) {
667 uint32_t outputID = getValueID(value);
668 auto attr = IntegerAttr::get(IntegerType::get(op.getContext(), 32), idx);
669 uint32_t indexID = prepareConstantInt(op.getLoc(), attr,
false);
671 outputOperands.push_back(outputID);
672 outputOperands.push_back(indexID);
674 if (
failed(encodeDebugInfoTensorInst(value)))
683LogicalResult Serializer::processVariableOp(spirv::VariableOp op) {
684 SmallVector<uint32_t, 4> operands;
685 SmallVector<StringRef, 2> elidedAttrs;
686 uint32_t resultID = 0;
687 uint32_t resultTypeID = 0;
688 if (
failed(processType(op.getLoc(), op.getType(), resultTypeID))) {
691 operands.push_back(resultTypeID);
692 resultID = getNextID();
693 valueIDMap[op.getResult()] = resultID;
694 operands.push_back(resultID);
695 operands.push_back(
static_cast<uint32_t
>(op.getStorageClass()));
697 for (
auto arg : op.getODSOperands(0)) {
698 auto argID = getValueID(arg);
700 return emitError(op.getLoc(),
"operand 0 has a use before def");
702 operands.push_back(argID);
704 if (failed(emitDebugLine(functionHeader, op.getLoc())))
707 for (
auto attr : op->getDiscardableAttrDictionary().getValue()) {
708 if (llvm::any_of(elidedAttrs, [&](StringRef elided) {
709 return attr.getName() == elided;
713 if (
failed(processDecoration(op.getLoc(), resultID, attr))) {
721Serializer::processGlobalVariableOp(spirv::GlobalVariableOp varOp) {
723 uint32_t resultTypeID = 0;
724 SmallVector<StringRef, 4> elidedAttrs;
725 if (
failed(processType(varOp.getLoc(), varOp.getType(), resultTypeID))) {
729 elidedAttrs.push_back(
"type");
730 SmallVector<uint32_t, 4> operands;
731 operands.push_back(resultTypeID);
732 auto resultID = getNextID();
735 auto varName = varOp.getSymName();
736 elidedAttrs.push_back(varOp.getSymNameAttrName());
737 if (failed(processName(resultID, varName))) {
740 globalVarIDMap[varName] = resultID;
741 operands.push_back(resultID);
744 operands.push_back(
static_cast<uint32_t
>(varOp.storageClass()));
747 StringRef initAttrName = varOp.getInitializerAttrName().getValue();
748 if (std::optional<StringRef> initSymbolName = varOp.getInitializer()) {
749 uint32_t initializerID = 0;
752 varOp->getParentOp(), initRef.
getAttr());
755 if (isa<spirv::GlobalVariableOp>(initOp))
756 initializerID = getVariableID(*initSymbolName);
758 initializerID = getSpecConstID(*initSymbolName);
762 "invalid usage of undefined variable as initializer");
764 operands.push_back(initializerID);
765 elidedAttrs.push_back(initAttrName);
768 if (failed(emitDebugLine(typesGlobalValues, varOp.getLoc())))
771 elidedAttrs.push_back(initAttrName);
774 NamedAttrList attrs(varOp->getDiscardableAttrDictionary().getValue());
775 varOp->getName().populateInherentAttrs(varOp, attrs);
776 for (
auto attr : attrs) {
777 if (llvm::any_of(elidedAttrs, [&](StringRef elided) {
778 return attr.getName() == elided;
782 if (
failed(processDecoration(varOp.getLoc(), resultID, attr))) {
789LogicalResult Serializer::processSelectionOp(spirv::SelectionOp selectionOp) {
792 auto &body = selectionOp.getBody();
793 for (
Block &block : body)
794 getOrCreateBlockID(&block);
796 auto *headerBlock = selectionOp.getHeaderBlock();
797 auto *mergeBlock = selectionOp.getMergeBlock();
798 auto headerID = getBlockID(headerBlock);
799 auto mergeID = getBlockID(mergeBlock);
800 auto loc = selectionOp.getLoc();
806 auto mergeOp = cast<spirv::MergeOp>(mergeBlock->back());
807 assert(selectionOp.getNumResults() == mergeOp.getNumOperands());
808 for (
unsigned i = 0, e = selectionOp.getNumResults(); i != e; ++i)
809 selectionOp.getResult(i).replaceAllUsesWith(mergeOp.getOperand(i));
821 auto emitSelectionMerge = [&]() {
822 if (failed(emitDebugLine(functionBody, loc)))
824 lastProcessedWasMergeInst =
true;
826 functionBody, spirv::Opcode::OpSelectionMerge,
827 {mergeID,
static_cast<uint32_t
>(selectionOp.getSelectionControl())});
831 processBlock(headerBlock,
false, emitSelectionMerge)))
838 headerBlock, [&](
Block *block) {
return processBlock(block); },
839 true, {mergeBlock})))
850 if (failed(emitPhiForBlockArguments(mergeBlock)))
853 LLVM_DEBUG(llvm::dbgs() <<
"done merge ");
854 LLVM_DEBUG(
printBlock(mergeBlock, llvm::dbgs()));
855 LLVM_DEBUG(llvm::dbgs() <<
"\n");
859LogicalResult Serializer::processLoopOp(spirv::LoopOp loopOp) {
863 auto &body = loopOp.getBody();
864 for (
Block &block : llvm::drop_begin(body))
865 getOrCreateBlockID(&block);
867 auto *headerBlock = loopOp.getHeaderBlock();
868 auto *continueBlock = loopOp.getContinueBlock();
869 auto *mergeBlock = loopOp.getMergeBlock();
870 auto headerID = getBlockID(headerBlock);
871 auto continueID = getBlockID(continueBlock);
872 auto mergeID = getBlockID(mergeBlock);
873 auto loc = loopOp.getLoc();
877 auto mergeOp = cast<spirv::MergeOp>(mergeBlock->back());
878 assert(loopOp.getNumResults() == mergeOp.getNumOperands());
879 for (
unsigned i = 0, e = loopOp.getNumResults(); i != e; ++i)
880 loopOp.getResult(i).replaceAllUsesWith(mergeOp.getOperand(i));
896 auto emitLoopMerge = [&]() {
897 if (failed(emitDebugLine(functionBody, loc)))
899 lastProcessedWasMergeInst =
true;
901 functionBody, spirv::Opcode::OpLoopMerge,
902 {mergeID, continueID,
static_cast<uint32_t
>(loopOp.getLoopControl())});
905 if (failed(processBlock(headerBlock,
false, emitLoopMerge)))
912 headerBlock, [&](
Block *block) {
return processBlock(block); },
913 true, {continueBlock, mergeBlock})))
917 if (failed(processBlock(continueBlock)))
925 LLVM_DEBUG(llvm::dbgs() <<
"done merge ");
927 LLVM_DEBUG(llvm::dbgs() <<
"\n");
931LogicalResult Serializer::processBranchConditionalOp(
932 spirv::BranchConditionalOp condBranchOp) {
933 auto conditionID = getValueID(condBranchOp.getCondition());
934 auto trueLabelID = getOrCreateBlockID(condBranchOp.getTrueBlock());
935 auto falseLabelID = getOrCreateBlockID(condBranchOp.getFalseBlock());
938 if (
auto weights = condBranchOp.getBranchWeights()) {
939 for (
auto val : weights->getValue())
940 arguments.push_back(cast<IntegerAttr>(val).getInt());
943 if (failed(emitDebugLine(functionBody, condBranchOp.getLoc())))
950LogicalResult Serializer::processBranchOp(spirv::BranchOp branchOp) {
951 if (failed(emitDebugLine(functionBody, branchOp.getLoc())))
954 {getOrCreateBlockID(branchOp.getTarget())});
958LogicalResult Serializer::processSwitchOp(spirv::SwitchOp switchOp) {
959 Value selector = switchOp.getSelector();
960 uint32_t selectorID = getValueID(selector);
961 uint32_t defaultLabelID = getOrCreateBlockID(switchOp.getDefaultTarget());
964 std::optional<mlir::DenseIntElementsAttr> literals = switchOp.getLiterals();
970 for (
auto [literal,
target] : llvm::zip_equal(*literals, targets)) {
971 if (bitWidth <= 32) {
975 isSigned ?
static_cast<uint32_t
>(literal.getSExtValue())
976 :
static_cast<uint32_t
>(literal.getZExtValue()));
979 for (
unsigned offset = 0; offset < bitWidth; offset += 32)
980 arguments.push_back(literal.extractBitsAsZExtValue(32, offset));
982 uint32_t targetLabelID = getOrCreateBlockID(
target);
983 arguments.push_back(targetLabelID);
987 if (failed(emitDebugLine(functionBody, switchOp.getLoc())))
993LogicalResult Serializer::processAddressOfOp(spirv::AddressOfOp addressOfOp) {
994 auto varName = addressOfOp.getVariable();
995 auto variableID = getVariableID(varName);
997 return addressOfOp.emitError(
"unknown result <id> for variable ")
1000 valueIDMap[addressOfOp.getPointer()] = variableID;
1005Serializer::processReferenceOfOp(spirv::ReferenceOfOp referenceOfOp) {
1006 auto constName = referenceOfOp.getSpecConst();
1007 auto constID = getSpecConstID(constName);
1009 return referenceOfOp.emitError(
1010 "unknown result <id> for specialization constant ")
1013 valueIDMap[referenceOfOp.getReference()] = constID;
1019Serializer::processOp<spirv::EntryPointOp>(spirv::EntryPointOp op) {
1022 operands.push_back(
static_cast<uint32_t
>(op.getExecutionModel()));
1024 auto funcID = getFunctionID(op.getFn());
1026 return op.emitError(
"missing <id> for function ")
1028 <<
"; function needs to be defined before spirv.EntryPoint is "
1031 operands.push_back(funcID);
1036 if (
auto interface = op.getInterface()) {
1037 for (
auto var : interface.getValue()) {
1038 auto id = getVariableID(cast<FlatSymbolRefAttr>(var).getValue());
1040 return op.emitError(
1041 "referencing undefined global variable."
1042 "spirv.EntryPoint is at the end of spirv.module. All "
1043 "referenced variables should already be defined");
1045 operands.push_back(
id);
1054Serializer::processOp<spirv::ExecutionModeOp>(spirv::ExecutionModeOp op) {
1057 auto funcID = getFunctionID(op.getFn());
1059 return op.emitError(
"missing <id> for function ")
1061 <<
"; function needs to be serialized before ExecutionModeOp is "
1064 operands.push_back(funcID);
1066 operands.push_back(
static_cast<uint32_t
>(op.getExecutionMode()));
1069 auto values = op.getValues();
1071 for (
auto &intVal : values.getValue()) {
1072 operands.push_back(
static_cast<uint32_t
>(
1073 cast<IntegerAttr>(intVal).getValue().getZExtValue()));
1083Serializer::processOp<spirv::ExecutionModeIdOp>(spirv::ExecutionModeIdOp op) {
1086 uint32_t funcID = getFunctionID(op.getFn());
1088 return op.emitError(
"missing <id> for function ")
1090 <<
"; function needs to be serialized before ExecutionModeIdOp is "
1093 operands.push_back(funcID);
1094 operands.push_back(
static_cast<uint32_t
>(op.getExecutionMode()));
1097 uint32_t
id = getSpecConstID(cast<FlatSymbolRefAttr>(refVal).getValue());
1099 return op.emitError(
"unknown <id> for specialization constant ")
1100 << cast<FlatSymbolRefAttr>(refVal).getValue();
1102 operands.push_back(
id);
1111Serializer::processOp<spirv::FunctionCallOp>(spirv::FunctionCallOp op) {
1112 auto funcName = op.getCallee();
1113 uint32_t resTypeID = 0;
1115 Type resultTy = op.getNumResults() ? *op.result_type_begin() : getVoidType();
1116 if (failed(processType(op.getLoc(), resultTy, resTypeID)))
1119 auto funcID = getOrCreateFunctionID(funcName);
1120 auto funcCallID = getNextID();
1123 for (
auto value : op.getArguments()) {
1124 auto valueID = getValueID(value);
1125 assert(valueID &&
"cannot find a value for spirv.FunctionCall");
1126 operands.push_back(valueID);
1129 if (!isa<NoneType>(resultTy))
1130 valueIDMap[op.getResult(0)] = funcCallID;
1133 for (
auto attr : op->getDiscardableAttrs())
1134 if (failed(processDecoration(op.getLoc(), funcCallID, attr)))
1141Serializer::processOp<spirv::CopyMemoryOp>(spirv::CopyMemoryOp op) {
1145 for (
Value operand : op->getOperands()) {
1146 auto id = getValueID(operand);
1147 assert(
id &&
"use before def!");
1148 operands.push_back(
id);
1151 StringAttr memoryAccess = op.getMemoryAccessAttrName();
1152 if (std::optional<spirv::MemoryAccess> value = op.getMemoryAccess())
1153 operands.push_back(
static_cast<uint32_t
>(*value));
1155 elidedAttrs.push_back(memoryAccess.strref());
1157 StringAttr alignment = op.getAlignmentAttrName();
1158 if (std::optional<uint32_t> value = op.getAlignment())
1159 operands.push_back(*value);
1161 elidedAttrs.push_back(alignment.strref());
1163 StringAttr sourceMemoryAccess = op.getSourceMemoryAccessAttrName();
1164 if (std::optional<spirv::MemoryAccess> value = op.getSourceMemoryAccess())
1165 operands.push_back(
static_cast<uint32_t
>(*value));
1167 elidedAttrs.push_back(sourceMemoryAccess.strref());
1169 StringAttr sourceAlignment = op.getSourceAlignmentAttrName();
1170 if (std::optional<uint32_t> value = op.getSourceAlignment())
1171 operands.push_back(*value);
1173 elidedAttrs.push_back(sourceAlignment.strref());
1174 if (failed(emitDebugLine(functionBody, op.getLoc())))
1181LogicalResult Serializer::processOp<spirv::GenericCastToPtrExplicitOp>(
1182 spirv::GenericCastToPtrExplicitOp op) {
1186 uint32_t resultTypeID = 0;
1187 uint32_t resultID = 0;
1188 resultTy = op->getResult(0).getType();
1189 if (failed(processType(loc, resultTy, resultTypeID)))
1191 operands.push_back(resultTypeID);
1193 resultID = getNextID();
1194 operands.push_back(resultID);
1195 valueIDMap[op->getResult(0)] = resultID;
1197 for (
Value operand : op->getOperands())
1198 operands.push_back(getValueID(operand));
1199 spirv::StorageClass resultStorage =
1200 cast<spirv::PointerType>(resultTy).getStorageClass();
1201 operands.push_back(
static_cast<uint32_t
>(resultStorage));
1209#define GET_SERIALIZATION_FNS
1210#include "mlir/Dialect/SPIRV/IR/SPIRVSerialization.inc"
static llvm::ManagedStatic< PassManagerOptions > options
static LogicalResult visitInPrettyBlockOrder(Block *headerBlock, function_ref< LogicalResult(Block *)> blockHandler, bool skipHeader=false, BlockRange skipBlocks={})
A pre-order depth-first visitor function for processing basic blocks.
static void printBlock(llvm::raw_ostream &os, Block *block, OpPrintingFlags &flags)
Attributes are known-constant values of operations.
This class provides an abstraction over the different types of ranges over Blocks.
Block represents an ordered list of Operations.
OpListType & getOperations()
A symbol reference with a reference path containing a single element.
StringAttr getAttr() const
Returns the name of the held symbol reference as a StringAttr.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
NamedAttrList is array of NamedAttributes that tracks whether it is sorted and does some basic work t...
This is a value defined by a result of an operation.
StringRef getStringRef() const
Return the name of this operation. This always succeeds.
StringRef stripDialect() const
Return the operation name with dialect name stripped, if it has one.
Operation is the basic unit of execution within MLIR.
OperationName getName()
The name of an operation is the key identifier for it.
operand_range getOperands()
Returns an iterator on the underlying Value's.
static Operation * lookupNearestSymbolFrom(Operation *from, StringAttr symbol)
Returns the operation registered with the given symbol name within the closest parent operation of,...
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
bool isSignedInteger() const
Return true if this is a signed 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.
constexpr llvm::StringLiteral extDebugInfo
Extension set name for non-semantic graph debug info.
void encodeStringLiteralInto(SmallVectorImpl< uint32_t > &binary, StringRef literal)
Encodes an SPIR-V literal string into the given binary vector.
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.
StringRef getFuncParamAttrName()
Returns the attribute name for specifying function parameter and result attributes.
constexpr StringRef attributeName()
StringRef getFuncParamAlignmentAttrName()
Returns the attribute name for specifying function parameter alignment.
Include the generated interface declarations.
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
llvm::SetVector< T, Vector, Set, N > SetVector
llvm::function_ref< Fn > function_ref