Files
clang-p2996/mlir/lib/Target/LLVMIR/LLVMImportInterface.cpp
Bruno Cardoso Lopes 5265412c13 [MLIR][LLVMIR] Import: add flag to prefer using unregistered intrinsics (#130685)
Currently, there is no common mechanism for supported intrinsics to be
generically annotated with arg and ret attributes. Since there are many
supported intrinsics around different dialects, the amount of work to
teach all them about these attributes is not trivial (though it would be
nice in the long term).

This PR adds a new flag `-prefer-unregistered-intrinsics` that can be
used alongside `--import-llvm` to always use `llvm.intrinsic_call`
during import time (ignoring dialect hooks for custom intrinsic
support).

Using this flag allow us to roundtrip the LLVM IR while eliminating a
whole set of differences coming from lack of arg/ret attributes on
supported intrinsics.

Note `convertIntrinsic` has to be moved to an implementation file
because it queries into `moduleImport` state, which is a fwd declaration
in `LLVMImportInterface.h`
2025-03-14 18:04:32 -07:00

93 lines
3.5 KiB
C++

//===------------------------------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file implements methods from LLVMImportInterface.
//
//===----------------------------------------------------------------------===//
#include "mlir/Target/LLVMIR/LLVMImportInterface.h"
#include "mlir/Target/LLVMIR/Import.h"
#include "mlir/Target/LLVMIR/ModuleImport.h"
using namespace mlir;
using namespace mlir::LLVM;
using namespace mlir::LLVM::detail;
LogicalResult mlir::LLVMImportInterface::convertUnregisteredIntrinsic(
OpBuilder &builder, llvm::CallInst *inst,
LLVM::ModuleImport &moduleImport) {
StringRef intrinName = inst->getCalledFunction()->getName();
SmallVector<llvm::Value *> args(inst->args());
ArrayRef<llvm::Value *> llvmOperands(args);
SmallVector<llvm::OperandBundleUse> llvmOpBundles;
llvmOpBundles.reserve(inst->getNumOperandBundles());
for (unsigned i = 0; i < inst->getNumOperandBundles(); ++i)
llvmOpBundles.push_back(inst->getOperandBundleAt(i));
SmallVector<Value> mlirOperands;
SmallVector<NamedAttribute> mlirAttrs;
if (failed(moduleImport.convertIntrinsicArguments(
llvmOperands, llvmOpBundles, false, {}, {}, mlirOperands, mlirAttrs)))
return failure();
Type results = moduleImport.convertType(inst->getType());
auto op = builder.create<::mlir::LLVM::CallIntrinsicOp>(
moduleImport.translateLoc(inst->getDebugLoc()), results,
StringAttr::get(builder.getContext(), intrinName),
ValueRange{mlirOperands}, FastmathFlagsAttr{});
moduleImport.setFastmathFlagsAttr(inst, op);
ArrayAttr argsAttr, resAttr;
moduleImport.convertParameterAttributes(inst, argsAttr, resAttr, builder);
op.setArgAttrsAttr(argsAttr);
op.setResAttrsAttr(resAttr);
// Update importer tracking of results.
unsigned numRes = op.getNumResults();
if (numRes == 1)
moduleImport.mapValue(inst) = op.getResult(0);
else if (numRes == 0)
moduleImport.mapNoResultOp(inst);
else
return op.emitError(
"expected at most one result from target intrinsic call");
return success();
}
/// Converts the LLVM intrinsic to an MLIR operation if a conversion exists.
/// Returns failure otherwise.
LogicalResult mlir::LLVMImportInterface::convertIntrinsic(
OpBuilder &builder, llvm::CallInst *inst,
LLVM::ModuleImport &moduleImport) const {
// Lookup the dialect interface for the given intrinsic.
// Verify the intrinsic identifier maps to an actual intrinsic.
llvm::Intrinsic::ID intrinId = inst->getIntrinsicID();
assert(intrinId != llvm::Intrinsic::not_intrinsic);
// First lookup the intrinsic across different dialects for known
// supported conversions, examples include arm-neon, nvm-sve, etc.
Dialect *dialect = nullptr;
if (!moduleImport.useUnregisteredIntrinsicsOnly())
dialect = intrinsicToDialect.lookup(intrinId);
// No specialized (supported) intrinsics, attempt to generate a generic
// version via llvm.call_intrinsic (if available).
if (!dialect)
return convertUnregisteredIntrinsic(builder, inst, moduleImport);
// Dispatch the conversion to the dialect interface.
const LLVMImportDialectInterface *iface = getInterfaceFor(dialect);
assert(iface && "expected to find a dialect interface");
return iface->convertIntrinsic(builder, inst, moduleImport);
}