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


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to