[clang] 40ae05d - [CIR] Return power-of-two ABI alignment for non-fundamental int widths (#210187)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Jul 17 07:07:51 PDT 2026
Author: adams381
Date: 2026-07-17T09:07:46-05:00
New Revision: 40ae05d4773f5c1b2a84ea7dc908d92671b8daa9
URL: https://github.com/llvm/llvm-project/commit/40ae05d4773f5c1b2a84ea7dc908d92671b8daa9
DIFF: https://github.com/llvm/llvm-project/commit/40ae05d4773f5c1b2a84ea7dc908d92671b8daa9.diff
LOG: [CIR] Return power-of-two ABI alignment for non-fundamental int widths (#210187)
`cir::IntType::getABIAlignment` returns `width / 8` for non-`_BitInt`
integers. For a non-fundamental width such as `i24` it returns 3, which
is
not a power of two, so a consumer that builds an `llvm::Align` from it
would
hit the power-of-two assertion unless it rounds the value up itself.
This rounds the alignment up to a power of two inside `getABIAlignment`,
matching how LLVM's default DataLayout aligns these (an `i24` aligns
like
`i32`). The fundamental widths are unchanged (`i8` -> 1, `i16` -> 2,
`i32` -> 4, `i64` -> 8), `__int128` stays at 16, and a sub-byte width
like
`i1` now reports 1 instead of 0. A unit test pins these cases.
Added:
clang/unittests/CIR/IntTypeABIAlignTest.cpp
Modified:
clang/lib/CIR/Dialect/IR/CIRTypes.cpp
clang/unittests/CIR/CMakeLists.txt
Removed:
################################################################################
diff --git a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
index 9c2a40e3681aa..afd3364af4ec2 100644
--- a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
@@ -809,7 +809,13 @@ uint64_t IntType::getABIAlignment(const mlir::DataLayout &dataLayout,
std::min(llvm::PowerOf2Ceil(width), static_cast<uint64_t>(64));
return std::max(alignBits / 8, static_cast<uint64_t>(1));
}
- return (uint64_t)(width / 8);
+ // Round up to a power-of-two byte alignment. DataLayout consumers such as
+ // llvm::Align require power-of-two alignments, and width / 8 is not a power
+ // of two for non-fundamental widths (e.g. i24 -> 3). This leaves the
+ // fundamental widths unchanged (i8 -> 1, i16 -> 2, i32 -> 4, i64 -> 8) and
+ // keeps __int128 at 16.
+ uint64_t alignBits = llvm::PowerOf2Ceil(width);
+ return std::max(alignBits / 8, static_cast<uint64_t>(1));
}
mlir::LogicalResult
diff --git a/clang/unittests/CIR/CMakeLists.txt b/clang/unittests/CIR/CMakeLists.txt
index a431356044cfc..446ca36fc39b0 100644
--- a/clang/unittests/CIR/CMakeLists.txt
+++ b/clang/unittests/CIR/CMakeLists.txt
@@ -6,6 +6,7 @@ include_directories(${MLIR_TABLEGEN_OUTPUT_DIR})
add_distinct_clang_unittest(CIRUnitTests
CallOpTest.cpp
ControlFlowTest.cpp
+ IntTypeABIAlignTest.cpp
PointerLikeTest.cpp
RecordTypeMetadataTest.cpp
UnionTypeSizeTest.cpp
diff --git a/clang/unittests/CIR/IntTypeABIAlignTest.cpp b/clang/unittests/CIR/IntTypeABIAlignTest.cpp
new file mode 100644
index 0000000000000..5fe0dc5bd2b4b
--- /dev/null
+++ b/clang/unittests/CIR/IntTypeABIAlignTest.cpp
@@ -0,0 +1,70 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Unit tests for IntType::getABIAlignment.
+//
+//===----------------------------------------------------------------------===//
+
+#include "mlir/IR/BuiltinOps.h"
+#include "mlir/IR/MLIRContext.h"
+#include "clang/CIR/Dialect/IR/CIRDialect.h"
+#include "clang/CIR/Dialect/IR/CIRTypes.h"
+#include "llvm/Support/MathExtras.h"
+#include "gtest/gtest.h"
+
+using namespace mlir;
+using namespace cir;
+
+namespace {
+
+class IntTypeABIAlignTest : public ::testing::Test {
+protected:
+ IntTypeABIAlignTest() { context.loadDialect<cir::CIRDialect>(); }
+
+ MLIRContext context;
+
+ uint64_t abiAlign(unsigned width, bool isSigned) {
+ IntType ty = IntType::get(&context, width, isSigned);
+ OpBuilder builder(&context);
+ auto module = ModuleOp::create(builder.getUnknownLoc());
+ mlir::DataLayout dl(module);
+ uint64_t align = dl.getTypeABIAlignment(ty);
+ module->erase();
+ return align;
+ }
+};
+
+// The fundamental integer widths keep their natural alignment.
+TEST_F(IntTypeABIAlignTest, FundamentalWidths) {
+ EXPECT_EQ(abiAlign(8, true), 1u);
+ EXPECT_EQ(abiAlign(16, true), 2u);
+ EXPECT_EQ(abiAlign(32, true), 4u);
+ EXPECT_EQ(abiAlign(64, true), 8u);
+}
+
+// __int128 is 16-byte aligned, so a 128-bit integer must not round down.
+TEST_F(IntTypeABIAlignTest, Int128) { EXPECT_EQ(abiAlign(128, true), 16u); }
+
+// A non-fundamental width must report a power-of-two alignment, not the bare
+// width / 8 (which would be 3 for i24 and trip llvm::Align). Rounding is on
+// the bit width, so a width that isn't a byte multiple still rounds up like
+// LLVM's DataLayout (i17 aligns like i32).
+TEST_F(IntTypeABIAlignTest, NonFundamentalWidthIsPowerOfTwo) {
+ for (unsigned width : {17u, 24u}) {
+ uint64_t align = abiAlign(width, true);
+ EXPECT_TRUE(llvm::isPowerOf2_64(align))
+ << "i" << width << " alignment " << align << " is not a power of two";
+ }
+ EXPECT_EQ(abiAlign(17, true), 4u);
+ EXPECT_EQ(abiAlign(24, true), 4u);
+}
+
+// A sub-byte width must still report a valid, non-zero alignment.
+TEST_F(IntTypeABIAlignTest, SubByteWidth) { EXPECT_EQ(abiAlign(1, true), 1u); }
+
+} // namespace
More information about the cfe-commits
mailing list