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->getAttrOfType<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()
396 for (
auto attr : op->getAttrs()) {
398 auto isValidDecoration = mlir::spirv::symbolizeEnum<spirv::Decoration>(
399 llvm::convertToCamelFromSnakeCase(attr.getName().strref(),
401 if (isValidDecoration != std::nullopt) {
402 if (failed(processDecoration(op.getLoc(), funcID, attr))) {
410 functions.append(functionHeader.begin(), functionHeader.end());
411 functions.append(functionBody.begin(), functionBody.end());
412 functionHeader.clear();
413 functionBody.clear();
418uint32_t Serializer::encodeDebugStringInst(StringRef str) {
419 uint32_t stringID = debugStringIDMap.lookup(str);
424 SmallVector<uint32_t, 2> operands;
425 stringID = getNextID();
426 debugStringIDMap[str] = stringID;
427 operands.push_back(stringID);
434LogicalResult Serializer::encodeDebugInfoGraphInst(spirv::GraphARMOp op,
435 uint32_t &debugGraphID) {
439 uint32_t voidTypeID = 0;
440 if (failed(processType(op.getLoc(), getVoidType(), voidTypeID)))
444 encodeDebugStringInst(getDebugInfoStringFromLoc(op.getLoc()));
447 operands.push_back(voidTypeID);
448 debugGraphID = getNextID();
449 operands.push_back(debugGraphID);
450 uint32_t graphID = getOrCreateFunctionID(op.getName());
451 operands.push_back(graphID);
452 operands.push_back(stringID);
454 if (failed(encodeExtensionInstruction(
464Serializer::encodeDebugInfoOperationInst(uint32_t debugGraphID,
475 instructionIDs.push_back(getValueID(
result));
477 if (instructionIDs.empty())
480 uint32_t voidTypeID = 0;
481 if (failed(processType(ops[0]->getLoc(), getVoidType(), voidTypeID)))
485 encodeDebugStringInst(getDebugInfoStringFromLoc(ops[0]->getLoc()));
488 operands.push_back(voidTypeID);
489 operands.push_back(getNextID());
490 operands.push_back(debugGraphID);
491 operands.push_back(stringID);
492 operands.append(instructionIDs);
494 if (failed(encodeExtensionInstruction(
497 operands, graphsDebugInfo)))
503LogicalResult Serializer::encodeDebugInfoTensorInst(
Value tensor) {
507 uint32_t voidTypeID = 0;
508 if (failed(processType(
tensor.getLoc(), getVoidType(), voidTypeID)))
511 uint32_t tensorID = valueIDMap.lookup(
tensor);
516 encodeDebugStringInst(getDebugInfoStringFromLoc(
tensor.getLoc()));
519 operands.push_back(voidTypeID);
520 operands.push_back(getNextID());
521 operands.push_back(tensorID);
522 operands.push_back(stringID);
524 if (failed(encodeExtensionInstruction(
533LogicalResult Serializer::processGraphARMOp(spirv::GraphARMOp op) {
534 if (op.getNumResults() < 1) {
535 return op.emitError(
"cannot serialize graph with no return types");
538 LLVM_DEBUG(llvm::dbgs() <<
"-- start graph '" << op.getName() <<
"' --\n");
539 assert(functionHeader.empty() && functionBody.empty());
541 uint32_t funcID = getOrCreateFunctionID(op.getName());
542 uint32_t fnTypeID = 0;
544 if (failed(processType(op.getLoc(), op.getFunctionType(), fnTypeID)))
550 for (
auto [idx, arg] : llvm::enumerate(op.getArguments())) {
551 uint32_t argTypeID = 0;
552 SmallVector<uint32_t, 3> inputOperands;
554 if (
failed(processType(op.getLoc(), arg.getType(), argTypeID))) {
558 uint32_t argValueID = getNextID();
559 valueIDMap[arg] = argValueID;
561 auto attr = IntegerAttr::get(IntegerType::get(op.getContext(), 32), idx);
562 uint32_t indexID = prepareConstantInt(op.getLoc(), attr,
false);
564 inputOperands.push_back(argTypeID);
565 inputOperands.push_back(argValueID);
566 inputOperands.push_back(indexID);
571 if (
failed(encodeDebugInfoTensorInst(arg)))
575 if (
failed(processBlock(&op.front(),
true)))
578 &op.front(), [&](
Block *block) { return processBlock(block); },
583 LLVM_DEBUG(llvm::dbgs() <<
"-- completed graph '" << op.getName()
588 llvm::append_range(graphs, functionHeader);
589 llvm::append_range(graphs, functionBody);
590 functionHeader.clear();
591 functionBody.clear();
593 uint32_t debugGraphID = 0;
594 if (failed(encodeDebugInfoGraphInst(op, debugGraphID)))
597 for (
const auto &debugEntry : tosaOpsMap[funcID]) {
598 if (failed(encodeDebugInfoOperationInst(debugGraphID, debugEntry.second)))
606Serializer::processGraphEntryPointARMOp(spirv::GraphEntryPointARMOp op) {
607 SmallVector<uint32_t, 4> operands;
608 StringRef graph = op.getFn();
610 uint32_t graphID = getOrCreateFunctionID(graph);
611 operands.push_back(graphID);
616 if (
ArrayAttr interface = op.getInterface()) {
617 for (Attribute var : interface.getValue()) {
618 StringRef value = cast<FlatSymbolRefAttr>(var).getValue();
619 if (uint32_t
id = getVariableID(value)) {
620 operands.push_back(
id);
623 "referencing undefined global variable."
624 "spirv.GraphEntryPointARM is at the end of spirv.module. All "
625 "referenced variables should already be defined");
634Serializer::processGraphOutputsARMOp(spirv::GraphOutputsARMOp op) {
635 for (
auto [idx, value] : llvm::enumerate(op->getOperands())) {
636 SmallVector<uint32_t, 2> outputOperands;
638 Type resType = value.getType();
639 uint32_t resTypeID = 0;
640 if (failed(processType(op.getLoc(), resType, resTypeID))) {
644 uint32_t outputID = getValueID(value);
645 auto attr = IntegerAttr::get(IntegerType::get(op.getContext(), 32), idx);
646 uint32_t indexID = prepareConstantInt(op.getLoc(), attr,
false);
648 outputOperands.push_back(outputID);
649 outputOperands.push_back(indexID);
651 if (failed(encodeDebugInfoTensorInst(value)))
660LogicalResult Serializer::processVariableOp(spirv::VariableOp op) {
661 SmallVector<uint32_t, 4> operands;
662 SmallVector<StringRef, 2> elidedAttrs;
663 uint32_t resultID = 0;
664 uint32_t resultTypeID = 0;
665 if (
failed(processType(op.getLoc(), op.getType(), resultTypeID))) {
668 operands.push_back(resultTypeID);
669 resultID = getNextID();
670 valueIDMap[op.getResult()] = resultID;
671 operands.push_back(resultID);
675 static_cast<uint32_t
>(cast<spirv::StorageClassAttr>(attr).getValue()));
678 for (
auto arg : op.getODSOperands(0)) {
679 auto argID = getValueID(arg);
681 return emitError(op.getLoc(),
"operand 0 has a use before def");
683 operands.push_back(argID);
685 if (
failed(emitDebugLine(functionHeader, op.getLoc())))
688 for (
auto attr : op->getAttrs()) {
689 if (llvm::any_of(elidedAttrs, [&](StringRef elided) {
690 return attr.getName() == elided;
694 if (failed(processDecoration(op.getLoc(), resultID, attr))) {
702Serializer::processGlobalVariableOp(spirv::GlobalVariableOp varOp) {
704 uint32_t resultTypeID = 0;
705 SmallVector<StringRef, 4> elidedAttrs;
706 if (
failed(processType(varOp.getLoc(), varOp.getType(), resultTypeID))) {
710 elidedAttrs.push_back(
"type");
711 SmallVector<uint32_t, 4> operands;
712 operands.push_back(resultTypeID);
713 auto resultID = getNextID();
716 auto varName = varOp.getSymName();
718 if (
failed(processName(resultID, varName))) {
721 globalVarIDMap[varName] = resultID;
722 operands.push_back(resultID);
725 operands.push_back(
static_cast<uint32_t
>(varOp.storageClass()));
728 StringRef initAttrName = varOp.getInitializerAttrName().getValue();
729 if (std::optional<StringRef> initSymbolName = varOp.getInitializer()) {
730 uint32_t initializerID = 0;
733 varOp->getParentOp(), initRef.getAttr());
736 if (isa<spirv::GlobalVariableOp>(initOp))
737 initializerID = getVariableID(*initSymbolName);
739 initializerID = getSpecConstID(*initSymbolName);
743 "invalid usage of undefined variable as initializer");
745 operands.push_back(initializerID);
746 elidedAttrs.push_back(initAttrName);
749 if (failed(emitDebugLine(typesGlobalValues, varOp.getLoc())))
752 elidedAttrs.push_back(initAttrName);
755 for (
auto attr : varOp->getAttrs()) {
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 (
auto attr = op->getAttr(memoryAccess)) {
1116 static_cast<uint32_t
>(cast<spirv::MemoryAccessAttr>(attr).getValue()));
1119 elidedAttrs.push_back(memoryAccess.strref());
1121 StringAttr alignment = op.getAlignmentAttrName();
1122 if (
auto attr = op->getAttr(alignment)) {
1123 operands.push_back(
static_cast<uint32_t
>(
1124 cast<IntegerAttr>(attr).getValue().getZExtValue()));
1127 elidedAttrs.push_back(alignment.strref());
1129 StringAttr sourceMemoryAccess = op.getSourceMemoryAccessAttrName();
1130 if (
auto attr = op->getAttr(sourceMemoryAccess)) {
1132 static_cast<uint32_t
>(cast<spirv::MemoryAccessAttr>(attr).getValue()));
1135 elidedAttrs.push_back(sourceMemoryAccess.strref());
1137 StringAttr sourceAlignment = op.getSourceAlignmentAttrName();
1138 if (
auto attr = op->getAttr(sourceAlignment)) {
1139 operands.push_back(
static_cast<uint32_t
>(
1140 cast<IntegerAttr>(attr).getValue().getZExtValue()));
1143 elidedAttrs.push_back(sourceAlignment.strref());
1144 if (failed(emitDebugLine(functionBody, op.getLoc())))
1151LogicalResult Serializer::processOp<spirv::GenericCastToPtrExplicitOp>(
1152 spirv::GenericCastToPtrExplicitOp op) {
1156 uint32_t resultTypeID = 0;
1157 uint32_t resultID = 0;
1158 resultTy = op->getResult(0).getType();
1159 if (failed(processType(loc, resultTy, resultTypeID)))
1161 operands.push_back(resultTypeID);
1163 resultID = getNextID();
1164 operands.push_back(resultID);
1165 valueIDMap[op->getResult(0)] = resultID;
1167 for (
Value operand : op->getOperands())
1168 operands.push_back(getValueID(operand));
1169 spirv::StorageClass resultStorage =
1170 cast<spirv::PointerType>(resultTy).getStorageClass();
1171 operands.push_back(
static_cast<uint32_t
>(resultStorage));
1179#define GET_SERIALIZATION_FNS
1180#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.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
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