[Mlir-commits] [mlir] [mlir][ABI] Add ABITypeMapper and ABIRewriteContext (PR #190661)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Mon Apr 6 12:45:25 PDT 2026
https://github.com/adams381 updated https://github.com/llvm/llvm-project/pull/190661
>From 23ef4674ee8ac04d7777d5442071a781b8a09b7b Mon Sep 17 00:00:00 2001
From: Adam Smith <adams at nvidia.com>
Date: Mon, 6 Apr 2026 12:14:06 -0700
Subject: [PATCH] [mlir][ABI] Add ABITypeMapper and ABIRewriteContext
Dialect-agnostic layer bridging MLIR and the LLVM ABI library.
ABITypeMapper handles built-in MLIR types; ABIRewriteContext is
the interface dialects implement for ABI rewrites (see
clang/docs/ClangIRABILowering.md Section 4).
Made-with: Cursor
---
mlir/include/mlir/ABI/ABIRewriteContext.h | 159 +++++++++++++++++
mlir/include/mlir/ABI/ABITypeMapper.h | 66 +++++++
mlir/lib/ABI/ABITypeMapper.cpp | 102 +++++++++++
mlir/lib/ABI/CMakeLists.txt | 14 ++
mlir/lib/CMakeLists.txt | 1 +
mlir/unittests/ABI/ABIRewriteContextTest.cpp | 99 +++++++++++
mlir/unittests/ABI/ABITypeMapperTest.cpp | 173 +++++++++++++++++++
mlir/unittests/ABI/CMakeLists.txt | 12 ++
mlir/unittests/CMakeLists.txt | 1 +
9 files changed, 627 insertions(+)
create mode 100644 mlir/include/mlir/ABI/ABIRewriteContext.h
create mode 100644 mlir/include/mlir/ABI/ABITypeMapper.h
create mode 100644 mlir/lib/ABI/ABITypeMapper.cpp
create mode 100644 mlir/lib/ABI/CMakeLists.txt
create mode 100644 mlir/unittests/ABI/ABIRewriteContextTest.cpp
create mode 100644 mlir/unittests/ABI/ABITypeMapperTest.cpp
create mode 100644 mlir/unittests/ABI/CMakeLists.txt
diff --git a/mlir/include/mlir/ABI/ABIRewriteContext.h b/mlir/include/mlir/ABI/ABIRewriteContext.h
new file mode 100644
index 00000000000000..71d5a56b599b78
--- /dev/null
+++ b/mlir/include/mlir/ABI/ABIRewriteContext.h
@@ -0,0 +1,159 @@
+//===- ABIRewriteContext.h - Dialect-specific ABI rewriting -----*- 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 defines ABIRewriteContext, the abstract interface for dialect-
+// specific ABI lowering rewrites. Each MLIR dialect that wants ABI lowering
+// (CIR, FIR, etc.) provides a concrete subclass.
+//
+// ABIRewriteContext consumes ABI classification results and drives the
+// creation of lowered function signatures, argument coercions, and call
+// site rewrites using dialect-specific operations.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MLIR_ABI_ABIREWRITECONTEXT_H
+#define MLIR_ABI_ABIREWRITECONTEXT_H
+
+#include "mlir/IR/Builders.h"
+#include "mlir/IR/Operation.h"
+#include "mlir/IR/Types.h"
+#include "mlir/IR/Value.h"
+#include "mlir/Interfaces/FunctionInterfaces.h"
+#include "llvm/Support/Alignment.h"
+
+namespace mlir {
+namespace abi {
+
+/// Classification of how a single argument or return value should be
+/// passed at the ABI level.
+///
+/// This is a dialect-agnostic representation. It mirrors the kinds
+/// found in the LLVM ABI library and in CIR's ABIArgInfo, but does
+/// not depend on either.
+enum class ArgKind : uint8_t {
+ /// Pass directly in registers, possibly coerced to a different type.
+ Direct,
+
+ /// Like Direct, but with a sign/zero extension attribute.
+ Extend,
+
+ /// Pass indirectly via a pointer (sret for returns, byval for args).
+ Indirect,
+
+ /// Ignore (void return, empty struct).
+ Ignore,
+
+ /// Expand an aggregate into its constituent scalar fields.
+ Expand,
+};
+
+/// Describes how a single argument or return value is passed after ABI
+/// lowering.
+struct ArgClassification {
+ ArgKind Kind = ArgKind::Direct;
+
+ /// The ABI-coerced type, if different from the original. Null means
+ /// use the original type.
+ Type CoercedType = nullptr;
+
+ /// For Indirect: alignment of the pointed-to object.
+ llvm::Align IndirectAlign = llvm::Align(1);
+
+ /// For Extend: whether to sign-extend (true) or zero-extend (false).
+ bool SignExtend = false;
+
+ /// For Direct: whether a struct coercion can be flattened into
+ /// individual register-width arguments.
+ bool CanFlatten = true;
+
+ /// For Indirect: whether the callee gets ownership (byval).
+ bool ByVal = false;
+
+ static ArgClassification getDirect(Type coerced = nullptr) {
+ ArgClassification c;
+ c.Kind = ArgKind::Direct;
+ c.CoercedType = coerced;
+ return c;
+ }
+
+ static ArgClassification getIgnore() {
+ ArgClassification c;
+ c.Kind = ArgKind::Ignore;
+ return c;
+ }
+
+ static ArgClassification getIndirect(llvm::Align align, bool byVal = true) {
+ ArgClassification c;
+ c.Kind = ArgKind::Indirect;
+ c.IndirectAlign = align;
+ c.ByVal = byVal;
+ return c;
+ }
+
+ static ArgClassification getExtend(Type coerced, bool signExt) {
+ ArgClassification c;
+ c.Kind = ArgKind::Extend;
+ c.CoercedType = coerced;
+ c.SignExtend = signExt;
+ return c;
+ }
+};
+
+/// Holds the full ABI classification for a function: return type and
+/// all arguments.
+struct FunctionClassification {
+ ArgClassification ReturnInfo;
+ SmallVector<ArgClassification> ArgInfos;
+};
+
+/// ABIRewriteContext is the abstract interface that each dialect
+/// implements to perform ABI-specific rewrites on its operations.
+///
+/// The pass orchestrator calls these methods after ABI classification
+/// to rewrite function definitions and call sites.
+class ABIRewriteContext {
+public:
+ virtual ~ABIRewriteContext() = default;
+
+ /// Rewrite a function definition to use ABI-lowered types.
+ ///
+ /// This creates a new function with the lowered signature, rewrites
+ /// the function body to adapt between the ABI types and the
+ /// original high-level types, and replaces the original function.
+ ///
+ /// \param funcOp The function to rewrite (via FunctionOpInterface).
+ /// \param fc The ABI classification for this function.
+ /// \param rewriter The pattern rewriter to use for modifications.
+ /// \returns success() if the function was rewritten.
+ virtual LogicalResult
+ rewriteFunctionDefinition(FunctionOpInterface funcOp,
+ const FunctionClassification &fc,
+ OpBuilder &rewriter) = 0;
+
+ /// Rewrite a call operation to match the callee's ABI-lowered
+ /// signature.
+ ///
+ /// This coerces arguments, handles indirect returns (sret), and
+ /// adapts the call result back to the original high-level type.
+ ///
+ /// \param callOp The call operation to rewrite.
+ /// \param fc The ABI classification for the callee.
+ /// \param rewriter The pattern rewriter to use for modifications.
+ /// \returns success() if the call was rewritten.
+ virtual LogicalResult rewriteCallSite(Operation *callOp,
+ const FunctionClassification &fc,
+ OpBuilder &rewriter) = 0;
+
+ /// Return the dialect namespace this context handles (e.g. "cir").
+ virtual StringRef getDialectNamespace() const = 0;
+};
+
+} // namespace abi
+} // namespace mlir
+
+#endif // MLIR_ABI_ABIREWRITECONTEXT_H
diff --git a/mlir/include/mlir/ABI/ABITypeMapper.h b/mlir/include/mlir/ABI/ABITypeMapper.h
new file mode 100644
index 00000000000000..2180c9c8a918db
--- /dev/null
+++ b/mlir/include/mlir/ABI/ABITypeMapper.h
@@ -0,0 +1,66 @@
+//===- ABITypeMapper.h - Map MLIR types to ABI types -----------*- 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 defines ABITypeMapper, which translates mlir::Type instances into
+// the llvm::abi::Type hierarchy defined in llvm/ABI/Types.h. Dialect-specific
+// types are handled via MLIR's DataLayoutTypeInterface.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MLIR_ABI_ABITYPEMAPPER_H
+#define MLIR_ABI_ABITYPEMAPPER_H
+
+#include "mlir/IR/BuiltinTypes.h"
+#include "mlir/IR/Types.h"
+#include "mlir/Interfaces/DataLayoutInterfaces.h"
+#include "llvm/ABI/Types.h"
+#include "llvm/Support/Allocator.h"
+
+namespace mlir {
+namespace abi {
+
+/// ABITypeMapper translates mlir::Type values into the llvm::abi::Type
+/// hierarchy used by the LLVM ABI Lowering Library.
+///
+/// Standard MLIR types (IntegerType, FloatType, IndexType, VectorType,
+/// MemRefType) are mapped directly. Dialect-specific types are mapped
+/// by querying the MLIR DataLayout for size and alignment.
+///
+/// Callers must supply a DataLayout (typically from the enclosing module)
+/// so the mapper can determine sizes and alignments.
+///
+/// The mapper owns a BumpPtrAllocator; all returned abi::Type pointers
+/// are valid for the lifetime of the mapper.
+class ABITypeMapper {
+public:
+ explicit ABITypeMapper(const DataLayout &dl);
+
+ /// Map an MLIR type to its ABI type representation. Returns nullptr
+ /// if the type cannot be mapped.
+ const llvm::abi::Type *map(mlir::Type type);
+
+ /// Access the underlying TypeBuilder for advanced use.
+ llvm::abi::TypeBuilder &getTypeBuilder() { return Builder; }
+
+private:
+ const llvm::abi::Type *mapIntegerType(mlir::IntegerType type);
+ const llvm::abi::Type *mapFloatType(mlir::FloatType type);
+ const llvm::abi::Type *mapIndexType(mlir::IndexType type);
+ const llvm::abi::Type *mapVectorType(mlir::VectorType type);
+ const llvm::abi::Type *mapMemRefType(mlir::MemRefType type);
+ const llvm::abi::Type *mapNoneType(mlir::NoneType type);
+
+ const DataLayout &DL;
+ llvm::BumpPtrAllocator Allocator;
+ llvm::abi::TypeBuilder Builder;
+};
+
+} // namespace abi
+} // namespace mlir
+
+#endif // MLIR_ABI_ABITYPEMAPPER_H
diff --git a/mlir/lib/ABI/ABITypeMapper.cpp b/mlir/lib/ABI/ABITypeMapper.cpp
new file mode 100644
index 00000000000000..c7a69780bbe64f
--- /dev/null
+++ b/mlir/lib/ABI/ABITypeMapper.cpp
@@ -0,0 +1,102 @@
+//===- ABITypeMapper.cpp - Map MLIR types to ABI types --------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "mlir/ABI/ABITypeMapper.h"
+#include "llvm/ADT/APFloat.h"
+#include "llvm/Support/Alignment.h"
+
+using namespace mlir;
+using namespace mlir::abi;
+
+ABITypeMapper::ABITypeMapper(const DataLayout &dl)
+ : DL(dl), Builder(Allocator) {}
+
+const llvm::abi::Type *ABITypeMapper::map(mlir::Type type) {
+ if (auto intTy = dyn_cast<mlir::IntegerType>(type))
+ return mapIntegerType(intTy);
+
+ if (auto floatTy = dyn_cast<mlir::FloatType>(type))
+ return mapFloatType(floatTy);
+
+ if (auto indexTy = dyn_cast<mlir::IndexType>(type))
+ return mapIndexType(indexTy);
+
+ if (auto vecTy = dyn_cast<mlir::VectorType>(type))
+ return mapVectorType(vecTy);
+
+ if (auto memRefTy = dyn_cast<mlir::MemRefType>(type))
+ return mapMemRefType(memRefTy);
+
+ if (auto noneTy = dyn_cast<mlir::NoneType>(type))
+ return mapNoneType(noneTy);
+
+ // For dialect-specific types, fall back to DataLayout queries.
+ // The type must implement DataLayoutTypeInterface for this to work.
+ llvm::TypeSize sizeInBits = DL.getTypeSizeInBits(type);
+ uint64_t abiAlign = DL.getTypeABIAlignment(type);
+ return Builder.getIntegerType(sizeInBits.getFixedValue(),
+ llvm::Align(abiAlign),
+ /*Signed=*/false);
+}
+
+const llvm::abi::Type *ABITypeMapper::mapIntegerType(mlir::IntegerType type) {
+ uint64_t width = type.getWidth();
+ uint64_t abiAlign = DL.getTypeABIAlignment(type);
+ // MLIR signless integers are treated as signed for ABI purposes.
+ // Most C/C++ integer types are signless in MLIR but behave as
+ // signed for ABI classification (sign extension, etc.).
+ bool isSigned = type.isSigned() || type.isSignless();
+ return Builder.getIntegerType(width, llvm::Align(abiAlign), isSigned);
+}
+
+const llvm::abi::Type *ABITypeMapper::mapFloatType(mlir::FloatType type) {
+ uint64_t abiAlign = DL.getTypeABIAlignment(type);
+ const llvm::fltSemantics &semantics = type.getFloatSemantics();
+ return Builder.getFloatType(semantics, llvm::Align(abiAlign));
+}
+
+const llvm::abi::Type *ABITypeMapper::mapIndexType(mlir::IndexType type) {
+ llvm::TypeSize sizeInBits = DL.getTypeSizeInBits(type);
+ uint64_t abiAlign = DL.getTypeABIAlignment(type);
+ return Builder.getIntegerType(sizeInBits.getFixedValue(),
+ llvm::Align(abiAlign),
+ /*Signed=*/false);
+}
+
+const llvm::abi::Type *ABITypeMapper::mapVectorType(mlir::VectorType type) {
+ const llvm::abi::Type *elementTy = map(type.getElementType());
+ if (!elementTy)
+ return nullptr;
+
+ auto shape = type.getShape();
+ // MLIR VectorType is always fixed-length and can be multi-dimensional.
+ // Flatten to a single dimension for ABI purposes.
+ uint64_t totalElements = 1;
+ for (int64_t dim : shape)
+ totalElements *= dim;
+
+ llvm::ElementCount ec = llvm::ElementCount::getFixed(totalElements);
+ uint64_t abiAlign = DL.getTypeABIAlignment(type);
+ return Builder.getVectorType(elementTy, ec, llvm::Align(abiAlign));
+}
+
+const llvm::abi::Type *ABITypeMapper::mapMemRefType(mlir::MemRefType type) {
+ // MemRef is pointer-like for ABI purposes.
+ llvm::TypeSize sizeInBits = DL.getTypeSizeInBits(type);
+ uint64_t abiAlign = DL.getTypeABIAlignment(type);
+ unsigned addrSpace = 0;
+ if (auto as = type.getMemorySpace())
+ if (auto intAttr = dyn_cast<IntegerAttr>(as))
+ addrSpace = intAttr.getInt();
+ return Builder.getPointerType(sizeInBits.getFixedValue(),
+ llvm::Align(abiAlign), addrSpace);
+}
+
+const llvm::abi::Type *ABITypeMapper::mapNoneType(mlir::NoneType type) {
+ return Builder.getVoidType();
+}
diff --git a/mlir/lib/ABI/CMakeLists.txt b/mlir/lib/ABI/CMakeLists.txt
new file mode 100644
index 00000000000000..eb434d25dd390e
--- /dev/null
+++ b/mlir/lib/ABI/CMakeLists.txt
@@ -0,0 +1,14 @@
+add_mlir_library(MLIRABI
+ ABITypeMapper.cpp
+
+ ADDITIONAL_HEADER_DIRS
+ ${MLIR_MAIN_INCLUDE_DIR}/mlir/ABI
+
+ LINK_COMPONENTS
+ ABI
+ Support
+
+ LINK_LIBS PUBLIC
+ MLIRIR
+ MLIRDataLayoutInterfaces
+ )
diff --git a/mlir/lib/CMakeLists.txt b/mlir/lib/CMakeLists.txt
index 91ed05f6548d70..d7a6e28d985861 100644
--- a/mlir/lib/CMakeLists.txt
+++ b/mlir/lib/CMakeLists.txt
@@ -1,6 +1,7 @@
# Enable errors for any global constructors.
add_flag_if_supported("-Werror=global-constructors" WERROR_GLOBAL_CONSTRUCTOR)
+add_subdirectory(ABI)
add_subdirectory(Analysis)
add_subdirectory(AsmParser)
add_subdirectory(Bytecode)
diff --git a/mlir/unittests/ABI/ABIRewriteContextTest.cpp b/mlir/unittests/ABI/ABIRewriteContextTest.cpp
new file mode 100644
index 00000000000000..04c28991cc7527
--- /dev/null
+++ b/mlir/unittests/ABI/ABIRewriteContextTest.cpp
@@ -0,0 +1,99 @@
+//===- ABIRewriteContextTest.cpp - Unit tests for ABIRewriteContext -------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "mlir/ABI/ABIRewriteContext.h"
+#include <gtest/gtest.h>
+
+using namespace mlir;
+using namespace mlir::abi;
+
+namespace {
+
+class MockRewriteContext : public ABIRewriteContext {
+public:
+ LogicalResult rewriteFunctionDefinition(FunctionOpInterface,
+ const FunctionClassification &,
+ OpBuilder &) override {
+ return success();
+ }
+
+ LogicalResult rewriteCallSite(Operation *, const FunctionClassification &,
+ OpBuilder &) override {
+ return success();
+ }
+
+ StringRef getDialectNamespace() const override { return "mock"; }
+};
+
+TEST(ABIRewriteContextTest, MockCanBeConstructedAndDestroyed) {
+ MockRewriteContext ctx;
+ EXPECT_EQ(ctx.getDialectNamespace(), "mock");
+}
+
+TEST(ABIRewriteContextTest, ArgClassificationDirect) {
+ auto c = ArgClassification::getDirect();
+ EXPECT_EQ(c.Kind, ArgKind::Direct);
+ EXPECT_EQ(c.CoercedType, nullptr);
+ EXPECT_TRUE(c.CanFlatten);
+}
+
+TEST(ABIRewriteContextTest, ArgClassificationDirectWithType) {
+ MLIRContext mlirCtx;
+ auto i32 = IntegerType::get(&mlirCtx, 32);
+ auto c = ArgClassification::getDirect(i32);
+ EXPECT_EQ(c.Kind, ArgKind::Direct);
+ EXPECT_EQ(c.CoercedType, i32);
+}
+
+TEST(ABIRewriteContextTest, ArgClassificationIgnore) {
+ auto c = ArgClassification::getIgnore();
+ EXPECT_EQ(c.Kind, ArgKind::Ignore);
+}
+
+TEST(ABIRewriteContextTest, ArgClassificationIndirect) {
+ auto c = ArgClassification::getIndirect(llvm::Align(8), true);
+ EXPECT_EQ(c.Kind, ArgKind::Indirect);
+ EXPECT_EQ(c.IndirectAlign, llvm::Align(8));
+ EXPECT_TRUE(c.ByVal);
+}
+
+TEST(ABIRewriteContextTest, ArgClassificationIndirectNoByVal) {
+ auto c = ArgClassification::getIndirect(llvm::Align(16), false);
+ EXPECT_EQ(c.Kind, ArgKind::Indirect);
+ EXPECT_EQ(c.IndirectAlign, llvm::Align(16));
+ EXPECT_FALSE(c.ByVal);
+}
+
+TEST(ABIRewriteContextTest, ArgClassificationExtend) {
+ MLIRContext mlirCtx;
+ auto i8 = IntegerType::get(&mlirCtx, 8);
+
+ auto signExt = ArgClassification::getExtend(i8, true);
+ EXPECT_EQ(signExt.Kind, ArgKind::Extend);
+ EXPECT_TRUE(signExt.SignExtend);
+
+ auto zeroExt = ArgClassification::getExtend(i8, false);
+ EXPECT_EQ(zeroExt.Kind, ArgKind::Extend);
+ EXPECT_FALSE(zeroExt.SignExtend);
+}
+
+TEST(ABIRewriteContextTest, FunctionClassificationHoldsReturnAndArgs) {
+ FunctionClassification fc;
+ fc.ReturnInfo = ArgClassification::getDirect();
+ fc.ArgInfos.push_back(ArgClassification::getDirect());
+ fc.ArgInfos.push_back(ArgClassification::getIndirect(llvm::Align(8), true));
+ fc.ArgInfos.push_back(ArgClassification::getIgnore());
+
+ EXPECT_EQ(fc.ReturnInfo.Kind, ArgKind::Direct);
+ EXPECT_EQ(fc.ArgInfos.size(), 3u);
+ EXPECT_EQ(fc.ArgInfos[0].Kind, ArgKind::Direct);
+ EXPECT_EQ(fc.ArgInfos[1].Kind, ArgKind::Indirect);
+ EXPECT_EQ(fc.ArgInfos[2].Kind, ArgKind::Ignore);
+}
+
+} // namespace
diff --git a/mlir/unittests/ABI/ABITypeMapperTest.cpp b/mlir/unittests/ABI/ABITypeMapperTest.cpp
new file mode 100644
index 00000000000000..4a7989298a149b
--- /dev/null
+++ b/mlir/unittests/ABI/ABITypeMapperTest.cpp
@@ -0,0 +1,173 @@
+//===- ABITypeMapperTest.cpp - Unit tests for ABITypeMapper ---------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "mlir/ABI/ABITypeMapper.h"
+#include "mlir/Dialect/DLTI/DLTI.h"
+#include "mlir/IR/Builders.h"
+#include "mlir/IR/BuiltinOps.h"
+#include "mlir/IR/BuiltinTypes.h"
+#include "mlir/IR/MLIRContext.h"
+#include "mlir/Interfaces/DataLayoutInterfaces.h"
+#include "llvm/ABI/Types.h"
+
+#include <gtest/gtest.h>
+
+using namespace mlir;
+using namespace mlir::abi;
+
+namespace {
+
+class ABITypeMapperTest : public ::testing::Test {
+protected:
+ void SetUp() override {
+ ctx.loadDialect<DLTIDialect>();
+ module = ModuleOp::create(UnknownLoc::get(&ctx));
+ }
+
+ void TearDown() override { module->destroy(); }
+
+ MLIRContext ctx;
+ ModuleOp module;
+};
+
+TEST_F(ABITypeMapperTest, MapI32) {
+ DataLayout dl(module);
+ ABITypeMapper mapper(dl);
+
+ auto i32 = IntegerType::get(&ctx, 32);
+ const llvm::abi::Type *result = mapper.map(i32);
+
+ ASSERT_NE(result, nullptr);
+ EXPECT_TRUE(result->isInteger());
+
+ auto *intTy = llvm::cast<llvm::abi::IntegerType>(result);
+ EXPECT_EQ(intTy->getSizeInBits().getFixedValue(), 32u);
+}
+
+TEST_F(ABITypeMapperTest, MapI1) {
+ DataLayout dl(module);
+ ABITypeMapper mapper(dl);
+
+ auto i1 = IntegerType::get(&ctx, 1);
+ const llvm::abi::Type *result = mapper.map(i1);
+
+ ASSERT_NE(result, nullptr);
+ EXPECT_TRUE(result->isInteger());
+
+ auto *intTy = llvm::cast<llvm::abi::IntegerType>(result);
+ EXPECT_EQ(intTy->getSizeInBits().getFixedValue(), 1u);
+}
+
+TEST_F(ABITypeMapperTest, MapI64) {
+ DataLayout dl(module);
+ ABITypeMapper mapper(dl);
+
+ auto i64 = IntegerType::get(&ctx, 64);
+ const llvm::abi::Type *result = mapper.map(i64);
+
+ ASSERT_NE(result, nullptr);
+ EXPECT_TRUE(result->isInteger());
+
+ auto *intTy = llvm::cast<llvm::abi::IntegerType>(result);
+ EXPECT_EQ(intTy->getSizeInBits().getFixedValue(), 64u);
+}
+
+TEST_F(ABITypeMapperTest, MapF32) {
+ DataLayout dl(module);
+ ABITypeMapper mapper(dl);
+
+ auto f32 = Float32Type::get(&ctx);
+ const llvm::abi::Type *result = mapper.map(f32);
+
+ ASSERT_NE(result, nullptr);
+ EXPECT_TRUE(result->isFloat());
+
+ auto *floatTy = llvm::cast<llvm::abi::FloatType>(result);
+ EXPECT_EQ(floatTy->getSizeInBits().getFixedValue(), 32u);
+}
+
+TEST_F(ABITypeMapperTest, MapF64) {
+ DataLayout dl(module);
+ ABITypeMapper mapper(dl);
+
+ auto f64 = Float64Type::get(&ctx);
+ const llvm::abi::Type *result = mapper.map(f64);
+
+ ASSERT_NE(result, nullptr);
+ EXPECT_TRUE(result->isFloat());
+
+ auto *floatTy = llvm::cast<llvm::abi::FloatType>(result);
+ EXPECT_EQ(floatTy->getSizeInBits().getFixedValue(), 64u);
+}
+
+TEST_F(ABITypeMapperTest, MapF16) {
+ DataLayout dl(module);
+ ABITypeMapper mapper(dl);
+
+ auto f16 = Float16Type::get(&ctx);
+ const llvm::abi::Type *result = mapper.map(f16);
+
+ ASSERT_NE(result, nullptr);
+ EXPECT_TRUE(result->isFloat());
+
+ auto *floatTy = llvm::cast<llvm::abi::FloatType>(result);
+ EXPECT_EQ(floatTy->getSizeInBits().getFixedValue(), 16u);
+}
+
+TEST_F(ABITypeMapperTest, MapNoneType) {
+ DataLayout dl(module);
+ ABITypeMapper mapper(dl);
+
+ auto none = NoneType::get(&ctx);
+ const llvm::abi::Type *result = mapper.map(none);
+
+ ASSERT_NE(result, nullptr);
+ EXPECT_TRUE(result->isVoid());
+}
+
+TEST_F(ABITypeMapperTest, MapVectorOf4xF32) {
+ DataLayout dl(module);
+ ABITypeMapper mapper(dl);
+
+ auto f32 = Float32Type::get(&ctx);
+ auto vec = VectorType::get({4}, f32);
+ const llvm::abi::Type *result = mapper.map(vec);
+
+ ASSERT_NE(result, nullptr);
+ EXPECT_TRUE(result->isVector());
+
+ auto *vecTy = llvm::cast<llvm::abi::VectorType>(result);
+ EXPECT_EQ(vecTy->getNumElements().getFixedValue(), 4u);
+ EXPECT_TRUE(vecTy->getElementType()->isFloat());
+}
+
+TEST_F(ABITypeMapperTest, MapSignedI32) {
+ DataLayout dl(module);
+ ABITypeMapper mapper(dl);
+
+ auto si32 = IntegerType::get(&ctx, 32, IntegerType::Signed);
+ const llvm::abi::Type *result = mapper.map(si32);
+
+ ASSERT_NE(result, nullptr);
+ auto *intTy = llvm::cast<llvm::abi::IntegerType>(result);
+ EXPECT_TRUE(intTy->isSigned());
+}
+
+TEST_F(ABITypeMapperTest, MapUnsignedI32) {
+ DataLayout dl(module);
+ ABITypeMapper mapper(dl);
+
+ auto ui32 = IntegerType::get(&ctx, 32, IntegerType::Unsigned);
+ const llvm::abi::Type *result = mapper.map(ui32);
+
+ ASSERT_NE(result, nullptr);
+ auto *intTy = llvm::cast<llvm::abi::IntegerType>(result);
+ EXPECT_FALSE(intTy->isSigned());
+}
+
+} // namespace
diff --git a/mlir/unittests/ABI/CMakeLists.txt b/mlir/unittests/ABI/CMakeLists.txt
new file mode 100644
index 00000000000000..39f955a8efea6c
--- /dev/null
+++ b/mlir/unittests/ABI/CMakeLists.txt
@@ -0,0 +1,12 @@
+add_mlir_unittest(MLIRABITests
+ ABIRewriteContextTest.cpp
+ ABITypeMapperTest.cpp
+)
+
+mlir_target_link_libraries(MLIRABITests
+ PRIVATE
+ MLIRABI
+ MLIRDataLayoutInterfaces
+ MLIRDLTIDialect
+ MLIRIR
+)
diff --git a/mlir/unittests/CMakeLists.txt b/mlir/unittests/CMakeLists.txt
index 89332bce5fe05b..654ec44d90b044 100644
--- a/mlir/unittests/CMakeLists.txt
+++ b/mlir/unittests/CMakeLists.txt
@@ -5,6 +5,7 @@ function(add_mlir_unittest test_dirname)
add_unittest(MLIRUnitTests ${test_dirname} ${ARGN})
endfunction()
+add_subdirectory(ABI)
add_subdirectory(Analysis)
add_subdirectory(Bytecode)
add_subdirectory(Conversion)
More information about the Mlir-commits
mailing list