[Mlir-commits] [mlir] [MLIR][LLVMIR] Import unregistered intrinsics via llvm.intrinsic_call (PR #128626)
Bruno Cardoso Lopes
llvmlistbot at llvm.org
Mon Feb 24 21:00:32 PST 2025
https://github.com/bcardosolopes created https://github.com/llvm/llvm-project/pull/128626
Currently, the llvm importer can only cover intrinsics that have a first class representation in an MLIR dialect (arm-neon, etc). This PR introduces a fallback mechanism that allow "unregistered" intrinsics to be imported by using the generic `llvm.intrinsic_call` operation. This is useful in several ways:
1. Allows round-trip the LLVM dialect output lowered from other dialects (example: ClangIR)
2. Enables MLIR-linking tools to operate on imported LLVM IR without requiring adding new operations to dozen of different targets (cc @xlauko @smeenai).
Implemented:
- Cover intrinsics across all current supported LLVM targets and generic ones.
- Use existing LLVM tablegen files to populate intrinsic matching.
- Matches with lower priority against dialect supported intrinsic conversion.
Open question: how to add the proper include path for tablegen to find Intrinsics.td?
>From 3896bb916e925427f997906591cb813bdde202f8 Mon Sep 17 00:00:00 2001
From: Bruno Cardoso Lopes <bruno.cardoso at gmail.com>
Date: Thu, 20 Feb 2025 16:24:56 -0800
Subject: [PATCH] [MLIR][LLVMIR] Import unregistered intrinsics via
llvm.intrinsic_call
Currently, the llvm importer can only cover intrinsics that have a first class
representation in an MLIR dialect (arm-neon, etc). This PR introduces a
fallback mechanism that allow "unregistered" intrinsics to be imported by using
the generic `llvm.intrinsic_call` operation. This is useful in several ways:
1. Allows round-trip the LLVM dialect output lowered from other dialects
(example: ClangIR)
2. Enables MLIR-linking tools to operate on imported LLVM IR without requiring
adding new operations to dozen of different targets (cc @xlauko @smeenai).
Implemented:
- Cover intrinsics across all current supported LLVM targets and generic ones.
- Use existing LLVM tablegen files to populate intrinsic matching.
- Matches with lower priority against dialect supported intrinsic conversion.
Open question: how to add the proper include path for tablegen to find
Intrinsics.td?
---
.../mlir/Dialect/LLVMIR/CMakeLists.txt | 26 ++++
.../mlir/Target/LLVMIR/LLVMImportInterface.h | 24 +++-
mlir/lib/Dialect/LLVMIR/CMakeLists.txt | 3 +
.../LLVMIR/LLVMIRToLLVMTranslation.cpp | 125 ++++++++++++++++++
.../Target/LLVMIR/Import/import-failure.ll | 12 --
.../LLVMIR/Import/intrinsic-unregistered.ll | 68 ++++++++++
.../tools/mlir-tblgen/LLVMIRConversionGen.cpp | 57 ++++++++
7 files changed, 302 insertions(+), 13 deletions(-)
create mode 100644 mlir/test/Target/LLVMIR/Import/intrinsic-unregistered.ll
diff --git a/mlir/include/mlir/Dialect/LLVMIR/CMakeLists.txt b/mlir/include/mlir/Dialect/LLVMIR/CMakeLists.txt
index 759de745440c2..cefd1bbe4b027 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/CMakeLists.txt
+++ b/mlir/include/mlir/Dialect/LLVMIR/CMakeLists.txt
@@ -81,3 +81,29 @@ mlir_tablegen(VCIXConversions.inc -gen-llvmir-conversions)
mlir_tablegen(VCIXOpsAttributes.h.inc -gen-attrdef-decls -attrdefs-dialect=vcix)
mlir_tablegen(VCIXOpsAttributes.cpp.inc -gen-attrdef-defs -attrdefs-dialect=vcix)
add_public_tablegen_target(MLIRVCIXConversionsIncGen)
+
+# FIXME: Should emit extra file with intrinsics_gen if MLIR is enabled? Or maybe find
+# a better way to get the path for Intrinsics.td?
+set(LLVM_TARGET_DEFINITIONS ../../../../../llvm/include/llvm/IR/Intrinsics.td)
+
+mlir_tablegen(LLVMUnregisteredLLVMIRIntrinsics.inc -gen-unregistered-llvmir-intrinsics)
+mlir_tablegen(LLVMUnregisteredAArch64LLVMIRIntrinsics.inc -gen-unregistered-llvmir-intrinsics -intrinsic-prefix=aarch64)
+mlir_tablegen(LLVMUnregisteredAMDGPULLVMIRIntrinsics.inc -gen-unregistered-llvmir-intrinsics -intrinsic-prefix=amdgcn)
+mlir_tablegen(LLVMUnregisteredARMLLVMIRIntrinsics.inc -gen-unregistered-llvmir-intrinsics -intrinsic-prefix=arm)
+mlir_tablegen(LLVMUnregisteredBPFLLVMIRIntrinsics.inc -gen-unregistered-llvmir-intrinsics -intrinsic-prefix=bpf)
+mlir_tablegen(LLVMUnregisteredDirectXLLVMIRIntrinsics.inc -gen-unregistered-llvmir-intrinsics -intrinsic-prefix=dx)
+mlir_tablegen(LLVMUnregisteredHexagonLLVMIRIntrinsics.inc -gen-unregistered-llvmir-intrinsics -intrinsic-prefix=hexagon)
+mlir_tablegen(LLVMUnregisteredLoongArchLLVMIRIntrinsics.inc -gen-unregistered-llvmir-intrinsics -intrinsic-prefix=loongarch)
+mlir_tablegen(LLVMUnregisteredMipsLLVMIRIntrinsics.inc -gen-unregistered-llvmir-intrinsics -intrinsic-prefix=mips)
+mlir_tablegen(LLVMUnregisteredNVPTXLLVMIRIntrinsics.inc -gen-unregistered-llvmir-intrinsics -intrinsic-prefix=nvvm)
+mlir_tablegen(LLVMUnregisteredPowerPCLLVMIRIntrinsics.inc -gen-unregistered-llvmir-intrinsics -intrinsic-prefix=ppc)
+mlir_tablegen(LLVMUnregisteredR600LLVMIRIntrinsics.inc -gen-unregistered-llvmir-intrinsics -intrinsic-prefix=r600)
+mlir_tablegen(LLVMUnregisteredRISCVLLVMIRIntrinsics.inc -gen-unregistered-llvmir-intrinsics -intrinsic-prefix=riscv)
+mlir_tablegen(LLVMUnregisteredSPIRVLLVMIRIntrinsics.inc -gen-unregistered-llvmir-intrinsics -intrinsic-prefix=spv)
+mlir_tablegen(LLVMUnregisteredS390LLVMIRIntrinsics.inc -gen-unregistered-llvmir-intrinsics -intrinsic-prefix=s390)
+mlir_tablegen(LLVMUnregisteredWebAssemblyLLVMIRIntrinsics.inc -gen-unregistered-llvmir-intrinsics -intrinsic-prefix=wasm)
+mlir_tablegen(LLVMUnregisteredX86LLVMIRIntrinsics.inc -gen-unregistered-llvmir-intrinsics -intrinsic-prefix=x86)
+mlir_tablegen(LLVMUnregisteredXCoreLLVMIRIntrinsics.inc -gen-unregistered-llvmir-intrinsics -intrinsic-prefix=xcore)
+mlir_tablegen(LLVMUnregisteredVELLVMIRIntrinsics.inc -gen-unregistered-llvmir-intrinsics -intrinsic-prefix=ve)
+
+add_public_tablegen_target(MLIRLLVMIntrinsicUnregisteredIncGen)
\ No newline at end of file
diff --git a/mlir/include/mlir/Target/LLVMIR/LLVMImportInterface.h b/mlir/include/mlir/Target/LLVMIR/LLVMImportInterface.h
index cc5a77ed35d2b..d122021e8586d 100644
--- a/mlir/include/mlir/Target/LLVMIR/LLVMImportInterface.h
+++ b/mlir/include/mlir/Target/LLVMIR/LLVMImportInterface.h
@@ -74,6 +74,10 @@ class LLVMImportDialectInterface
/// returns the list of supported intrinsic identifiers.
virtual ArrayRef<unsigned> getSupportedIntrinsics() const { return {}; }
+ /// Returns the list of LLVM IR intrinsic identifiers that are unsupported
+ /// but dialects might have a generic way to represent them.
+ virtual ArrayRef<unsigned> getUnregisteredIntrinsics() const { return {}; }
+
/// Hook for derived dialect interfaces to publish the supported instructions.
/// As every LLVM IR instruction has a unique integer identifier, the function
/// returns the list of supported instruction identifiers. These identifiers
@@ -139,6 +143,9 @@ class LLVMImportInterface
// Add a mapping for all supported intrinsic identifiers.
for (unsigned id : iface.getSupportedIntrinsics())
intrinsicToDialect[id] = iface.getDialect();
+ // Add a mapping for all unregistered intrinsic identifiers.
+ for (unsigned id : iface.getUnregisteredIntrinsics())
+ unregisteredIntrinscToDialect[id] = iface.getDialect();
// Add a mapping for all supported instruction identifiers.
for (unsigned id : iface.getSupportedInstructions())
instructionToDialect[id] = &iface;
@@ -155,7 +162,19 @@ class LLVMImportInterface
LogicalResult convertIntrinsic(OpBuilder &builder, llvm::CallInst *inst,
LLVM::ModuleImport &moduleImport) const {
// Lookup the dialect interface for the given intrinsic.
- Dialect *dialect = intrinsicToDialect.lookup(inst->getIntrinsicID());
+ llvm::Intrinsic::ID intrinId = inst->getIntrinsicID();
+ if (intrinId == llvm::Intrinsic::not_intrinsic)
+ return failure();
+
+ // First lookup intrinsic across different dialects for known
+ // supported converstions, examples include arm-neon, nvm-sve, etc
+ Dialect *dialect = intrinsicToDialect.lookup(intrinId);
+
+ // No specialized (supported) intrinsics, attempt to generate a generic
+ // version via llvm.call_intrinsic (if available).
+ if (!dialect)
+ dialect = unregisteredIntrinscToDialect.lookup(intrinId);
+
if (!dialect)
return failure();
@@ -227,6 +246,9 @@ class LLVMImportInterface
DenseMap<unsigned, Dialect *> intrinsicToDialect;
DenseMap<unsigned, const LLVMImportDialectInterface *> instructionToDialect;
DenseMap<unsigned, SmallVector<Dialect *, 1>> metadataToDialect;
+
+ /// Unregistered generic and target independent intrinsics.
+ DenseMap<unsigned, Dialect *> unregisteredIntrinscToDialect;
};
} // namespace mlir
diff --git a/mlir/lib/Dialect/LLVMIR/CMakeLists.txt b/mlir/lib/Dialect/LLVMIR/CMakeLists.txt
index c9a3b97294562..030aed9cdb06a 100644
--- a/mlir/lib/Dialect/LLVMIR/CMakeLists.txt
+++ b/mlir/lib/Dialect/LLVMIR/CMakeLists.txt
@@ -17,6 +17,9 @@ add_mlir_dialect_library(MLIRLLVMDialect
MLIRLLVMTypesIncGen
MLIRLLVMIntrinsicOpsIncGen
MLIRLLVMInterfacesIncGen
+ MLIRLLVMConversionsIncGen
+ MLIRLLVMIntrinsicConversionsIncGen
+ MLIRLLVMIntrinsicUnregisteredIncGen
MLIROpenMPOpsIncGen
intrinsics_gen
diff --git a/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMIRToLLVMTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMIRToLLVMTranslation.cpp
index 4fd043c7c93e6..88ea2ff58434d 100644
--- a/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMIRToLLVMTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMIRToLLVMTranslation.cpp
@@ -24,6 +24,24 @@
#include "llvm/IR/InlineAsm.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
+#include "llvm/IR/IntrinsicsAArch64.h"
+#include "llvm/IR/IntrinsicsAMDGPU.h"
+#include "llvm/IR/IntrinsicsARM.h"
+#include "llvm/IR/IntrinsicsBPF.h"
+#include "llvm/IR/IntrinsicsDirectX.h"
+#include "llvm/IR/IntrinsicsHexagon.h"
+#include "llvm/IR/IntrinsicsLoongArch.h"
+#include "llvm/IR/IntrinsicsMips.h"
+#include "llvm/IR/IntrinsicsNVPTX.h"
+#include "llvm/IR/IntrinsicsPowerPC.h"
+#include "llvm/IR/IntrinsicsR600.h"
+#include "llvm/IR/IntrinsicsRISCV.h"
+#include "llvm/IR/IntrinsicsS390.h"
+#include "llvm/IR/IntrinsicsSPIRV.h"
+#include "llvm/IR/IntrinsicsVE.h"
+#include "llvm/IR/IntrinsicsWebAssembly.h"
+#include "llvm/IR/IntrinsicsX86.h"
+#include "llvm/IR/IntrinsicsXCore.h"
#include "llvm/Support/ModRef.h"
using namespace mlir;
@@ -56,6 +74,105 @@ static ArrayRef<unsigned> getSupportedIntrinsicsImpl() {
return convertibleIntrinsics;
}
+/// Returns true if the LLVM IR intrinsic is convertible to llvm.intrinsic_call
+/// Returns false otherwise.
+static bool isConvertibleUnregisteredIntrinsic(llvm::Intrinsic::ID id) {
+ static const DenseSet<unsigned> convertibleTargetIntrinsics = {
+#include "mlir/Dialect/LLVMIR/LLVMUnregisteredAArch64LLVMIRIntrinsics.inc"
+#include "mlir/Dialect/LLVMIR/LLVMUnregisteredAMDGPULLVMIRIntrinsics.inc"
+#include "mlir/Dialect/LLVMIR/LLVMUnregisteredARMLLVMIRIntrinsics.inc"
+#include "mlir/Dialect/LLVMIR/LLVMUnregisteredBPFLLVMIRIntrinsics.inc"
+#include "mlir/Dialect/LLVMIR/LLVMUnregisteredDirectXLLVMIRIntrinsics.inc"
+#include "mlir/Dialect/LLVMIR/LLVMUnregisteredHexagonLLVMIRIntrinsics.inc"
+#include "mlir/Dialect/LLVMIR/LLVMUnregisteredLLVMIRIntrinsics.inc"
+#include "mlir/Dialect/LLVMIR/LLVMUnregisteredLoongArchLLVMIRIntrinsics.inc"
+#include "mlir/Dialect/LLVMIR/LLVMUnregisteredMipsLLVMIRIntrinsics.inc"
+#include "mlir/Dialect/LLVMIR/LLVMUnregisteredNVPTXLLVMIRIntrinsics.inc"
+#include "mlir/Dialect/LLVMIR/LLVMUnregisteredPowerPCLLVMIRIntrinsics.inc"
+#include "mlir/Dialect/LLVMIR/LLVMUnregisteredR600LLVMIRIntrinsics.inc"
+#include "mlir/Dialect/LLVMIR/LLVMUnregisteredRISCVLLVMIRIntrinsics.inc"
+#include "mlir/Dialect/LLVMIR/LLVMUnregisteredS390LLVMIRIntrinsics.inc"
+#include "mlir/Dialect/LLVMIR/LLVMUnregisteredSPIRVLLVMIRIntrinsics.inc"
+#include "mlir/Dialect/LLVMIR/LLVMUnregisteredVELLVMIRIntrinsics.inc"
+#include "mlir/Dialect/LLVMIR/LLVMUnregisteredWebAssemblyLLVMIRIntrinsics.inc"
+#include "mlir/Dialect/LLVMIR/LLVMUnregisteredX86LLVMIRIntrinsics.inc"
+#include "mlir/Dialect/LLVMIR/LLVMUnregisteredXCoreLLVMIRIntrinsics.inc"
+ };
+ return convertibleTargetIntrinsics.contains(id);
+}
+
+/// Returns the list of LLVM IR intrinsic identifiers that are not registered
+/// by any dialect but can be convertible to llvm.intrinsic_call operation.
+static ArrayRef<unsigned> getUnregisteredIntrinsicsImpl() {
+ static const SmallVector<unsigned> convertibleTargetIntrinsics = {
+#include "mlir/Dialect/LLVMIR/LLVMUnregisteredAArch64LLVMIRIntrinsics.inc"
+#include "mlir/Dialect/LLVMIR/LLVMUnregisteredAMDGPULLVMIRIntrinsics.inc"
+#include "mlir/Dialect/LLVMIR/LLVMUnregisteredARMLLVMIRIntrinsics.inc"
+#include "mlir/Dialect/LLVMIR/LLVMUnregisteredBPFLLVMIRIntrinsics.inc"
+#include "mlir/Dialect/LLVMIR/LLVMUnregisteredDirectXLLVMIRIntrinsics.inc"
+#include "mlir/Dialect/LLVMIR/LLVMUnregisteredHexagonLLVMIRIntrinsics.inc"
+#include "mlir/Dialect/LLVMIR/LLVMUnregisteredLLVMIRIntrinsics.inc"
+#include "mlir/Dialect/LLVMIR/LLVMUnregisteredLoongArchLLVMIRIntrinsics.inc"
+#include "mlir/Dialect/LLVMIR/LLVMUnregisteredMipsLLVMIRIntrinsics.inc"
+#include "mlir/Dialect/LLVMIR/LLVMUnregisteredNVPTXLLVMIRIntrinsics.inc"
+#include "mlir/Dialect/LLVMIR/LLVMUnregisteredPowerPCLLVMIRIntrinsics.inc"
+#include "mlir/Dialect/LLVMIR/LLVMUnregisteredR600LLVMIRIntrinsics.inc"
+#include "mlir/Dialect/LLVMIR/LLVMUnregisteredRISCVLLVMIRIntrinsics.inc"
+#include "mlir/Dialect/LLVMIR/LLVMUnregisteredS390LLVMIRIntrinsics.inc"
+#include "mlir/Dialect/LLVMIR/LLVMUnregisteredSPIRVLLVMIRIntrinsics.inc"
+#include "mlir/Dialect/LLVMIR/LLVMUnregisteredVELLVMIRIntrinsics.inc"
+#include "mlir/Dialect/LLVMIR/LLVMUnregisteredWebAssemblyLLVMIRIntrinsics.inc"
+#include "mlir/Dialect/LLVMIR/LLVMUnregisteredX86LLVMIRIntrinsics.inc"
+#include "mlir/Dialect/LLVMIR/LLVMUnregisteredXCoreLLVMIRIntrinsics.inc"
+ };
+ return convertibleTargetIntrinsics;
+}
+
+/// Converts the LLVM intrinsic to a generic LLVM intrinsic call using
+/// llvm.intrinsic_call. Returns failure otherwise.
+static LogicalResult
+convertUnregisteredIntrinsicImpl(OpBuilder &odsBuilder, llvm::CallInst *inst,
+ LLVM::ModuleImport &moduleImport) {
+ llvm::Intrinsic::ID intrinsicID = inst->getIntrinsicID();
+ StringRef intrinName = inst->getCalledFunction()->getName();
+
+ // Sanity check the intrinsic ID.
+ assert(isConvertibleUnregisteredIntrinsic(intrinsicID));
+ 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();
+
+ mlir::Type results = moduleImport.convertType(inst->getType());
+ auto op = odsBuilder.create<::mlir::LLVM::CallIntrinsicOp>(
+ moduleImport.translateLoc(inst->getDebugLoc()), results,
+ StringAttr::get(odsBuilder.getContext(), intrinName),
+ ValueRange{mlirOperands}, FastmathFlagsAttr{});
+
+ moduleImport.setFastmathFlagsAttr(inst, op);
+
+ // 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 LLVM dialect operation if a
/// conversion exits. Returns failure otherwise.
static LogicalResult convertIntrinsicImpl(OpBuilder &odsBuilder,
@@ -75,6 +192,8 @@ static LogicalResult convertIntrinsicImpl(OpBuilder &odsBuilder,
llvmOpBundles.push_back(inst->getOperandBundleAt(i));
#include "mlir/Dialect/LLVMIR/LLVMIntrinsicFromLLVMIRConversions.inc"
+ } else if (isConvertibleUnregisteredIntrinsic(intrinsicID)) {
+ return convertUnregisteredIntrinsicImpl(odsBuilder, inst, moduleImport);
}
return failure();
@@ -422,6 +541,12 @@ class LLVMDialectLLVMIRImportInterface : public LLVMImportDialectInterface {
return getSupportedIntrinsicsImpl();
}
+ /// Returns the list of LLVM IR intrinsic identifiers that are unsupported
+ /// by existing dialects by are convertible to generic llvm.call_intrinsic.
+ ArrayRef<unsigned> getUnregisteredIntrinsics() const final {
+ return getUnregisteredIntrinsicsImpl();
+ }
+
/// Returns the list of LLVM IR metadata kinds that are convertible to MLIR
/// LLVM dialect attributes.
ArrayRef<unsigned>
diff --git a/mlir/test/Target/LLVMIR/Import/import-failure.ll b/mlir/test/Target/LLVMIR/Import/import-failure.ll
index d929a59284762..fc4ccddb756d5 100644
--- a/mlir/test/Target/LLVMIR/Import/import-failure.ll
+++ b/mlir/test/Target/LLVMIR/Import/import-failure.ll
@@ -38,18 +38,6 @@ bb1:
; // -----
-declare void @llvm.gcroot(ptr %arg1, ptr %arg2)
-
-; CHECK: <unknown>
-; CHECK-SAME: error: unhandled intrinsic: call void @llvm.gcroot(ptr %arg1, ptr null)
-define void @unhandled_intrinsic() gc "example" {
- %arg1 = alloca ptr
- call void @llvm.gcroot(ptr %arg1, ptr null)
- ret void
-}
-
-; // -----
-
; Check that debug intrinsics with an unsupported argument are dropped.
declare void @llvm.dbg.value(metadata, metadata, metadata)
diff --git a/mlir/test/Target/LLVMIR/Import/intrinsic-unregistered.ll b/mlir/test/Target/LLVMIR/Import/intrinsic-unregistered.ll
new file mode 100644
index 0000000000000..0f30ce438dbaa
--- /dev/null
+++ b/mlir/test/Target/LLVMIR/Import/intrinsic-unregistered.ll
@@ -0,0 +1,68 @@
+; RUN: mlir-translate -import-llvm %s -split-input-file | FileCheck %s
+
+declare i64 @llvm.aarch64.ldxr.p0(ptr)
+
+define dso_local void @t0(ptr %a) {
+ %x = call i64 @llvm.aarch64.ldxr.p0(ptr elementtype(i8) %a)
+ ret void
+}
+
+; CHECK-LABEL: llvm.func @llvm.aarch64.ldxr.p0(!llvm.ptr)
+; CHECK-LABEL: llvm.func @t0
+; CHECK: llvm.call_intrinsic "llvm.aarch64.ldxr.p0"({{.*}}) : (!llvm.ptr) -> i64
+; CHECK: llvm.return
+; CHECK: }
+
+; -----
+
+declare <8 x i8> @llvm.aarch64.neon.uabd.v8i8(<8 x i8>, <8 x i8>)
+
+define dso_local <8 x i8> @t1(<8 x i8> %lhs, <8 x i8> %rhs) {
+ %r = call <8 x i8> @llvm.aarch64.neon.uabd.v8i8(<8 x i8> %lhs, <8 x i8> %rhs)
+ ret <8 x i8> %r
+}
+
+; CHECK: llvm.func @t1(%[[A0:.*]]: vector<8xi8>, %[[A1:.*]]: vector<8xi8>) -> vector<8xi8> {{.*}} {
+; CHECK: %[[R:.*]] = llvm.call_intrinsic "llvm.aarch64.neon.uabd.v8i8"(%[[A0]], %[[A1]]) : (vector<8xi8>, vector<8xi8>) -> vector<8xi8>
+; CHECK: llvm.return %[[R]] : vector<8xi8>
+; CHECK: }
+
+; -----
+
+declare void @llvm.aarch64.neon.st2.v8i8.p0(<8 x i8>, <8 x i8>, ptr)
+
+define dso_local void @t2(<8 x i8> %lhs, <8 x i8> %rhs, ptr %a) {
+ call void @llvm.aarch64.neon.st2.v8i8.p0(<8 x i8> %lhs, <8 x i8> %rhs, ptr %a)
+ ret void
+}
+
+; CHECK: llvm.func @t2(%[[A0:.*]]: vector<8xi8>, %[[A1:.*]]: vector<8xi8>, %[[A2:.*]]: !llvm.ptr) {{.*}} {
+; CHECK: llvm.call_intrinsic "llvm.aarch64.neon.st2.v8i8.p0"(%[[A0]], %[[A1]], %[[A2]]) : (vector<8xi8>, vector<8xi8>, !llvm.ptr) -> !llvm.void
+; CHECK: llvm.return
+; CHECK: }
+
+; -----
+
+declare void @llvm.gcroot(ptr %arg1, ptr %arg2)
+define void @gctest() gc "example" {
+ %arg1 = alloca ptr
+ call void @llvm.gcroot(ptr %arg1, ptr null)
+ ret void
+}
+
+; CHECK-LABEL: @gctest
+; CHECK: llvm.call_intrinsic "llvm.gcroot"({{.*}}, {{.*}}) : (!llvm.ptr, !llvm.ptr) -> !llvm.void
+
+; -----
+
+; Test we get the supported version, not the unregistered one.
+
+declare i32 @llvm.lround.i32.f32(float)
+
+; CHECK-LABEL: llvm.func @lround_test
+define void @lround_test(float %0, double %1) {
+ ; CHECK-NOT: llvm.call_intrinsic "llvm.lround
+ ; CHECK: llvm.intr.lround(%{{.*}}) : (f32) -> i32
+ %3 = call i32 @llvm.lround.i32.f32(float %0)
+ ret void
+}
\ No newline at end of file
diff --git a/mlir/tools/mlir-tblgen/LLVMIRConversionGen.cpp b/mlir/tools/mlir-tblgen/LLVMIRConversionGen.cpp
index 9e19f479d673a..c78872fa2de39 100644
--- a/mlir/tools/mlir-tblgen/LLVMIRConversionGen.cpp
+++ b/mlir/tools/mlir-tblgen/LLVMIRConversionGen.cpp
@@ -19,6 +19,7 @@
#include "llvm/ADT/Sequence.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/Twine.h"
+#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/TableGen/Error.h"
@@ -564,6 +565,46 @@ static bool emitConvertibleIntrinsics(const RecordKeeper &records,
return false;
}
+static void emitOneUnregisteredIntrinsic(const Record &record, raw_ostream &os,
+ StringRef targetName) {
+ StringRef targetPrefix = record.getValueAsString("TargetPrefix");
+
+ // Not interested in target specific intrinsics in the generic namespace.
+ if (targetName.empty() && !targetPrefix.empty())
+ return;
+
+ // Skip unknown targets.
+ if (!targetName.empty() && targetPrefix != targetName)
+ return;
+
+ StringRef defName = record.getName();
+ ArrayRef<SMLoc> defLoc = record.getLoc();
+
+ // Sanity check the input.
+ if (!defName.starts_with("int_"))
+ PrintFatalError(defLoc,
+ "Intrinsic '" + defName + "' does not start with 'int_'!");
+
+ StringRef enumName = defName.substr(4);
+
+ os << "llvm::Intrinsic::";
+ if (!targetName.empty())
+ os << StringRef(targetName).upper() << "Intrinsics::";
+ os << enumName << ",\n";
+}
+
+// Emit the list of LLVM IR intrinsics enums, both target and generic. Those
+// are used for LLVMImporter's convenience when looking at intrinsics while
+// being up-to-date with new additions to LLVM.
+static bool emitUnregisteredIntrinsics(const RecordKeeper &records,
+ raw_ostream &os, StringRef targetName) {
+
+ for (const Record *def : records.getAllDerivedDefinitions("Intrinsic"))
+ emitOneUnregisteredIntrinsic(*def, os, targetName);
+
+ return false;
+}
+
static mlir::GenRegistration
genLLVMIRConversions("gen-llvmir-conversions",
"Generate LLVM IR conversions", emitBuilders);
@@ -590,3 +631,19 @@ static mlir::GenRegistration genConvertibleLLVMIRIntrinsics(
"gen-convertible-llvmir-intrinsics",
"Generate list of convertible LLVM IR intrinsics",
emitConvertibleIntrinsics);
+
+static llvm::cl::OptionCategory
+ genUnregIntrinsicCat("Options for -gen-unregistered-llvmir-intrinsics");
+static llvm::cl::opt<std::string> unregIntrinsicPrefix(
+ "intrinsic-prefix",
+ cl::desc("Specify target to generate intrinsic information"),
+ cl::value_desc("target prefix"), cl::cat(genUnregIntrinsicCat));
+
+static mlir::GenRegistration genUnregisteredLLVMIRIntrinsics(
+ "gen-unregistered-llvmir-intrinsics",
+ "Generate enum list of target specific or generic intrinsics according to "
+ "enums defined in LLVM by other tablegen backends",
+ [](const RecordKeeper &records, raw_ostream &os) {
+ return emitUnregisteredIntrinsics(records, os,
+ unregIntrinsicPrefix.getValue());
+ });
\ No newline at end of file
More information about the Mlir-commits
mailing list