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();
439uint32_t Serializer::encodeDebugStringInst(StringRef str) {
440 uint32_t stringID = debugStringIDMap.lookup(str);
446 stringID = getNextID();
447 debugStringIDMap[str] = stringID;
448 operands.push_back(stringID);
455LogicalResult Serializer::encodeDebugInfoGraphInst(spirv::GraphARMOp op,
456 uint32_t &debugGraphID) {
457 if (!options.emitDebugInfo)
460 uint32_t voidTypeID = 0;
461 if (
failed(processType(op.getLoc(), getVoidType(), voidTypeID)))
465 encodeDebugStringInst(getDebugInfoStringFromLoc(op.getLoc()));
467 SmallVector<uint32_t, 6> operands;
468 operands.push_back(voidTypeID);
469 debugGraphID = getNextID();
470 operands.push_back(debugGraphID);
471 uint32_t graphID = getOrCreateFunctionID(op.getName());
472 operands.push_back(graphID);
473 operands.push_back(stringID);
475 if (
failed(encodeExtensionInstruction(
485Serializer::encodeDebugInfoOperationInst(uint32_t debugGraphID,
487 if (!options.emitDebugInfo)
496 instructionIDs.push_back(getValueID(
result));
498 if (instructionIDs.empty())
501 uint32_t voidTypeID = 0;
502 if (failed(processType(ops[0]->getLoc(), getVoidType(), voidTypeID)))
506 encodeDebugStringInst(getDebugInfoStringFromLoc(ops[0]->getLoc()));
509 operands.push_back(voidTypeID);
510 operands.push_back(getNextID());
511 operands.push_back(debugGraphID);
512 operands.push_back(stringID);
513 operands.append(instructionIDs);
515 if (failed(encodeExtensionInstruction(
518 operands, graphsDebugInfo)))
524LogicalResult Serializer::encodeDebugInfoTensorInst(
Value tensor) {
528 uint32_t voidTypeID = 0;
529 if (failed(processType(
tensor.getLoc(), getVoidType(), voidTypeID)))
532 uint32_t tensorID = valueIDMap.lookup(
tensor);
537 encodeDebugStringInst(getDebugInfoStringFromLoc(
tensor.getLoc()));
540 operands.push_back(voidTypeID);
541 operands.push_back(getNextID());
542 operands.push_back(tensorID);
543 operands.push_back(stringID);
545 if (failed(encodeExtensionInstruction(
554LogicalResult Serializer::processGraphARMOp(spirv::GraphARMOp op) {
555 if (op.getNumResults() < 1) {
556 return op.emitError(
"cannot serialize graph with no return types");
559 LLVM_DEBUG(llvm::dbgs() <<
"-- start graph '" << op.getName() <<
"' --\n");
560 assert(functionHeader.empty() && functionBody.empty());
562 uint32_t funcID = getOrCreateFunctionID(op.getName());
563 uint32_t fnTypeID = 0;
565 if (failed(processType(op.getLoc(), op.getFunctionType(), fnTypeID)))
571 for (
auto [idx, arg] : llvm::enumerate(op.getArguments())) {
572 uint32_t argTypeID = 0;
573 SmallVector<uint32_t, 3> inputOperands;
575 if (
failed(processType(op.getLoc(), arg.getType(), argTypeID))) {
579 uint32_t argValueID = getNextID();
580 valueIDMap[arg] = argValueID;
582 auto attr = IntegerAttr::get(IntegerType::get(op.getContext(), 32), idx);
583 uint32_t indexID = prepareConstantInt(op.getLoc(), attr,
false);
585 inputOperands.push_back(argTypeID);
586 inputOperands.push_back(argValueID);
587 inputOperands.push_back(indexID);
592 if (failed(encodeDebugInfoTensorInst(arg)))
596 if (failed(processBlock(&op.front(),
true)))
599 &op.front(), [&](
Block *block) { return processBlock(block); },
604 LLVM_DEBUG(llvm::dbgs() <<
"-- completed graph '" << op.getName()
609 llvm::append_range(graphs, functionHeader);
610 llvm::append_range(graphs, functionBody);
611 functionHeader.clear();
612 functionBody.clear();
614 uint32_t debugGraphID = 0;
615 if (
failed(encodeDebugInfoGraphInst(op, debugGraphID)))
618 for (
const auto &debugEntry : tosaOpsMap[funcID]) {
619 if (
failed(encodeDebugInfoOperationInst(debugGraphID, debugEntry.second)))
627Serializer::processGraphEntryPointARMOp(spirv::GraphEntryPointARMOp op) {
628 SmallVector<uint32_t, 4> operands;
629 StringRef graph = op.getFn();
631 uint32_t graphID = getOrCreateFunctionID(graph);
632 operands.push_back(graphID);
637 if (ArrayAttr interface = op.getInterface()) {
638 for (
Attribute var : interface.getValue()) {
639 StringRef value = cast<FlatSymbolRefAttr>(var).getValue();
640 if (uint32_t
id = getVariableID(value)) {
641 operands.push_back(
id);
644 "referencing undefined global variable."
645 "spirv.GraphEntryPointARM is at the end of spirv.module. All "
646 "referenced variables should already be defined");
655Serializer::processGraphOutputsARMOp(spirv::GraphOutputsARMOp op) {
656 for (
auto [idx, value] : llvm::enumerate(op->getOperands())) {
659 Type resType = value.getType();
660 uint32_t resTypeID = 0;
661 if (failed(processType(op.getLoc(), resType, resTypeID))) {
665 uint32_t outputID = getValueID(value);
666 auto attr = IntegerAttr::get(IntegerType::get(op.getContext(), 32), idx);
667 uint32_t indexID = prepareConstantInt(op.getLoc(), attr,
false);
669 outputOperands.push_back(outputID);
670 outputOperands.push_back(indexID);
672 if (
failed(encodeDebugInfoTensorInst(value)))
681LogicalResult Serializer::processVariableOp(spirv::VariableOp op) {
682 SmallVector<uint32_t, 4> operands;
683 SmallVector<StringRef, 2> elidedAttrs;
684 uint32_t resultID = 0;
685 uint32_t resultTypeID = 0;
686 if (
failed(processType(op.getLoc(), op.getType(), resultTypeID))) {
689 operands.push_back(resultTypeID);
690 resultID = getNextID();
691 valueIDMap[op.getResult()] = resultID;
692 operands.push_back(resultID);
693 operands.push_back(
static_cast<uint32_t
>(op.getStorageClass()));
695 for (
auto arg : op.getODSOperands(0)) {
696 auto argID = getValueID(arg);
698 return emitError(op.getLoc(),
"operand 0 has a use before def");
700 operands.push_back(argID);
702 if (failed(emitDebugLine(functionHeader, op.getLoc())))
705 for (
auto attr : op->getDiscardableAttrDictionary().getValue()) {
706 if (llvm::any_of(elidedAttrs, [&](StringRef elided) {
707 return attr.getName() == elided;
711 if (
failed(processDecoration(op.getLoc(), resultID, attr))) {
719Serializer::processGlobalVariableOp(spirv::GlobalVariableOp varOp) {
721 uint32_t resultTypeID = 0;
722 SmallVector<StringRef, 4> elidedAttrs;
723 if (
failed(processType(varOp.getLoc(), varOp.getType(), resultTypeID))) {
727 elidedAttrs.push_back(
"type");
728 SmallVector<uint32_t, 4> operands;
729 operands.push_back(resultTypeID);
730 auto resultID = getNextID();
733 auto varName = varOp.getSymName();
734 elidedAttrs.push_back(varOp.getSymNameAttrName());
735 if (failed(processName(resultID, varName))) {
738 globalVarIDMap[varName] = resultID;
739 operands.push_back(resultID);
742 operands.push_back(
static_cast<uint32_t
>(varOp.storageClass()));
745 StringRef initAttrName = varOp.getInitializerAttrName().getValue();
746 if (std::optional<StringRef> initSymbolName = varOp.getInitializer()) {
747 uint32_t initializerID = 0;
750 varOp->getParentOp(), initRef.
getAttr());
753 if (isa<spirv::GlobalVariableOp>(initOp))
754 initializerID = getVariableID(*initSymbolName);
756 initializerID = getSpecConstID(*initSymbolName);
760 "invalid usage of undefined variable as initializer");
762 operands.push_back(initializerID);
763 elidedAttrs.push_back(initAttrName);
766 if (failed(emitDebugLine(typesGlobalValues, varOp.getLoc())))
769 elidedAttrs.push_back(initAttrName);
772 NamedAttrList attrs(varOp->getDiscardableAttrDictionary().getValue());
773 varOp->getName().populateInherentAttrs(varOp, attrs);
774 for (
auto attr : attrs) {
775 if (llvm::any_of(elidedAttrs, [&](StringRef elided) {
776 return attr.getName() == elided;
780 if (
failed(processDecoration(varOp.getLoc(), resultID, attr))) {
787LogicalResult Serializer::processSelectionOp(spirv::SelectionOp selectionOp) {
790 auto &body = selectionOp.getBody();
791 for (
Block &block : body)
792 getOrCreateBlockID(&block);
794 auto *headerBlock = selectionOp.getHeaderBlock();
795 auto *mergeBlock = selectionOp.getMergeBlock();
796 auto headerID = getBlockID(headerBlock);
797 auto mergeID = getBlockID(mergeBlock);
798 auto loc = selectionOp.getLoc();
804 auto mergeOp = cast<spirv::MergeOp>(mergeBlock->back());
805 assert(selectionOp.getNumResults() == mergeOp.getNumOperands());
806 for (
unsigned i = 0, e = selectionOp.getNumResults(); i != e; ++i)
807 selectionOp.getResult(i).replaceAllUsesWith(mergeOp.getOperand(i));
819 auto emitSelectionMerge = [&]() {
820 if (failed(emitDebugLine(functionBody, loc)))
822 lastProcessedWasMergeInst =
true;
824 functionBody, spirv::Opcode::OpSelectionMerge,
825 {mergeID,
static_cast<uint32_t
>(selectionOp.getSelectionControl())});
829 processBlock(headerBlock,
false, emitSelectionMerge)))
836 headerBlock, [&](
Block *block) {
return processBlock(block); },
837 true, {mergeBlock})))
848 if (failed(emitPhiForBlockArguments(mergeBlock)))
851 LLVM_DEBUG(llvm::dbgs() <<
"done merge ");
852 LLVM_DEBUG(
printBlock(mergeBlock, llvm::dbgs()));
853 LLVM_DEBUG(llvm::dbgs() <<
"\n");
857LogicalResult Serializer::processLoopOp(spirv::LoopOp loopOp) {
861 auto &body = loopOp.getBody();
862 for (
Block &block : llvm::drop_begin(body))
863 getOrCreateBlockID(&block);
865 auto *headerBlock = loopOp.getHeaderBlock();
866 auto *continueBlock = loopOp.getContinueBlock();
867 auto *mergeBlock = loopOp.getMergeBlock();
868 auto headerID = getBlockID(headerBlock);
869 auto continueID = getBlockID(continueBlock);
870 auto mergeID = getBlockID(mergeBlock);
871 auto loc = loopOp.getLoc();
875 auto mergeOp = cast<spirv::MergeOp>(mergeBlock->back());
876 assert(loopOp.getNumResults() == mergeOp.getNumOperands());
877 for (
unsigned i = 0, e = loopOp.getNumResults(); i != e; ++i)
878 loopOp.getResult(i).replaceAllUsesWith(mergeOp.getOperand(i));
894 auto emitLoopMerge = [&]() {
895 if (
failed(emitDebugLine(functionBody, loc)))
897 lastProcessedWasMergeInst =
true;
899 functionBody, spirv::Opcode::OpLoopMerge,
900 {mergeID, continueID,
static_cast<uint32_t
>(loopOp.getLoopControl())});
903 if (failed(processBlock(headerBlock,
false, emitLoopMerge)))
910 headerBlock, [&](
Block *block) {
return processBlock(block); },
911 true, {continueBlock, mergeBlock})))
915 if (failed(processBlock(continueBlock)))
923 LLVM_DEBUG(llvm::dbgs() <<
"done merge ");
924 LLVM_DEBUG(
printBlock(mergeBlock, llvm::dbgs()));
925 LLVM_DEBUG(llvm::dbgs() <<
"\n");
929LogicalResult Serializer::processBranchConditionalOp(
930 spirv::BranchConditionalOp condBranchOp) {
931 auto conditionID = getValueID(condBranchOp.getCondition());
932 auto trueLabelID = getOrCreateBlockID(condBranchOp.getTrueBlock());
933 auto falseLabelID = getOrCreateBlockID(condBranchOp.getFalseBlock());
936 if (
auto weights = condBranchOp.getBranchWeights()) {
937 for (
auto val : weights->getValue())
938 arguments.push_back(cast<IntegerAttr>(val).getInt());
941 if (failed(emitDebugLine(functionBody, condBranchOp.getLoc())))
948LogicalResult Serializer::processBranchOp(spirv::BranchOp branchOp) {
949 if (failed(emitDebugLine(functionBody, branchOp.getLoc())))
952 {getOrCreateBlockID(branchOp.getTarget())});
956LogicalResult Serializer::processSwitchOp(spirv::SwitchOp switchOp) {
957 uint32_t selectorID = getValueID(switchOp.getSelector());
958 uint32_t defaultLabelID = getOrCreateBlockID(switchOp.getDefaultTarget());
961 std::optional<mlir::DenseIntElementsAttr> literals = switchOp.getLiterals();
964 for (
auto [literal,
target] : llvm::zip_equal(*literals, targets)) {
965 arguments.push_back(literal.getLimitedValue());
966 uint32_t targetLabelID = getOrCreateBlockID(
target);
967 arguments.push_back(targetLabelID);
971 if (failed(emitDebugLine(functionBody, switchOp.getLoc())))
977LogicalResult Serializer::processAddressOfOp(spirv::AddressOfOp addressOfOp) {
978 auto varName = addressOfOp.getVariable();
979 auto variableID = getVariableID(varName);
981 return addressOfOp.emitError(
"unknown result <id> for variable ")
984 valueIDMap[addressOfOp.getPointer()] = variableID;
989Serializer::processReferenceOfOp(spirv::ReferenceOfOp referenceOfOp) {
990 auto constName = referenceOfOp.getSpecConst();
991 auto constID = getSpecConstID(constName);
993 return referenceOfOp.emitError(
994 "unknown result <id> for specialization constant ")
997 valueIDMap[referenceOfOp.getReference()] = constID;
1003Serializer::processOp<spirv::EntryPointOp>(spirv::EntryPointOp op) {
1006 operands.push_back(
static_cast<uint32_t
>(op.getExecutionModel()));
1008 auto funcID = getFunctionID(op.getFn());
1010 return op.emitError(
"missing <id> for function ")
1012 <<
"; function needs to be defined before spirv.EntryPoint is "
1015 operands.push_back(funcID);
1020 if (
auto interface = op.getInterface()) {
1021 for (
auto var : interface.getValue()) {
1022 auto id = getVariableID(cast<FlatSymbolRefAttr>(var).getValue());
1024 return op.emitError(
1025 "referencing undefined global variable."
1026 "spirv.EntryPoint is at the end of spirv.module. All "
1027 "referenced variables should already be defined");
1029 operands.push_back(
id);
1038Serializer::processOp<spirv::ExecutionModeOp>(spirv::ExecutionModeOp op) {
1041 auto funcID = getFunctionID(op.getFn());
1043 return op.emitError(
"missing <id> for function ")
1045 <<
"; function needs to be serialized before ExecutionModeOp is "
1048 operands.push_back(funcID);
1050 operands.push_back(
static_cast<uint32_t
>(op.getExecutionMode()));
1053 auto values = op.getValues();
1055 for (
auto &intVal : values.getValue()) {
1056 operands.push_back(
static_cast<uint32_t
>(
1057 cast<IntegerAttr>(intVal).getValue().getZExtValue()));
1067Serializer::processOp<spirv::ExecutionModeIdOp>(spirv::ExecutionModeIdOp op) {
1070 uint32_t funcID = getFunctionID(op.getFn());
1072 return op.emitError(
"missing <id> for function ")
1074 <<
"; function needs to be serialized before ExecutionModeIdOp is "
1077 operands.push_back(funcID);
1078 operands.push_back(
static_cast<uint32_t
>(op.getExecutionMode()));
1080 for (
Attribute refVal : op.getValues().getValue()) {
1081 uint32_t
id = getSpecConstID(cast<FlatSymbolRefAttr>(refVal).getValue());
1083 return op.emitError(
"unknown <id> for specialization constant ")
1084 << cast<FlatSymbolRefAttr>(refVal).getValue();
1086 operands.push_back(
id);
1095Serializer::processOp<spirv::FunctionCallOp>(spirv::FunctionCallOp op) {
1096 auto funcName = op.getCallee();
1097 uint32_t resTypeID = 0;
1099 Type resultTy = op.getNumResults() ? *op.result_type_begin() : getVoidType();
1100 if (failed(processType(op.getLoc(), resultTy, resTypeID)))
1103 auto funcID = getOrCreateFunctionID(funcName);
1104 auto funcCallID = getNextID();
1107 for (
auto value : op.getArguments()) {
1108 auto valueID = getValueID(value);
1109 assert(valueID &&
"cannot find a value for spirv.FunctionCall");
1110 operands.push_back(valueID);
1113 if (!isa<NoneType>(resultTy))
1114 valueIDMap[op.getResult(0)] = funcCallID;
1117 for (
auto attr : op->getDiscardableAttrs())
1118 if (failed(processDecoration(op.getLoc(), funcCallID, attr)))
1125Serializer::processOp<spirv::CopyMemoryOp>(spirv::CopyMemoryOp op) {
1129 for (
Value operand : op->getOperands()) {
1130 auto id = getValueID(operand);
1131 assert(
id &&
"use before def!");
1132 operands.push_back(
id);
1135 StringAttr memoryAccess = op.getMemoryAccessAttrName();
1136 if (std::optional<spirv::MemoryAccess> value = op.getMemoryAccess())
1137 operands.push_back(
static_cast<uint32_t
>(*value));
1139 elidedAttrs.push_back(memoryAccess.strref());
1141 StringAttr alignment = op.getAlignmentAttrName();
1142 if (std::optional<uint32_t> value = op.getAlignment())
1143 operands.push_back(*value);
1145 elidedAttrs.push_back(alignment.strref());
1147 StringAttr sourceMemoryAccess = op.getSourceMemoryAccessAttrName();
1148 if (std::optional<spirv::MemoryAccess> value = op.getSourceMemoryAccess())
1149 operands.push_back(
static_cast<uint32_t
>(*value));
1151 elidedAttrs.push_back(sourceMemoryAccess.strref());
1153 StringAttr sourceAlignment = op.getSourceAlignmentAttrName();
1154 if (std::optional<uint32_t> value = op.getSourceAlignment())
1155 operands.push_back(*value);
1157 elidedAttrs.push_back(sourceAlignment.strref());
1158 if (failed(emitDebugLine(functionBody, op.getLoc())))
1165LogicalResult Serializer::processOp<spirv::GenericCastToPtrExplicitOp>(
1166 spirv::GenericCastToPtrExplicitOp op) {
1170 uint32_t resultTypeID = 0;
1171 uint32_t resultID = 0;
1172 resultTy = op->getResult(0).getType();
1173 if (failed(processType(loc, resultTy, resultTypeID)))
1175 operands.push_back(resultTypeID);
1177 resultID = getNextID();
1178 operands.push_back(resultID);
1179 valueIDMap[op->getResult(0)] = resultID;
1181 for (
Value operand : op->getOperands())
1182 operands.push_back(getValueID(operand));
1183 spirv::StorageClass resultStorage =
1184 cast<spirv::PointerType>(resultTy).getStorageClass();
1185 operands.push_back(
static_cast<uint32_t
>(resultStorage));
1193#define GET_SERIALIZATION_FNS
1194#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...
This class represents an instance of an SSA value in the MLIR system, representing a computable 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