20#include "llvm/ADT/DepthFirstIterator.h"
21#include "llvm/ADT/StringExtras.h"
22#include "llvm/Support/Debug.h"
23#include "llvm/Support/FormatVariadic.h"
25#define DEBUG_TYPE "spirv-serialization"
34std::string getDebugInfoStringFromLoc(
Location loc) {
35 if (
auto fileLineCol = dyn_cast<FileLineColLoc>(loc)) {
36 return llvm::formatv(
"{0}:{1}:{2}", fileLineCol.getFilename(),
37 fileLineCol.getLine(), fileLineCol.getColumn());
39 if (
auto nameLoc = dyn_cast<NameLoc>(loc)) {
40 return nameLoc.getName().str();
42 if (
auto fusedLoc = dyn_cast<FusedLoc>(loc)) {
44 llvm::raw_string_ostream os(
result);
46 map_range(fusedLoc.getLocations(), getDebugInfoStringFromLoc), os,
";");
71 bool skipHeader =
false,
BlockRange skipBlocks = {}) {
72 llvm::df_iterator_default_set<Block *, 4> doneBlocks;
73 doneBlocks.insert(skipBlocks.begin(), skipBlocks.end());
75 for (
Block *block : llvm::depth_first_ext(headerBlock, doneBlocks)) {
76 if (skipHeader && block == headerBlock)
78 if (
failed(blockHandler(block)))
86LogicalResult Serializer::processConstantOp(spirv::ConstantOp op) {
88 prepareConstant(op.getLoc(), op.getType(), op.getValue())) {
89 valueIDMap[op.getResult()] = resultID;
90 if (isa<spirv::TensorArmType>(op.getType()) &&
91 failed(encodeDebugInfoTensorInst(op.getResult())))
98LogicalResult Serializer::processConstantCompositeReplicateOp(
99 spirv::EXTConstantCompositeReplicateOp op) {
100 if (uint32_t resultID = prepareConstantCompositeReplicate(
101 op.getLoc(), op.getType(), op.getValue())) {
102 valueIDMap[op.getResult()] = resultID;
108LogicalResult Serializer::processSpecConstantOp(spirv::SpecConstantOp op) {
109 if (
auto resultID = prepareConstantScalar(op.getLoc(), op.getDefaultValue(),
112 if (
auto specID = op->getDiscardableAttrOfType<IntegerAttr>(
"spec_id")) {
113 auto val =
static_cast<uint32_t
>(specID.getInt());
114 if (failed(emitDecoration(resultID, spirv::Decoration::SpecId, {val})))
118 specConstIDMap[op.getSymName()] = resultID;
119 return processName(resultID, op.getSymName());
125Serializer::processSpecConstantCompositeOp(spirv::SpecConstantCompositeOp op) {
127 if (failed(processType(op.getLoc(), op.getType(), typeID))) {
131 auto resultID = getNextID();
134 operands.push_back(typeID);
135 operands.push_back(resultID);
137 auto constituents = op.getConstituents();
139 for (
auto index : llvm::seq<uint32_t>(0, constituents.size())) {
140 auto constituent = dyn_cast<FlatSymbolRefAttr>(constituents[
index]);
142 auto constituentName = constituent.getValue();
143 auto constituentID = getSpecConstID(constituentName);
145 if (!constituentID) {
146 return op.emitError(
"unknown result <id> for specialization constant ")
150 operands.push_back(constituentID);
153 encodeInstructionWithContinuationInto(
154 typesGlobalValues, spirv::Opcode::OpSpecConstantComposite, operands);
155 specConstIDMap[op.getSymName()] = resultID;
157 return processName(resultID, op.getSymName());
160LogicalResult Serializer::processSpecConstantCompositeReplicateOp(
161 spirv::EXTSpecConstantCompositeReplicateOp op) {
163 if (
failed(processType(op.getLoc(), op.getType(), typeID))) {
167 auto constituent = dyn_cast<FlatSymbolRefAttr>(op.getConstituent());
170 "expected flat symbol reference for constituent instead of ")
171 << op.getConstituent();
173 StringRef constituentName = constituent.getValue();
174 uint32_t constituentID = getSpecConstID(constituentName);
175 if (!constituentID) {
176 return op.emitError(
"unknown result <id> for replicated spec constant ")
180 uint32_t resultID = getNextID();
181 uint32_t operands[] = {typeID, resultID, constituentID};
184 spirv::Opcode::OpSpecConstantCompositeReplicateEXT,
187 specConstIDMap[op.getSymName()] = resultID;
189 return processName(resultID, op.getSymName());
193Serializer::processSpecConstantOperationOp(spirv::SpecConstantOperationOp op) {
195 if (
failed(processType(op.getLoc(), op.getType(), typeID))) {
199 auto resultID = getNextID();
201 SmallVector<uint32_t, 8> operands;
202 operands.push_back(typeID);
203 operands.push_back(resultID);
205 Block &block = op.getRegion().getBlocks().front();
208 std::string enclosedOpName;
209 llvm::raw_string_ostream rss(enclosedOpName);
211 auto enclosedOpcode = spirv::symbolizeOpcode(enclosedOpName);
213 if (!enclosedOpcode) {
214 op.emitError(
"Couldn't find op code for op ")
219 operands.push_back(
static_cast<uint32_t
>(*enclosedOpcode));
223 uint32_t
id = getValueID(operand);
224 assert(
id &&
"use before def!");
225 operands.push_back(
id);
230 valueIDMap[op.getResult()] = resultID;
236Serializer::processGraphConstantARMOp(spirv::GraphConstantARMOp op) {
237 if (uint32_t resultID = prepareGraphConstantId(op.getLoc(), op.getType(),
238 op.getGraphConstantIdAttr())) {
239 valueIDMap[op.getResult()] = resultID;
245LogicalResult Serializer::processUndefOp(spirv::UndefOp op) {
246 auto undefType = op.getType();
247 auto &
id = undefValIDMap[undefType];
251 if (failed(processType(op.getLoc(), undefType, typeID)))
256 valueIDMap[op.getResult()] = id;
260LogicalResult Serializer::processFuncParameter(spirv::FuncOp op) {
261 for (
auto [idx, arg] : llvm::enumerate(op.getArguments())) {
262 uint32_t argTypeID = 0;
263 if (failed(processType(op.getLoc(), arg.getType(), argTypeID))) {
266 auto argValueID = getNextID();
269 auto funcOp = cast<FunctionOpInterface>(*op);
270 for (
auto argAttr : funcOp.getArgAttrs(idx)) {
271 if (argAttr.getName() != DecorationAttr::name)
274 if (
auto decAttr = dyn_cast<DecorationAttr>(argAttr.getValue())) {
275 if (
failed(processDecorationAttr(op->getLoc(), argValueID,
276 decAttr.getValue(), decAttr)))
281 valueIDMap[arg] = argValueID;
283 {argTypeID, argValueID});
288LogicalResult Serializer::processFuncOp(spirv::FuncOp op) {
289 LLVM_DEBUG(llvm::dbgs() <<
"-- start function '" << op.getName() <<
"' --\n");
290 assert(functionHeader.empty() && functionBody.empty());
292 uint32_t fnTypeID = 0;
294 if (
failed(processType(op.getLoc(), op.getFunctionType(), fnTypeID)))
298 SmallVector<uint32_t, 4> operands;
299 uint32_t resTypeID = 0;
300 auto resultTypes = op.getFunctionType().getResults();
301 if (resultTypes.size() > 1) {
302 return op.emitError(
"cannot serialize function with multiple return types");
304 if (failed(processType(op.getLoc(),
305 (resultTypes.empty() ? getVoidType() : resultTypes[0]),
309 operands.push_back(resTypeID);
310 auto funcID = getOrCreateFunctionID(op.getName());
311 operands.push_back(funcID);
312 operands.push_back(
static_cast<uint32_t
>(op.getFunctionControl()));
313 operands.push_back(fnTypeID);
317 if (failed(processName(funcID, op.getName()))) {
322 auto linkageAttr = op.getLinkageAttributes();
323 auto hasImportLinkage =
324 linkageAttr && (linkageAttr.value().getLinkageType().getValue() ==
325 spirv::LinkageType::Import);
326 if (op.isExternal() && !hasImportLinkage) {
328 "'spirv.module' cannot contain external functions "
329 "without 'Import' linkage_attributes (LinkageAttributes)");
331 if (op.isExternal() && hasImportLinkage) {
341 if (
failed(processFuncParameter(op)))
348 for (Value arg : op.getArguments())
349 valueIDMap.erase(arg);
356 if (
failed(processFuncParameter(op)))
368 {getOrCreateBlockID(&op.front())});
369 if (failed(processBlock(&op.front(),
true)))
372 &op.front(), [&](
Block *block) { return processBlock(block); },
379 for (
const auto &deferredValue : deferredPhiValues) {
380 Value value = deferredValue.first;
381 uint32_t
id = getValueID(value);
382 LLVM_DEBUG(llvm::dbgs() <<
"[phi] fix reference of value " << value
383 <<
" to id = " <<
id <<
'\n');
384 assert(
id &&
"OpPhi references undefined value!");
385 for (
size_t offset : deferredValue.second)
386 functionBody[offset] = id;
388 deferredPhiValues.clear();
390 LLVM_DEBUG(llvm::dbgs() <<
"-- completed function '" << op.getName()
397 op->getName().populateInherentAttrs(op, attrs);
398 for (
auto attr : attrs) {
400 auto isValidDecoration = mlir::spirv::symbolizeEnum<spirv::Decoration>(
401 llvm::convertToCamelFromSnakeCase(attr.getName().strref(),
403 if (isValidDecoration != std::nullopt) {
404 if (failed(processDecoration(op.getLoc(), funcID, attr))) {
412 functions.append(functionHeader.begin(), functionHeader.end());
413 functions.append(functionBody.begin(), functionBody.end());
414 functionHeader.clear();
415 functionBody.clear();
420uint32_t Serializer::encodeDebugStringInst(StringRef str) {
421 uint32_t stringID = debugStringIDMap.lookup(str);
426 SmallVector<uint32_t, 2> operands;
427 stringID = getNextID();
428 debugStringIDMap[str] = stringID;
429 operands.push_back(stringID);
436LogicalResult Serializer::encodeDebugInfoGraphInst(spirv::GraphARMOp op,
437 uint32_t &debugGraphID) {
441 uint32_t voidTypeID = 0;
442 if (failed(processType(op.getLoc(), getVoidType(), voidTypeID)))
446 encodeDebugStringInst(getDebugInfoStringFromLoc(op.getLoc()));
449 operands.push_back(voidTypeID);
450 debugGraphID = getNextID();
451 operands.push_back(debugGraphID);
452 uint32_t graphID = getOrCreateFunctionID(op.getName());
453 operands.push_back(graphID);
454 operands.push_back(stringID);
456 if (failed(encodeExtensionInstruction(
466Serializer::encodeDebugInfoOperationInst(uint32_t debugGraphID,
477 instructionIDs.push_back(getValueID(
result));
479 if (instructionIDs.empty())
482 uint32_t voidTypeID = 0;
483 if (failed(processType(ops[0]->getLoc(), getVoidType(), voidTypeID)))
487 encodeDebugStringInst(getDebugInfoStringFromLoc(ops[0]->getLoc()));
490 operands.push_back(voidTypeID);
491 operands.push_back(getNextID());
492 operands.push_back(debugGraphID);
493 operands.push_back(stringID);
494 operands.append(instructionIDs);
496 if (failed(encodeExtensionInstruction(
499 operands, graphsDebugInfo)))
505LogicalResult Serializer::encodeDebugInfoTensorInst(
Value tensor) {
509 uint32_t voidTypeID = 0;
510 if (failed(processType(
tensor.getLoc(), getVoidType(), voidTypeID)))
513 uint32_t tensorID = valueIDMap.lookup(
tensor);
518 encodeDebugStringInst(getDebugInfoStringFromLoc(
tensor.getLoc()));
521 operands.push_back(voidTypeID);
522 operands.push_back(getNextID());
523 operands.push_back(tensorID);
524 operands.push_back(stringID);
526 if (failed(encodeExtensionInstruction(
535LogicalResult Serializer::processGraphARMOp(spirv::GraphARMOp op) {
536 if (op.getNumResults() < 1) {
537 return op.emitError(
"cannot serialize graph with no return types");
540 LLVM_DEBUG(llvm::dbgs() <<
"-- start graph '" << op.getName() <<
"' --\n");
541 assert(functionHeader.empty() && functionBody.empty());
543 uint32_t funcID = getOrCreateFunctionID(op.getName());
544 uint32_t fnTypeID = 0;
546 if (failed(processType(op.getLoc(), op.getFunctionType(), fnTypeID)))
552 for (
auto [idx, arg] : llvm::enumerate(op.getArguments())) {
553 uint32_t argTypeID = 0;
554 SmallVector<uint32_t, 3> inputOperands;
556 if (
failed(processType(op.getLoc(), arg.getType(), argTypeID))) {
560 uint32_t argValueID = getNextID();
561 valueIDMap[arg] = argValueID;
563 auto attr = IntegerAttr::get(IntegerType::get(op.getContext(), 32), idx);
564 uint32_t indexID = prepareConstantInt(op.getLoc(), attr,
false);
566 inputOperands.push_back(argTypeID);
567 inputOperands.push_back(argValueID);
568 inputOperands.push_back(indexID);
573 if (
failed(encodeDebugInfoTensorInst(arg)))
577 if (
failed(processBlock(&op.front(),
true)))
580 &op.front(), [&](
Block *block) { return processBlock(block); },
585 LLVM_DEBUG(llvm::dbgs() <<
"-- completed graph '" << op.getName()
590 llvm::append_range(graphs, functionHeader);
591 llvm::append_range(graphs, functionBody);
592 functionHeader.clear();
593 functionBody.clear();
595 uint32_t debugGraphID = 0;
596 if (failed(encodeDebugInfoGraphInst(op, debugGraphID)))
599 for (
const auto &debugEntry : tosaOpsMap[funcID]) {
600 if (failed(encodeDebugInfoOperationInst(debugGraphID, debugEntry.second)))
608Serializer::processGraphEntryPointARMOp(spirv::GraphEntryPointARMOp op) {
609 SmallVector<uint32_t, 4> operands;
610 StringRef graph = op.getFn();
612 uint32_t graphID = getOrCreateFunctionID(graph);
613 operands.push_back(graphID);
618 if (
ArrayAttr interface = op.getInterface()) {
619 for (Attribute var : interface.getValue()) {
620 StringRef value = cast<FlatSymbolRefAttr>(var).getValue();
621 if (uint32_t
id = getVariableID(value)) {
622 operands.push_back(
id);
625 "referencing undefined global variable."
626 "spirv.GraphEntryPointARM is at the end of spirv.module. All "
627 "referenced variables should already be defined");
636Serializer::processGraphOutputsARMOp(spirv::GraphOutputsARMOp op) {
637 for (
auto [idx, value] : llvm::enumerate(op->getOperands())) {
640 Type resType = value.getType();
641 uint32_t resTypeID = 0;
642 if (failed(processType(op.getLoc(), resType, resTypeID))) {
646 uint32_t outputID = getValueID(value);
647 auto attr = IntegerAttr::get(IntegerType::get(op.getContext(), 32), idx);
648 uint32_t indexID = prepareConstantInt(op.getLoc(), attr,
false);
650 outputOperands.push_back(outputID);
651 outputOperands.push_back(indexID);
653 if (failed(encodeDebugInfoTensorInst(value)))
662LogicalResult Serializer::processVariableOp(spirv::VariableOp op) {
665 uint32_t resultID = 0;
666 uint32_t resultTypeID = 0;
667 if (failed(processType(op.getLoc(), op.getType(), resultTypeID))) {
670 operands.push_back(resultTypeID);
671 resultID = getNextID();
672 valueIDMap[op.getResult()] = resultID;
673 operands.push_back(resultID);
674 operands.push_back(
static_cast<uint32_t
>(op.getStorageClass()));
676 for (
auto arg : op.getODSOperands(0)) {
677 auto argID = getValueID(arg);
679 return emitError(op.getLoc(),
"operand 0 has a use before def");
681 operands.push_back(argID);
683 if (
failed(emitDebugLine(functionHeader, op.getLoc())))
686 for (
auto attr : op->getDiscardableAttrDictionary().getValue()) {
687 if (llvm::any_of(elidedAttrs, [&](StringRef elided) {
688 return attr.getName() == elided;
692 if (failed(processDecoration(op.getLoc(), resultID, attr))) {
700Serializer::processGlobalVariableOp(spirv::GlobalVariableOp varOp) {
702 uint32_t resultTypeID = 0;
703 SmallVector<StringRef, 4> elidedAttrs;
704 if (
failed(processType(varOp.getLoc(), varOp.getType(), resultTypeID))) {
708 elidedAttrs.push_back(
"type");
709 SmallVector<uint32_t, 4> operands;
710 operands.push_back(resultTypeID);
711 auto resultID = getNextID();
714 auto varName = varOp.getSymName();
716 if (
failed(processName(resultID, varName))) {
719 globalVarIDMap[varName] = resultID;
720 operands.push_back(resultID);
723 operands.push_back(
static_cast<uint32_t
>(varOp.storageClass()));
726 StringRef initAttrName = varOp.getInitializerAttrName().getValue();
727 if (std::optional<StringRef> initSymbolName = varOp.getInitializer()) {
728 uint32_t initializerID = 0;
729 FlatSymbolRefAttr initRef = varOp.getInitializerAttr();
734 if (isa<spirv::GlobalVariableOp>(initOp))
735 initializerID = getVariableID(*initSymbolName);
737 initializerID = getSpecConstID(*initSymbolName);
741 "invalid usage of undefined variable as initializer");
743 operands.push_back(initializerID);
744 elidedAttrs.push_back(initAttrName);
747 if (failed(emitDebugLine(typesGlobalValues, varOp.getLoc())))
750 elidedAttrs.push_back(initAttrName);
753 NamedAttrList attrs(varOp->getDiscardableAttrDictionary().getValue());
754 varOp->getName().populateInherentAttrs(varOp, attrs);
755 for (
auto attr : attrs) {
756 if (llvm::any_of(elidedAttrs, [&](StringRef elided) {
757 return attr.getName() == elided;
761 if (
failed(processDecoration(varOp.getLoc(), resultID, attr))) {
768LogicalResult Serializer::processSelectionOp(spirv::SelectionOp selectionOp) {
771 auto &body = selectionOp.getBody();
772 for (
Block &block : body)
773 getOrCreateBlockID(&block);
775 auto *headerBlock = selectionOp.getHeaderBlock();
776 auto *mergeBlock = selectionOp.getMergeBlock();
777 auto headerID = getBlockID(headerBlock);
778 auto mergeID = getBlockID(mergeBlock);
779 auto loc = selectionOp.getLoc();
785 auto mergeOp = cast<spirv::MergeOp>(mergeBlock->back());
786 assert(selectionOp.getNumResults() == mergeOp.getNumOperands());
787 for (
unsigned i = 0, e = selectionOp.getNumResults(); i != e; ++i)
788 selectionOp.getResult(i).replaceAllUsesWith(mergeOp.getOperand(i));
800 auto emitSelectionMerge = [&]() {
801 if (failed(emitDebugLine(functionBody, loc)))
803 lastProcessedWasMergeInst =
true;
805 functionBody, spirv::Opcode::OpSelectionMerge,
806 {mergeID,
static_cast<uint32_t
>(selectionOp.getSelectionControl())});
810 processBlock(headerBlock,
false, emitSelectionMerge)))
817 headerBlock, [&](
Block *block) {
return processBlock(block); },
818 true, {mergeBlock})))
829 if (
failed(emitPhiForBlockArguments(mergeBlock)))
832 LLVM_DEBUG(llvm::dbgs() <<
"done merge ");
833 LLVM_DEBUG(printBlock(mergeBlock, llvm::dbgs()));
834 LLVM_DEBUG(llvm::dbgs() <<
"\n");
838LogicalResult Serializer::processLoopOp(spirv::LoopOp loopOp) {
842 auto &body = loopOp.getBody();
843 for (
Block &block : llvm::drop_begin(body))
844 getOrCreateBlockID(&block);
846 auto *headerBlock = loopOp.getHeaderBlock();
847 auto *continueBlock = loopOp.getContinueBlock();
848 auto *mergeBlock = loopOp.getMergeBlock();
849 auto headerID = getBlockID(headerBlock);
850 auto continueID = getBlockID(continueBlock);
851 auto mergeID = getBlockID(mergeBlock);
852 auto loc = loopOp.getLoc();
856 auto mergeOp = cast<spirv::MergeOp>(mergeBlock->back());
857 assert(loopOp.getNumResults() == mergeOp.getNumOperands());
858 for (
unsigned i = 0, e = loopOp.getNumResults(); i != e; ++i)
859 loopOp.getResult(i).replaceAllUsesWith(mergeOp.getOperand(i));
875 auto emitLoopMerge = [&]() {
876 if (failed(emitDebugLine(functionBody, loc)))
878 lastProcessedWasMergeInst =
true;
880 functionBody, spirv::Opcode::OpLoopMerge,
881 {mergeID, continueID,
static_cast<uint32_t
>(loopOp.getLoopControl())});
884 if (
failed(processBlock(headerBlock,
false, emitLoopMerge)))
891 headerBlock, [&](
Block *block) {
return processBlock(block); },
892 true, {continueBlock, mergeBlock})))
896 if (failed(processBlock(continueBlock)))
904 LLVM_DEBUG(llvm::dbgs() <<
"done merge ");
905 LLVM_DEBUG(
printBlock(mergeBlock, llvm::dbgs()));
906 LLVM_DEBUG(llvm::dbgs() <<
"\n");
910LogicalResult Serializer::processBranchConditionalOp(
911 spirv::BranchConditionalOp condBranchOp) {
912 auto conditionID = getValueID(condBranchOp.getCondition());
913 auto trueLabelID = getOrCreateBlockID(condBranchOp.getTrueBlock());
914 auto falseLabelID = getOrCreateBlockID(condBranchOp.getFalseBlock());
917 if (
auto weights = condBranchOp.getBranchWeights()) {
918 for (
auto val : weights->getValue())
919 arguments.push_back(cast<IntegerAttr>(val).getInt());
922 if (failed(emitDebugLine(functionBody, condBranchOp.getLoc())))
929LogicalResult Serializer::processBranchOp(spirv::BranchOp branchOp) {
930 if (failed(emitDebugLine(functionBody, branchOp.getLoc())))
933 {getOrCreateBlockID(branchOp.getTarget())});
937LogicalResult Serializer::processSwitchOp(spirv::SwitchOp switchOp) {
938 uint32_t selectorID = getValueID(switchOp.getSelector());
939 uint32_t defaultLabelID = getOrCreateBlockID(switchOp.getDefaultTarget());
942 std::optional<mlir::DenseIntElementsAttr> literals = switchOp.getLiterals();
945 for (
auto [literal,
target] : llvm::zip_equal(*literals, targets)) {
946 arguments.push_back(literal.getLimitedValue());
947 uint32_t targetLabelID = getOrCreateBlockID(
target);
948 arguments.push_back(targetLabelID);
952 if (failed(emitDebugLine(functionBody, switchOp.getLoc())))
958LogicalResult Serializer::processAddressOfOp(spirv::AddressOfOp addressOfOp) {
959 auto varName = addressOfOp.getVariable();
960 auto variableID = getVariableID(varName);
962 return addressOfOp.emitError(
"unknown result <id> for variable ")
965 valueIDMap[addressOfOp.getPointer()] = variableID;
970Serializer::processReferenceOfOp(spirv::ReferenceOfOp referenceOfOp) {
971 auto constName = referenceOfOp.getSpecConst();
972 auto constID = getSpecConstID(constName);
974 return referenceOfOp.emitError(
975 "unknown result <id> for specialization constant ")
978 valueIDMap[referenceOfOp.getReference()] = constID;
984Serializer::processOp<spirv::EntryPointOp>(spirv::EntryPointOp op) {
987 operands.push_back(
static_cast<uint32_t
>(op.getExecutionModel()));
989 auto funcID = getFunctionID(op.getFn());
991 return op.emitError(
"missing <id> for function ")
993 <<
"; function needs to be defined before spirv.EntryPoint is "
996 operands.push_back(funcID);
1001 if (
auto interface = op.getInterface()) {
1002 for (
auto var : interface.getValue()) {
1003 auto id = getVariableID(cast<FlatSymbolRefAttr>(var).getValue());
1005 return op.emitError(
1006 "referencing undefined global variable."
1007 "spirv.EntryPoint is at the end of spirv.module. All "
1008 "referenced variables should already be defined");
1010 operands.push_back(
id);
1019Serializer::processOp<spirv::ExecutionModeOp>(spirv::ExecutionModeOp op) {
1022 auto funcID = getFunctionID(op.getFn());
1024 return op.emitError(
"missing <id> for function ")
1026 <<
"; function needs to be serialized before ExecutionModeOp is "
1029 operands.push_back(funcID);
1031 operands.push_back(
static_cast<uint32_t
>(op.getExecutionMode()));
1034 auto values = op.getValues();
1036 for (
auto &intVal : values.getValue()) {
1037 operands.push_back(
static_cast<uint32_t
>(
1038 cast<IntegerAttr>(intVal).getValue().getZExtValue()));
1048Serializer::processOp<spirv::ExecutionModeIdOp>(spirv::ExecutionModeIdOp op) {
1051 uint32_t funcID = getFunctionID(op.getFn());
1053 return op.emitError(
"missing <id> for function ")
1055 <<
"; function needs to be serialized before ExecutionModeIdOp is "
1058 operands.push_back(funcID);
1059 operands.push_back(
static_cast<uint32_t
>(op.getExecutionMode()));
1062 uint32_t
id = getSpecConstID(cast<FlatSymbolRefAttr>(refVal).getValue());
1064 return op.emitError(
"unknown <id> for specialization constant ")
1065 << cast<FlatSymbolRefAttr>(refVal).getValue();
1067 operands.push_back(
id);
1076Serializer::processOp<spirv::FunctionCallOp>(spirv::FunctionCallOp op) {
1077 auto funcName = op.getCallee();
1078 uint32_t resTypeID = 0;
1080 Type resultTy = op.getNumResults() ? *op.result_type_begin() : getVoidType();
1081 if (failed(processType(op.getLoc(), resultTy, resTypeID)))
1084 auto funcID = getOrCreateFunctionID(funcName);
1085 auto funcCallID = getNextID();
1088 for (
auto value : op.getArguments()) {
1089 auto valueID = getValueID(value);
1090 assert(valueID &&
"cannot find a value for spirv.FunctionCall");
1091 operands.push_back(valueID);
1094 if (!isa<NoneType>(resultTy))
1095 valueIDMap[op.getResult(0)] = funcCallID;
1103Serializer::processOp<spirv::CopyMemoryOp>(spirv::CopyMemoryOp op) {
1107 for (
Value operand : op->getOperands()) {
1108 auto id = getValueID(operand);
1109 assert(
id &&
"use before def!");
1110 operands.push_back(
id);
1113 StringAttr memoryAccess = op.getMemoryAccessAttrName();
1114 if (std::optional<spirv::MemoryAccess> value = op.getMemoryAccess())
1115 operands.push_back(
static_cast<uint32_t
>(*value));
1117 elidedAttrs.push_back(memoryAccess.strref());
1119 StringAttr alignment = op.getAlignmentAttrName();
1120 if (std::optional<uint32_t> value = op.getAlignment())
1121 operands.push_back(*value);
1123 elidedAttrs.push_back(alignment.strref());
1125 StringAttr sourceMemoryAccess = op.getSourceMemoryAccessAttrName();
1126 if (std::optional<spirv::MemoryAccess> value = op.getSourceMemoryAccess())
1127 operands.push_back(
static_cast<uint32_t
>(*value));
1129 elidedAttrs.push_back(sourceMemoryAccess.strref());
1131 StringAttr sourceAlignment = op.getSourceAlignmentAttrName();
1132 if (std::optional<uint32_t> value = op.getSourceAlignment())
1133 operands.push_back(*value);
1135 elidedAttrs.push_back(sourceAlignment.strref());
1136 if (failed(emitDebugLine(functionBody, op.getLoc())))
1143LogicalResult Serializer::processOp<spirv::GenericCastToPtrExplicitOp>(
1144 spirv::GenericCastToPtrExplicitOp op) {
1148 uint32_t resultTypeID = 0;
1149 uint32_t resultID = 0;
1150 resultTy = op->getResult(0).getType();
1151 if (failed(processType(loc, resultTy, resultTypeID)))
1153 operands.push_back(resultTypeID);
1155 resultID = getNextID();
1156 operands.push_back(resultID);
1157 valueIDMap[op->getResult(0)] = resultID;
1159 for (
Value operand : op->getOperands())
1160 operands.push_back(getValueID(operand));
1161 spirv::StorageClass resultStorage =
1162 cast<spirv::PointerType>(resultTy).getStorageClass();
1163 operands.push_back(
static_cast<uint32_t
>(resultStorage));
1171#define GET_SERIALIZATION_FNS
1172#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()
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 StringRef getSymbolAttrName()
Return the name of the attribute used for symbol names.
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.
constexpr StringRef attributeName()
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