def LLVM_LifetimeStartOp : LLVM_LifetimeBaseOp<"lifetime.start"> {
// Custom builder to convert the size argument to an attribute.
string mlirBuilder = [{
- $_builder.create<LLVM::LifetimeStartOp>(
+ $_op = $_builder.create<LLVM::LifetimeStartOp>(
$_location, $_int_attr($size), $ptr);
}];
}
def LLVM_LifetimeEndOp : LLVM_LifetimeBaseOp<"lifetime.end"> {
// Custom builder to convert the size argument to an attribute.
string mlirBuilder = [{
- $_builder.create<LLVM::LifetimeEndOp>(
+ $_op = $_builder.create<LLVM::LifetimeEndOp>(
$_location, $_int_attr($size), $ptr);
}];
}
// convertible to MLIR.
auto *dbgIntr = cast<llvm::DbgVariableIntrinsic>(inst);
if (dbgIntr->getExpression()->getNumElements() == 0)
- $_builder.create<$_qualCppClassName>($_location,
+ $_op = $_builder.create<$_qualCppClassName>($_location,
$}] # argName # [{, $_var_attr($varInfo));
}];
let assemblyFormat = [{
$rows, $columns);
}];
string mlirBuilder = [{
- $_builder.create<LLVM::MatrixColumnMajorStoreOp>(
+ $_op = $_builder.create<LLVM::MatrixColumnMajorStoreOp>(
$_location, $matrix, $data, $stride,
$_int_attr($isVolatile), $_int_attr($rows), $_int_attr($columns));
}];
$value, $data, llvm::Align($alignment), $mask);
}];
string mlirBuilder = [{
- $_builder.create<LLVM::MaskedStoreOp>($_location,
+ $_op = $_builder.create<LLVM::MaskedStoreOp>($_location,
$value, $data, $mask, $_int_attr($alignment));
}];
list<int> llvmArgIndices = [0, 1, 3, 2];
$value, $ptrs, llvm::Align($alignment), $mask);
}];
string mlirBuilder = [{
- $_builder.create<LLVM::masked_scatter>($_location,
+ $_op = $_builder.create<LLVM::masked_scatter>($_location,
$value, $ptrs, $mask, $_int_attr($alignment));
}];
list<int> llvmArgIndices = [0, 1, 3, 2];
// of the MLIR operation argument with the given name, or if the
// name matches the result name, by a reference to store the
// result of the newly created MLIR operation to;
+ // - $_op - substituted by a reference to store the newly created MLIR
+ // operation (only for MLIR operations that return no result);
// - $_int_attr - substituted by a call to an integer attribute matcher;
// - $_var_attr - substituted by a call to a variable attribute matcher;
// - $_resultType - substituted with the MLIR result type;
// - $_location - substituted with the MLIR location;
// - $_builder - substituted with the MLIR builder;
// - $_qualCppClassName - substitiuted with the MLIR operation class name.
+ // Always either store a reference to the result of the newly created
+ // operation, or to the operation itself if it does not return a result.
// Additionally, `$$` can be used to produce the dollar character.
string mlirBuilder = "";
$_location, resultTypes, *mlirOperands);
}] # !if(!gt(requiresFastmath, 0),
"moduleImport.setFastmathFlagsAttr(inst, op);", "")
- # !if(!gt(numResults, 0), "$res = op;", "(void)op;");
+ # !if(!gt(numResults, 0), "$res = op;", "$_op = op;");
}
// Base class for LLVM intrinsic operations, should not be used directly. Places
# setAliasScopeMetadataCode;
// FIXME: Import attributes.
string mlirBuilder = [{
- $_builder.create<LLVM::StoreOp>($_location, $value, $addr);
+ $_op = $_builder.create<LLVM::StoreOp>($_location, $value, $addr);
}];
let builders = [
OpBuilder<(ins "Value":$value, "Value":$addr,
moduleImport.convertValues(llvmOperands);
if (failed(mlirOperands))
return failure();
- $_builder.create<LLVM::ReturnOp>($_location, *mlirOperands);
+ $_op = $_builder.create<LLVM::ReturnOp>($_location, *mlirOperands);
}];
}
string llvmInstName = "Resume";
string llvmBuilder = [{ builder.CreateResume($value); }];
string mlirBuilder = [{
- $_builder.create<LLVM::ResumeOp>($_location, $value);
+ $_op = $_builder.create<LLVM::ResumeOp>($_location, $value);
}];
}
def LLVM_UnreachableOp : LLVM_TerminatorOp<"unreachable"> {
string llvmInstName = "Unreachable";
string llvmBuilder = [{ builder.CreateUnreachable(); }];
string mlirBuilder = [{
- $_builder.create<LLVM::UnreachableOp>($_location);
+ $_op = $_builder.create<LLVM::UnreachableOp>($_location);
}];
}
}];
string mlirBuilder = [{
llvm::FenceInst *fenceInst = cast<llvm::FenceInst>(inst);
- $_builder.create<LLVM::FenceOp>(
+ $_op = $_builder.create<LLVM::FenceOp>(
$_location,
getLLVMAtomicOrdering(fenceInst->getOrdering()),
getLLVMSyncScope(fenceInst));
return failure();
}
+ /// Hook for derived dialect interfaces to implement the import of metadata
+ /// into MLIR. Attaches the converted metadata kind and node to the provided
+ /// operation.
+ virtual LogicalResult
+ setMetadataAttrs(OpBuilder &builder, unsigned kind, llvm::MDNode *node,
+ Operation *op, LLVM::ModuleImport &moduleImport) const {
+ return failure();
+ }
+
/// Hook for derived dialect interfaces to publish the supported intrinsics.
/// As every LLVM IR intrinsic has a unique integer identifier, the function
/// returns the list of supported intrinsic identifiers.
virtual ArrayRef<unsigned> getSupportedIntrinsics() const { return {}; }
+
+ /// Hook for derived dialect interfaces to publish the supported metadata
+ /// kinds. As every metadata kind has a unique integer identifier, the
+ /// function returns the list of supported metadata identifiers.
+ virtual ArrayRef<unsigned> getSupportedMetadata() const { return {}; }
};
/// Interface collection for the import of LLVM IR that dispatches to a concrete
public:
using Base::Base;
- /// Queries all dialect interfaces to build a map from intrinsic identifiers
- /// to the dialect interface that supports importing the intrinsic. Returns
- /// failure if multiple dialect interfaces translate the same LLVM IR
- /// intrinsic.
+ /// Queries all registered dialect interfaces for the supported LLVM IR
+ /// intrinsic and metadata kinds and builds the dispatch tables for the
+ /// conversion. Returns failure if multiple dialect interfaces translate the
+ /// same LLVM IR intrinsic.
LogicalResult initializeImport() {
for (const LLVMImportDialectInterface &iface : *this) {
// Verify the supported intrinsics have not been mapped before.
// Add a mapping for all supported intrinsic identifiers.
for (unsigned id : iface.getSupportedIntrinsics())
intrinsicToDialect[id] = iface.getDialect();
+ // Add a mapping for all supported metadata kinds.
+ for (unsigned kind : iface.getSupportedMetadata())
+ metadataToDialect[kind].push_back(iface.getDialect());
}
return success();
return intrinsicToDialect.count(id);
}
+ /// Attaches the given LLVM metadata to the imported operation if a conversion
+ /// to one or more MLIR dialect attributes exists and succeeds. Returns
+ /// success if at least one of the conversions is successful and failure if
+ /// all of them fail.
+ LogicalResult setMetadataAttrs(OpBuilder &builder, unsigned kind,
+ llvm::MDNode *node, Operation *op,
+ LLVM::ModuleImport &moduleImport) const {
+ // Lookup the dialect interfaces for the given metadata.
+ auto it = metadataToDialect.find(kind);
+ if (it == metadataToDialect.end())
+ return failure();
+
+ // Dispatch the conversion to the dialect interfaces.
+ bool isSuccess = false;
+ for (Dialect *dialect : it->getSecond()) {
+ const LLVMImportDialectInterface *iface = getInterfaceFor(dialect);
+ assert(iface && "expected to find a dialect interface");
+ if (succeeded(
+ iface->setMetadataAttrs(builder, kind, node, op, moduleImport)))
+ isSuccess = true;
+ }
+
+ // Returns failure if all conversions fail.
+ return success(isSuccess);
+ }
+
+ /// Returns true if the given LLVM IR metadata is convertible to an MLIR
+ /// attribute.
+ bool isConvertibleMetadata(unsigned kind) {
+ return metadataToDialect.count(kind);
+ }
+
private:
DenseMap<unsigned, Dialect *> intrinsicToDialect;
+ DenseMap<unsigned, SmallVector<Dialect *, 1>> metadataToDialect;
};
} // namespace mlir
ModuleImport(ModuleOp mlirModule, std::unique_ptr<llvm::Module> llvmModule);
/// Calls the LLVMImportInterface initialization that queries the registered
- /// dialect interfaces for the supported LLVM IR intrinsics and builds the
- /// dispatch table. Returns failure if multiple dialect interfaces translate
- /// the same LLVM IR intrinsic.
+ /// dialect interfaces for the supported LLVM IR intrinsics and metadata kinds
+ /// and builds the dispatch tables. Returns failure if multiple dialect
+ /// interfaces translate the same LLVM IR intrinsic.
LogicalResult initializeImportInterface() { return iface.initializeImport(); }
/// Converts all functions of the LLVM module to MLIR functions.
/// Returns the MLIR value mapped to the given LLVM value.
Value lookupValue(llvm::Value *value) { return valueMapping.lookup(value); }
+ /// Stores a mapping between an LLVM instruction and the imported MLIR
+ /// operation if the operation returns no result. Asserts if the operation
+ /// returns a result and should be added to valueMapping instead.
+ void mapNoResultOp(llvm::Instruction *inst, Operation *mlir) {
+ mapNoResultOp(inst) = mlir;
+ }
+
+ /// Provides write-once access to store the MLIR operation corresponding to
+ /// the given LLVM instruction if the operation returns no result. Asserts if
+ /// the operation returns a result and should be added to valueMapping
+ /// instead.
+ Operation *&mapNoResultOp(llvm::Instruction *inst) {
+ Operation *&mlir = noResultOpMapping[inst];
+ assert(inst->getType()->isVoidTy() &&
+ "attempting to map an operation that returns a result");
+ assert(mlir == nullptr &&
+ "attempting to map an operation that is already mapped");
+ return mlir;
+ }
+
+ /// Returns the MLIR operation mapped to the given LLVM instruction. Queries
+ /// valueMapping and noResultOpMapping to support operations with and without
+ /// result.
+ Operation *lookupOperation(llvm::Instruction *inst) {
+ if (Value value = lookupValue(inst))
+ return value.getDefiningOp();
+ return noResultOpMapping.lookup(inst);
+ }
+
/// Stores the mapping between an LLVM block and its MLIR counterpart.
void mapBlock(llvm::BasicBlock *llvm, Block *mlir) {
auto result = blockMapping.try_emplace(llvm, mlir);
/// Clears the block and value mapping before processing a new region.
void clearBlockAndValueMapping() {
valueMapping.clear();
+ noResultOpMapping.clear();
blockMapping.clear();
}
/// Sets the constant insertion point to the start of the given block.
/// counterpart exists. Otherwise, returns failure.
LogicalResult convertInstruction(OpBuilder &odsBuilder,
llvm::Instruction *inst);
+ /// Converts the metadata attached to the original instruction `inst` if
+ /// a dialect interfaces supports the specific kind of metadata and attaches
+ /// the resulting dialect attributes to the converted operation `op`. Emits a
+ /// warning if the conversion of a supported metadata kind fails.
+ void setNonDebugMetadataAttrs(llvm::Instruction *inst, Operation *op);
/// Imports `inst` and populates valueMapping[inst] with the result of the
- /// imported operation.
+ /// imported operation or noResultOpMapping[inst] with the imported operation
+ /// if it has no result.
LogicalResult processInstruction(llvm::Instruction *inst);
/// Converts the `branch` arguments in the order of the phi's found in
/// `target` and appends them to the `blockArguments` to attach to the
DenseMap<llvm::BasicBlock *, Block *> blockMapping;
/// Function-local mapping between original and imported values.
DenseMap<llvm::Value *, Value> valueMapping;
+ /// Function-local mapping between original instructions and imported
+ /// operations for all operations that return no result. All operations that
+ /// return a result have a valueMapping entry instead.
+ DenseMap<llvm::Instruction *, Operation *> noResultOpMapping;
/// Uniquing map of GlobalVariables.
DenseMap<llvm::GlobalVariable *, GlobalOp> globals;
/// The stateful type translator (contains named structs).
return failure();
}
+/// Returns the list of LLVM IR metadata kinds that are convertible to MLIR LLVM
+/// dialect attributes.
+static ArrayRef<unsigned> getSupportedMetadataImpl() {
+ static const SmallVector<unsigned> convertibleMetadata = {
+ llvm::LLVMContext::MD_prof // profiling metadata
+ };
+ return convertibleMetadata;
+}
+
+/// Attaches the given profiling metadata to the imported operation if a
+/// conversion to an MLIR profiling attribute exists and succeeds. Returns
+/// failure otherwise.
+static LogicalResult setProfilingAttrs(OpBuilder &builder, llvm::MDNode *node,
+ Operation *op,
+ LLVM::ModuleImport &moduleImport) {
+ // Return success for empty metadata nodes since there is nothing to import.
+ if (!node->getNumOperands())
+ return success();
+
+ // Return failure for non-"branch_weights" metadata.
+ auto *name = dyn_cast<llvm::MDString>(node->getOperand(0));
+ if (!name || !name->getString().equals("branch_weights"))
+ return failure();
+
+ // Copy the branch weights to an array.
+ SmallVector<int32_t> branchWeights;
+ branchWeights.reserve(node->getNumOperands() - 1);
+ for (unsigned i = 1, e = node->getNumOperands(); i != e; ++i) {
+ llvm::ConstantInt *branchWeight =
+ llvm::mdconst::extract<llvm::ConstantInt>(node->getOperand(i));
+ branchWeights.push_back(branchWeight->getZExtValue());
+ }
+
+ // Attach the branch weights to the operations that support it.
+ if (auto condBrOp = dyn_cast<CondBrOp>(op)) {
+ condBrOp.setBranchWeightsAttr(builder.getI32VectorAttr(branchWeights));
+ return success();
+ }
+ if (auto switchOp = dyn_cast<SwitchOp>(op)) {
+ switchOp.setBranchWeightsAttr(builder.getI32VectorAttr(branchWeights));
+ return success();
+ }
+ return failure();
+}
+
namespace {
/// Implementation of the dialect interface that converts operations belonging
return convertIntrinsicImpl(builder, inst, moduleImport);
}
+ /// Attaches the given LLVM metadata to the imported operation if a conversion
+ /// to an LLVM dialect attribute exists and succeeds. Returns failure
+ /// otherwise.
+ LogicalResult setMetadataAttrs(OpBuilder &builder, unsigned kind,
+ llvm::MDNode *node, Operation *op,
+ LLVM::ModuleImport &moduleImport) const final {
+ // Call metadata specific handlers.
+ if (kind == llvm::LLVMContext::MD_prof)
+ return setProfilingAttrs(builder, node, op, moduleImport);
+
+ // A handler for a supported metadata kind is missing.
+ llvm_unreachable("unknown metadata type");
+ }
+
/// Returns the list of LLVM IR intrinsic identifiers that are convertible to
/// MLIR LLVM dialect intrinsics.
ArrayRef<unsigned> getSupportedIntrinsics() const final {
return getSupportedIntrinsicsImpl();
}
+
+ /// Returns the list of LLVM IR metadata kinds that are convertible to MLIR
+ /// LLVM dialect attributes.
+ ArrayRef<unsigned> getSupportedMetadata() const final {
+ return getSupportedMetadataImpl();
+ }
};
} // namespace
#include "llvm/IR/InlineAsm.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
+#include "llvm/IR/Metadata.h"
#include "llvm/IR/Operator.h"
using namespace mlir;
return success();
}
+void ModuleImport::setNonDebugMetadataAttrs(llvm::Instruction *inst,
+ Operation *op) {
+ SmallVector<std::pair<unsigned, llvm::MDNode *>> allMetadata;
+ inst->getAllMetadataOtherThanDebugLoc(allMetadata);
+ for (auto &[kind, node] : allMetadata) {
+ if (!iface.isConvertibleMetadata(kind))
+ continue;
+ if (failed(iface.setMetadataAttrs(builder, kind, node, op, *this))) {
+ Location loc = debugImporter->translateLoc(inst->getDebugLoc());
+ emitWarning(loc) << "unhandled metadata (" << kind << ") " << diag(*inst);
+ }
+ }
+}
+
void ModuleImport::setFastmathFlagsAttr(llvm::Instruction *inst,
Operation *op) const {
auto iface = cast<FastmathFlagsInterface>(op);
// resulting in a conflicting `valueMapping` entry.
llvm::Instruction *inst = constExpr->getAsInstruction();
auto guard = llvm::make_scope_exit([&]() {
+ assert(noResultOpMapping.find(inst) == noResultOpMapping.end() &&
+ "expected constant expression to return a result");
valueMapping.erase(inst);
inst->deleteValue();
});
succBlockArgs.push_back(blockArgs);
}
- if (brInst->isConditional()) {
- FailureOr<Value> condition = convertValue(brInst->getCondition());
- if (failed(condition))
- return failure();
- builder.create<LLVM::CondBrOp>(loc, *condition, succBlocks.front(),
- succBlockArgs.front(), succBlocks.back(),
- succBlockArgs.back());
- } else {
- builder.create<LLVM::BrOp>(loc, succBlockArgs.front(),
- succBlocks.front());
+ if (!brInst->isConditional()) {
+ auto brOp = builder.create<LLVM::BrOp>(loc, succBlockArgs.front(),
+ succBlocks.front());
+ mapNoResultOp(inst, brOp);
+ return success();
}
+ FailureOr<Value> condition = convertValue(brInst->getCondition());
+ if (failed(condition))
+ return failure();
+ auto condBrOp = builder.create<LLVM::CondBrOp>(
+ loc, *condition, succBlocks.front(), succBlockArgs.front(),
+ succBlocks.back(), succBlockArgs.back());
+ mapNoResultOp(inst, condBrOp);
return success();
}
if (inst->getOpcode() == llvm::Instruction::Switch) {
caseBlocks[it.index()] = lookupBlock(succBB);
}
- builder.create<SwitchOp>(loc, *condition, lookupBlock(defaultBB),
- defaultBlockArgs, caseValues, caseBlocks,
- caseOperandRefs);
+ auto switchOp = builder.create<SwitchOp>(
+ loc, *condition, lookupBlock(defaultBB), defaultBlockArgs, caseValues,
+ caseBlocks, caseOperandRefs);
+ mapNoResultOp(inst, switchOp);
return success();
}
if (inst->getOpcode() == llvm::Instruction::PHI) {
setFastmathFlagsAttr(inst, callOp);
if (!callInst->getType()->isVoidTy())
mapValue(inst, callOp.getResult());
+ else
+ mapNoResultOp(inst, callOp);
return success();
}
if (inst->getOpcode() == llvm::Instruction::LandingPad) {
}
Type type = convertType(lpInst->getType());
- Value res =
+ auto lpOp =
builder.create<LandingpadOp>(loc, type, lpInst->isCleanup(), operands);
- mapValue(inst, res);
+ mapValue(inst, lpOp);
return success();
}
if (inst->getOpcode() == llvm::Instruction::Invoke) {
}
if (!invokeInst->getType()->isVoidTy())
mapValue(inst, invokeOp.getResults().front());
+ else
+ mapNoResultOp(inst, invokeOp);
return success();
}
if (inst->getOpcode() == llvm::Instruction::GetElementPtr) {
}
Type type = convertType(inst->getType());
- Value res = builder.create<GEPOp>(loc, type, sourceElementType, *basePtr,
- indices, gepInst->isInBounds());
- mapValue(inst, res);
+ auto gepOp = builder.create<GEPOp>(loc, type, sourceElementType, *basePtr,
+ indices, gepInst->isInBounds());
+ mapValue(inst, gepOp);
return success();
}
for (llvm::Instruction &inst : *bb) {
if (failed(processInstruction(&inst)))
return failure();
+
+ // Set the non-debug metadata attributes on the imported operation and emit
+ // a warning if an instruction other than a phi instruction is dropped
+ // during the import.
+ if (Operation *op = lookupOperation(&inst)) {
+ setNonDebugMetadataAttrs(&inst, op);
+ } else if (inst.getOpcode() != llvm::Instruction::PHI) {
+ Location loc = debugImporter->translateLoc(inst.getDebugLoc());
+ emitWarning(loc) << "dropped instruction " << diag(inst);
+ }
}
return success();
}
; RUN: not mlir-translate -import-llvm -split-input-file %s 2>&1 | FileCheck %s
-; CHECK: unhandled instruction indirectbr i8* %dst, [label %bb1, label %bb2]
+; CHECK: error: unhandled instruction indirectbr i8* %dst, [label %bb1, label %bb2]
define i32 @unhandled_instruction(i8* %dst) {
indirectbr i8* %dst, [label %bb1, label %bb2]
bb1:
; // -----
-; CHECK: unhandled constant i8* blockaddress(@unhandled_constant, %bb1)
+; CHECK: error: unhandled constant i8* blockaddress(@unhandled_constant, %bb1)
define i8* @unhandled_constant() {
bb1:
ret i8* blockaddress(@unhandled_constant, %bb1)
declare void @llvm.gcroot(ptr %arg0, ptr %arg1)
-; CHECK: unhandled intrinsic call void @llvm.gcroot(ptr %arg0, ptr %arg1)
+; CHECK: error: unhandled intrinsic call void @llvm.gcroot(ptr %arg0, ptr %arg1)
define void @unhandled_intrinsic(ptr %arg0, ptr %arg1) {
call void @llvm.gcroot(ptr %arg0, ptr %arg1)
ret void
}
+
+; // -----
+
+; CHECK: warning: unhandled metadata (2) br i1 %arg1, label %bb1, label %bb2, !prof !0
+define i64 @cond_br(i1 %arg1, i64 %arg2) {
+entry:
+ br i1 %arg1, label %bb1, label %bb2, !prof !0
+bb1:
+ ret i64 %arg2
+bb2:
+ ret i64 %arg2
+}
+
+!0 = !{!"unknown metadata"}
+
+; // -----
+
+declare void @llvm.dbg.value(metadata, metadata, metadata)
+
+; CHECK: warning: dropped instruction call void @llvm.dbg.value(metadata i64 %arg1, metadata !3, metadata !DIExpression(DW_OP_plus_uconst, 42, DW_OP_stack_value)), !dbg !5
+define void @dropped_instruction(i64 %arg1) {
+ call void @llvm.dbg.value(metadata i64 %arg1, metadata !3, metadata !DIExpression(DW_OP_plus_uconst, 42, DW_OP_stack_value)), !dbg !5
+ ret void
+}
+
+!llvm.dbg.cu = !{!1}
+!llvm.module.flags = !{!0}
+!0 = !{i32 2, !"Debug Info Version", i32 3}
+!1 = distinct !DICompileUnit(language: DW_LANG_C, file: !2)
+!2 = !DIFile(filename: "debug-info.ll", directory: "/")
+!3 = !DILocalVariable(scope: !4, name: "arg", file: !2, line: 1, arg: 1, align: 32);
+!4 = distinct !DISubprogram(name: "intrinsic", scope: !2, file: !2, spFlags: DISPFlagDefinition, unit: !1)
+!5 = !DILocation(line: 1, column: 2, scope: !4)
--- /dev/null
+; RUN: mlir-translate -import-llvm -split-input-file %s | FileCheck %s
+
+; CHECK-LABEL: @cond_br
+define i64 @cond_br(i1 %arg1, i64 %arg2) {
+entry:
+ ; CHECK: llvm.cond_br
+ ; CHECK-SAME: weights(dense<[0, 3]> : vector<2xi32>)
+ br i1 %arg1, label %bb1, label %bb2, !prof !0
+bb1:
+ ret i64 %arg2
+bb2:
+ ret i64 %arg2
+}
+
+!0 = !{!"branch_weights", i32 0, i32 3}
+
+; // -----
+
+; CHECK-LABEL: @simple_switch(
+define i32 @simple_switch(i32 %arg1) {
+ ; CHECK: llvm.switch
+ ; CHECK: {branch_weights = dense<[42, 3, 5]> : vector<3xi32>}
+ switch i32 %arg1, label %bbd [
+ i32 0, label %bb1
+ i32 9, label %bb2
+ ], !prof !0
+bb1:
+ ret i32 %arg1
+bb2:
+ ret i32 %arg1
+bbd:
+ ret i32 %arg1
+}
+
+!0 = !{!"branch_weights", i32 42, i32 3, i32 5}
if (op.getNumResults() != 1)
return emitError(record, "expected op to have one result");
bs << "moduleImport.mapValue(inst)";
+ } else if (name == "_op") {
+ bs << "moduleImport.mapNoResultOp(inst)";
} else if (name == "_int_attr") {
bs << "moduleImport.matchIntegerAttr";
} else if (name == "_var_attr") {