19 #include "llvm/ADT/DepthFirstIterator.h"
20 #include "llvm/ADT/StringExtras.h"
21 #include "llvm/Support/Debug.h"
23 #define DEBUG_TYPE "spirv-serialization"
45 bool skipHeader =
false,
BlockRange skipBlocks = {}) {
46 llvm::df_iterator_default_set<Block *, 4> doneBlocks;
47 doneBlocks.insert(skipBlocks.begin(), skipBlocks.end());
49 for (
Block *block : llvm::depth_first_ext(headerBlock, doneBlocks)) {
50 if (skipHeader && block == headerBlock)
52 if (
failed(blockHandler(block)))
60 LogicalResult Serializer::processConstantOp(spirv::ConstantOp op) {
62 prepareConstant(op.getLoc(), op.getType(), op.getValue())) {
63 valueIDMap[op.getResult()] = resultID;
69 LogicalResult Serializer::processConstantCompositeReplicateOp(
70 spirv::EXTConstantCompositeReplicateOp op) {
71 if (uint32_t resultID = prepareConstantCompositeReplicate(
72 op.getLoc(), op.getType(), op.getValue())) {
73 valueIDMap[op.getResult()] = resultID;
79 LogicalResult Serializer::processSpecConstantOp(spirv::SpecConstantOp op) {
80 if (
auto resultID = prepareConstantScalar(op.getLoc(), op.getDefaultValue(),
83 if (
auto specID = op->getAttrOfType<IntegerAttr>(
"spec_id")) {
84 auto val =
static_cast<uint32_t
>(specID.getInt());
85 if (
failed(emitDecoration(resultID, spirv::Decoration::SpecId, {val})))
89 specConstIDMap[op.getSymName()] = resultID;
90 return processName(resultID, op.getSymName());
96 Serializer::processSpecConstantCompositeOp(spirv::SpecConstantCompositeOp op) {
98 if (
failed(processType(op.getLoc(), op.getType(), typeID))) {
102 auto resultID = getNextID();
105 operands.push_back(typeID);
106 operands.push_back(resultID);
108 auto constituents = op.getConstituents();
110 for (
auto index : llvm::seq<uint32_t>(0, constituents.size())) {
111 auto constituent = dyn_cast<FlatSymbolRefAttr>(constituents[index]);
113 auto constituentName = constituent.getValue();
114 auto constituentID = getSpecConstID(constituentName);
116 if (!constituentID) {
117 return op.emitError(
"unknown result <id> for specialization constant ")
121 operands.push_back(constituentID);
125 spirv::Opcode::OpSpecConstantComposite, operands);
126 specConstIDMap[op.getSymName()] = resultID;
128 return processName(resultID, op.getSymName());
131 LogicalResult Serializer::processSpecConstantCompositeReplicateOp(
132 spirv::EXTSpecConstantCompositeReplicateOp op) {
134 if (
failed(processType(op.getLoc(), op.getType(), typeID))) {
138 auto constituent = dyn_cast<FlatSymbolRefAttr>(op.getConstituent());
141 "expected flat symbol reference for constituent instead of ")
142 << op.getConstituent();
144 StringRef constituentName = constituent.getValue();
145 uint32_t constituentID = getSpecConstID(constituentName);
146 if (!constituentID) {
147 return op.emitError(
"unknown result <id> for replicated spec constant ")
151 uint32_t resultID = getNextID();
152 uint32_t operands[] = {typeID, resultID, constituentID};
155 spirv::Opcode::OpSpecConstantCompositeReplicateEXT,
158 specConstIDMap[op.getSymName()] = resultID;
160 return processName(resultID, op.getSymName());
164 Serializer::processSpecConstantOperationOp(spirv::SpecConstantOperationOp op) {
166 if (
failed(processType(op.getLoc(), op.getType(), typeID))) {
170 auto resultID = getNextID();
173 operands.push_back(typeID);
174 operands.push_back(resultID);
176 Block &block = op.getRegion().getBlocks().
front();
179 std::string enclosedOpName;
180 llvm::raw_string_ostream rss(enclosedOpName);
182 auto enclosedOpcode = spirv::symbolizeOpcode(enclosedOpName);
184 if (!enclosedOpcode) {
185 op.emitError(
"Couldn't find op code for op ")
190 operands.push_back(
static_cast<uint32_t
>(*enclosedOpcode));
194 uint32_t
id = getValueID(operand);
195 assert(
id &&
"use before def!");
196 operands.push_back(
id);
201 valueIDMap[op.getResult()] = resultID;
207 Serializer::processGraphConstantARMOp(spirv::GraphConstantARMOp op) {
208 if (uint32_t resultID = prepareGraphConstantId(op.getLoc(), op.getType(),
209 op.getGraphConstantIdAttr())) {
210 valueIDMap[op.getResult()] = resultID;
216 LogicalResult Serializer::processUndefOp(spirv::UndefOp op) {
217 auto undefType = op.getType();
218 auto &
id = undefValIDMap[undefType];
222 if (
failed(processType(op.getLoc(), undefType, typeID)))
227 valueIDMap[op.getResult()] = id;
231 LogicalResult Serializer::processFuncParameter(spirv::FuncOp op) {
233 uint32_t argTypeID = 0;
234 if (
failed(processType(op.getLoc(), arg.getType(), argTypeID))) {
237 auto argValueID = getNextID();
240 auto funcOp = cast<FunctionOpInterface>(*op);
241 for (
auto argAttr : funcOp.getArgAttrs(idx)) {
242 if (argAttr.getName() != DecorationAttr::name)
245 if (
auto decAttr = dyn_cast<DecorationAttr>(argAttr.getValue())) {
246 if (
failed(processDecorationAttr(op->getLoc(), argValueID,
247 decAttr.getValue(), decAttr)))
252 valueIDMap[arg] = argValueID;
254 {argTypeID, argValueID});
259 LogicalResult Serializer::processFuncOp(spirv::FuncOp op) {
260 LLVM_DEBUG(llvm::dbgs() <<
"-- start function '" << op.getName() <<
"' --\n");
261 assert(functionHeader.empty() && functionBody.empty());
263 uint32_t fnTypeID = 0;
265 if (
failed(processType(op.getLoc(), op.getFunctionType(), fnTypeID)))
270 uint32_t resTypeID = 0;
271 auto resultTypes = op.getFunctionType().getResults();
272 if (resultTypes.size() > 1) {
273 return op.emitError(
"cannot serialize function with multiple return types");
275 if (
failed(processType(op.getLoc(),
276 (resultTypes.empty() ? getVoidType() : resultTypes[0]),
280 operands.push_back(resTypeID);
281 auto funcID = getOrCreateFunctionID(op.getName());
282 operands.push_back(funcID);
283 operands.push_back(
static_cast<uint32_t
>(op.getFunctionControl()));
284 operands.push_back(fnTypeID);
288 if (
failed(processName(funcID, op.getName()))) {
293 auto linkageAttr = op.getLinkageAttributes();
294 auto hasImportLinkage =
295 linkageAttr && (linkageAttr.value().getLinkageType().getValue() ==
296 spirv::LinkageType::Import);
297 if (op.isExternal() && !hasImportLinkage) {
299 "'spirv.module' cannot contain external functions "
300 "without 'Import' linkage_attributes (LinkageAttributes)");
302 if (op.isExternal() && hasImportLinkage) {
312 if (
failed(processFuncParameter(op)))
319 if (
failed(processFuncParameter(op)))
331 {getOrCreateBlockID(&op.front())});
332 if (
failed(processBlock(&op.front(),
true)))
335 &op.front(), [&](
Block *block) { return processBlock(block); },
342 for (
const auto &deferredValue : deferredPhiValues) {
343 Value value = deferredValue.first;
344 uint32_t
id = getValueID(value);
345 LLVM_DEBUG(llvm::dbgs() <<
"[phi] fix reference of value " << value
346 <<
" to id = " <<
id <<
'\n');
347 assert(
id &&
"OpPhi references undefined value!");
348 for (
size_t offset : deferredValue.second)
349 functionBody[offset] = id;
351 deferredPhiValues.clear();
353 LLVM_DEBUG(llvm::dbgs() <<
"-- completed function '" << op.getName()
359 for (
auto attr : op->getAttrs()) {
361 auto isValidDecoration = mlir::spirv::symbolizeEnum<spirv::Decoration>(
362 llvm::convertToCamelFromSnakeCase(attr.getName().strref(),
364 if (isValidDecoration != std::nullopt) {
365 if (
failed(processDecoration(op.getLoc(), funcID, attr))) {
373 functions.append(functionHeader.begin(), functionHeader.end());
374 functions.append(functionBody.begin(), functionBody.end());
375 functionHeader.clear();
376 functionBody.clear();
381 LogicalResult Serializer::processGraphARMOp(spirv::GraphARMOp op) {
382 if (op.getNumResults() < 1) {
383 return op.emitError(
"cannot serialize graph with no return types");
386 LLVM_DEBUG(llvm::dbgs() <<
"-- start graph '" << op.getName() <<
"' --\n");
387 assert(functionHeader.empty() && functionBody.empty());
389 uint32_t funcID = getOrCreateFunctionID(op.getName());
390 uint32_t fnTypeID = 0;
392 if (
failed(processType(op.getLoc(), op.getFunctionType(), fnTypeID)))
399 uint32_t argTypeID = 0;
402 if (
failed(processType(op.getLoc(), arg.getType(), argTypeID))) {
406 uint32_t argValueID = getNextID();
407 valueIDMap[arg] = argValueID;
410 uint32_t indexID = prepareConstantInt(op.getLoc(), attr,
false);
412 inputOperands.push_back(argTypeID);
413 inputOperands.push_back(argValueID);
414 inputOperands.push_back(indexID);
420 if (
failed(processBlock(&op.front(),
true)))
423 &op.front(), [&](
Block *block) { return processBlock(block); },
428 LLVM_DEBUG(llvm::dbgs() <<
"-- completed graph '" << op.getName()
433 llvm::append_range(graphs, functionHeader);
434 llvm::append_range(graphs, functionBody);
435 functionHeader.clear();
436 functionBody.clear();
442 Serializer::processGraphEntryPointARMOp(spirv::GraphEntryPointARMOp op) {
444 StringRef graph = op.getFn();
446 uint32_t graphID = getOrCreateFunctionID(graph);
447 operands.push_back(graphID);
452 if (ArrayAttr interface = op.getInterface()) {
453 for (
Attribute var : interface.getValue()) {
454 StringRef value = cast<FlatSymbolRefAttr>(var).getValue();
455 if (uint32_t
id = getVariableID(value)) {
456 operands.push_back(
id);
459 "referencing undefined global variable."
460 "spirv.GraphEntryPointARM is at the end of spirv.module. All "
461 "referenced variables should already be defined");
470 Serializer::processGraphOutputsARMOp(spirv::GraphOutputsARMOp op) {
474 Type resType = value.getType();
475 uint32_t resTypeID = 0;
476 if (
failed(processType(op.getLoc(), resType, resTypeID))) {
480 uint32_t outputID = getValueID(value);
482 uint32_t indexID = prepareConstantInt(op.getLoc(), attr,
false);
484 outputOperands.push_back(outputID);
485 outputOperands.push_back(indexID);
493 LogicalResult Serializer::processVariableOp(spirv::VariableOp op) {
496 uint32_t resultID = 0;
497 uint32_t resultTypeID = 0;
498 if (
failed(processType(op.getLoc(), op.getType(), resultTypeID))) {
501 operands.push_back(resultTypeID);
502 resultID = getNextID();
503 valueIDMap[op.getResult()] = resultID;
504 operands.push_back(resultID);
505 auto attr = op->getAttr(spirv::attributeName<spirv::StorageClass>());
508 static_cast<uint32_t
>(cast<spirv::StorageClassAttr>(attr).getValue()));
510 elidedAttrs.push_back(spirv::attributeName<spirv::StorageClass>());
511 for (
auto arg : op.getODSOperands(0)) {
512 auto argID = getValueID(arg);
514 return emitError(op.getLoc(),
"operand 0 has a use before def");
516 operands.push_back(argID);
518 if (
failed(emitDebugLine(functionHeader, op.getLoc())))
521 for (
auto attr : op->getAttrs()) {
522 if (llvm::any_of(elidedAttrs, [&](StringRef elided) {
523 return attr.getName() == elided;
527 if (
failed(processDecoration(op.getLoc(), resultID, attr))) {
535 Serializer::processGlobalVariableOp(spirv::GlobalVariableOp varOp) {
537 uint32_t resultTypeID = 0;
539 if (
failed(processType(varOp.getLoc(), varOp.getType(), resultTypeID))) {
543 elidedAttrs.push_back(
"type");
545 operands.push_back(resultTypeID);
546 auto resultID = getNextID();
549 auto varName = varOp.getSymName();
551 if (
failed(processName(resultID, varName))) {
554 globalVarIDMap[varName] = resultID;
555 operands.push_back(resultID);
558 operands.push_back(
static_cast<uint32_t
>(varOp.storageClass()));
561 StringRef initAttrName = varOp.getInitializerAttrName().getValue();
562 if (std::optional<StringRef> initSymbolName = varOp.getInitializer()) {
563 uint32_t initializerID = 0;
566 varOp->getParentOp(), initRef.getAttr());
569 if (isa<spirv::GlobalVariableOp>(initOp))
570 initializerID = getVariableID(*initSymbolName);
572 initializerID = getSpecConstID(*initSymbolName);
576 "invalid usage of undefined variable as initializer");
578 operands.push_back(initializerID);
579 elidedAttrs.push_back(initAttrName);
582 if (
failed(emitDebugLine(typesGlobalValues, varOp.getLoc())))
585 elidedAttrs.push_back(initAttrName);
588 for (
auto attr : varOp->getAttrs()) {
589 if (llvm::any_of(elidedAttrs, [&](StringRef elided) {
590 return attr.getName() == elided;
594 if (
failed(processDecoration(varOp.getLoc(), resultID, attr))) {
601 LogicalResult Serializer::processSelectionOp(spirv::SelectionOp selectionOp) {
604 auto &body = selectionOp.getBody();
605 for (
Block &block : body)
606 getOrCreateBlockID(&block);
608 auto *headerBlock = selectionOp.getHeaderBlock();
609 auto *mergeBlock = selectionOp.getMergeBlock();
610 auto headerID = getBlockID(headerBlock);
611 auto mergeID = getBlockID(mergeBlock);
612 auto loc = selectionOp.getLoc();
618 auto mergeOp = cast<spirv::MergeOp>(mergeBlock->back());
619 assert(selectionOp.getNumResults() == mergeOp.getNumOperands());
620 for (
unsigned i = 0, e = selectionOp.getNumResults(); i != e; ++i)
621 selectionOp.getResult(i).replaceAllUsesWith(mergeOp.getOperand(i));
633 auto emitSelectionMerge = [&]() {
634 if (
failed(emitDebugLine(functionBody, loc)))
636 lastProcessedWasMergeInst =
true;
638 functionBody, spirv::Opcode::OpSelectionMerge,
639 {mergeID,
static_cast<uint32_t
>(selectionOp.getSelectionControl())});
643 processBlock(headerBlock,
false, emitSelectionMerge)))
650 headerBlock, [&](
Block *block) {
return processBlock(block); },
651 true, {mergeBlock})))
662 if (
failed(emitPhiForBlockArguments(mergeBlock)))
665 LLVM_DEBUG(llvm::dbgs() <<
"done merge ");
666 LLVM_DEBUG(printBlock(mergeBlock, llvm::dbgs()));
667 LLVM_DEBUG(llvm::dbgs() <<
"\n");
671 LogicalResult Serializer::processLoopOp(spirv::LoopOp loopOp) {
675 auto &body = loopOp.getBody();
676 for (
Block &block : llvm::drop_begin(body))
677 getOrCreateBlockID(&block);
679 auto *headerBlock = loopOp.getHeaderBlock();
680 auto *continueBlock = loopOp.getContinueBlock();
681 auto *mergeBlock = loopOp.getMergeBlock();
682 auto headerID = getBlockID(headerBlock);
683 auto continueID = getBlockID(continueBlock);
684 auto mergeID = getBlockID(mergeBlock);
685 auto loc = loopOp.getLoc();
689 auto mergeOp = cast<spirv::MergeOp>(mergeBlock->back());
690 assert(loopOp.getNumResults() == mergeOp.getNumOperands());
691 for (
unsigned i = 0, e = loopOp.getNumResults(); i != e; ++i)
692 loopOp.getResult(i).replaceAllUsesWith(mergeOp.getOperand(i));
708 auto emitLoopMerge = [&]() {
709 if (
failed(emitDebugLine(functionBody, loc)))
711 lastProcessedWasMergeInst =
true;
713 functionBody, spirv::Opcode::OpLoopMerge,
714 {mergeID, continueID,
static_cast<uint32_t
>(loopOp.getLoopControl())});
717 if (
failed(processBlock(headerBlock,
false, emitLoopMerge)))
724 headerBlock, [&](
Block *block) {
return processBlock(block); },
725 true, {continueBlock, mergeBlock})))
729 if (
failed(processBlock(continueBlock)))
737 LLVM_DEBUG(llvm::dbgs() <<
"done merge ");
738 LLVM_DEBUG(printBlock(mergeBlock, llvm::dbgs()));
739 LLVM_DEBUG(llvm::dbgs() <<
"\n");
743 LogicalResult Serializer::processBranchConditionalOp(
744 spirv::BranchConditionalOp condBranchOp) {
745 auto conditionID = getValueID(condBranchOp.getCondition());
746 auto trueLabelID = getOrCreateBlockID(condBranchOp.getTrueBlock());
747 auto falseLabelID = getOrCreateBlockID(condBranchOp.getFalseBlock());
750 if (
auto weights = condBranchOp.getBranchWeights()) {
751 for (
auto val : weights->getValue())
752 arguments.push_back(cast<IntegerAttr>(val).getInt());
755 if (
failed(emitDebugLine(functionBody, condBranchOp.getLoc())))
762 LogicalResult Serializer::processBranchOp(spirv::BranchOp branchOp) {
763 if (
failed(emitDebugLine(functionBody, branchOp.getLoc())))
766 {getOrCreateBlockID(branchOp.getTarget())});
770 LogicalResult Serializer::processAddressOfOp(spirv::AddressOfOp addressOfOp) {
771 auto varName = addressOfOp.getVariable();
772 auto variableID = getVariableID(varName);
774 return addressOfOp.emitError(
"unknown result <id> for variable ")
777 valueIDMap[addressOfOp.getPointer()] = variableID;
782 Serializer::processReferenceOfOp(spirv::ReferenceOfOp referenceOfOp) {
783 auto constName = referenceOfOp.getSpecConst();
784 auto constID = getSpecConstID(constName);
786 return referenceOfOp.emitError(
787 "unknown result <id> for specialization constant ")
790 valueIDMap[referenceOfOp.getReference()] = constID;
796 Serializer::processOp<spirv::EntryPointOp>(spirv::EntryPointOp op) {
799 operands.push_back(
static_cast<uint32_t
>(op.getExecutionModel()));
801 auto funcID = getFunctionID(op.getFn());
803 return op.emitError(
"missing <id> for function ")
805 <<
"; function needs to be defined before spirv.EntryPoint is "
808 operands.push_back(funcID);
813 if (
auto interface = op.getInterface()) {
814 for (
auto var : interface.getValue()) {
815 auto id = getVariableID(cast<FlatSymbolRefAttr>(var).getValue());
818 "referencing undefined global variable."
819 "spirv.EntryPoint is at the end of spirv.module. All "
820 "referenced variables should already be defined");
822 operands.push_back(
id);
831 Serializer::processOp<spirv::ExecutionModeOp>(spirv::ExecutionModeOp op) {
834 auto funcID = getFunctionID(op.getFn());
836 return op.emitError(
"missing <id> for function ")
838 <<
"; function needs to be serialized before ExecutionModeOp is "
841 operands.push_back(funcID);
843 operands.push_back(
static_cast<uint32_t
>(op.getExecutionMode()));
846 auto values = op.getValues();
848 for (
auto &intVal : values.getValue()) {
849 operands.push_back(
static_cast<uint32_t
>(
850 llvm::cast<IntegerAttr>(intVal).getValue().getZExtValue()));
860 Serializer::processOp<spirv::FunctionCallOp>(spirv::FunctionCallOp op) {
861 auto funcName = op.getCallee();
862 uint32_t resTypeID = 0;
864 Type resultTy = op.getNumResults() ? *op.result_type_begin() : getVoidType();
865 if (
failed(processType(op.getLoc(), resultTy, resTypeID)))
868 auto funcID = getOrCreateFunctionID(funcName);
869 auto funcCallID = getNextID();
872 for (
auto value : op.getArguments()) {
873 auto valueID = getValueID(value);
874 assert(valueID &&
"cannot find a value for spirv.FunctionCall");
875 operands.push_back(valueID);
878 if (!isa<NoneType>(resultTy))
879 valueIDMap[op.getResult(0)] = funcCallID;
887 Serializer::processOp<spirv::CopyMemoryOp>(spirv::CopyMemoryOp op) {
891 for (
Value operand : op->getOperands()) {
892 auto id = getValueID(operand);
893 assert(
id &&
"use before def!");
894 operands.push_back(
id);
897 StringAttr memoryAccess = op.getMemoryAccessAttrName();
898 if (
auto attr = op->getAttr(memoryAccess)) {
900 static_cast<uint32_t
>(cast<spirv::MemoryAccessAttr>(attr).getValue()));
903 elidedAttrs.push_back(memoryAccess.strref());
905 StringAttr alignment = op.getAlignmentAttrName();
906 if (
auto attr = op->getAttr(alignment)) {
907 operands.push_back(
static_cast<uint32_t
>(
908 cast<IntegerAttr>(attr).getValue().getZExtValue()));
911 elidedAttrs.push_back(alignment.strref());
913 StringAttr sourceMemoryAccess = op.getSourceMemoryAccessAttrName();
914 if (
auto attr = op->getAttr(sourceMemoryAccess)) {
916 static_cast<uint32_t
>(cast<spirv::MemoryAccessAttr>(attr).getValue()));
919 elidedAttrs.push_back(sourceMemoryAccess.strref());
921 StringAttr sourceAlignment = op.getSourceAlignmentAttrName();
922 if (
auto attr = op->getAttr(sourceAlignment)) {
923 operands.push_back(
static_cast<uint32_t
>(
924 cast<IntegerAttr>(attr).getValue().getZExtValue()));
927 elidedAttrs.push_back(sourceAlignment.strref());
928 if (
failed(emitDebugLine(functionBody, op.getLoc())))
935 LogicalResult Serializer::processOp<spirv::GenericCastToPtrExplicitOp>(
936 spirv::GenericCastToPtrExplicitOp op) {
940 uint32_t resultTypeID = 0;
941 uint32_t resultID = 0;
942 resultTy = op->getResult(0).getType();
943 if (
failed(processType(loc, resultTy, resultTypeID)))
945 operands.push_back(resultTypeID);
947 resultID = getNextID();
948 operands.push_back(resultID);
949 valueIDMap[op->getResult(0)] = resultID;
951 for (
Value operand : op->getOperands())
952 operands.push_back(getValueID(operand));
953 spirv::StorageClass resultStorage =
954 cast<spirv::PointerType>(resultTy).getStorageClass();
955 operands.push_back(
static_cast<uint32_t
>(resultStorage));
963 #define GET_SERIALIZATION_FNS
964 #include "mlir/Dialect/SPIRV/IR/SPIRVSerialization.inc"
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.
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...
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 void enumerate(std::tuple< Tys... > &tuple, CallbackT &&callback)
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.
Include the generated interface declarations.
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...