Author: adams381
Date: 2026-04-08T06:19:04-07:00
New Revision: 73e2b0e64186e2386d777e936c92bb25a995a0f4

URL: 
https://github.com/llvm/llvm-project/commit/73e2b0e64186e2386d777e936c92bb25a995a0f4
DIFF: 
https://github.com/llvm/llvm-project/commit/73e2b0e64186e2386d777e936c92bb25a995a0f4.diff

LOG: [CIR][ABI] Add _BitInt flag to IntType (#188113)

Add an optional `bitint` parameter to `cir::IntType` so CIR can
distinguish `_BitInt(N)` from builtin integer types like `__int128`.
Both lower to the same LLVM integer type, but they have different ABI
rules (alignment, passing convention) on x86_64.

The flag is set during CIRGen for `Type::BitInt`, printed/parsed as
`!cir.int<s, 128, bitint>`, and excluded from `isFundamental()`.
Existing 2-arg `IntType::get()` calls continue to work via a default
parameter.

Added: 
    clang/test/CIR/CodeGen/bitint.c
    clang/test/CIR/IR/bitint.cir

Modified: 
    clang/include/clang/CIR/Dialect/IR/CIRTypes.td
    clang/lib/CIR/CodeGen/CIRGenTypes.cpp
    clang/lib/CIR/Dialect/IR/CIRTypes.cpp
    clang/test/CIR/CodeGenBuiltins/builtins-overflow.cpp
    clang/test/CIR/global-var-simple.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td 
b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
index 5433d4fa7fd76..778f9bfdfd0c1 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
@@ -49,22 +49,37 @@ def CIR_IntType : CIR_Type<"Int", "int", [
     Those integer types that are directly available in C/C++ standard are 
called
     fundamental integer types. Said types are: `signed char`, `short`, `int`,
     `long`, `long long`, and their unsigned variations.
+
+    Examples: `!cir.int<s, 32>`, `!cir.int<u, 64>`, `!cir.int<s, 128, bitint>`
   }];
-  let parameters = (ins "unsigned":$width, "bool":$isSigned);
+  let parameters = (ins "unsigned":$width, "bool":$is_signed,
+                        DefaultValuedParameter<"bool", "false">:$is_bit_int);
+  let builders = [
+    TypeBuilder<(ins "unsigned":$width, "bool":$is_signed), [{
+      return $_get($_ctxt, width, is_signed, /*is_bit_int=*/false);
+    }]>,
+  ];
   let hasCustomAssemblyFormat = 1;
   let extraClassDeclaration = [{
     /// Return true if this is a signed integer type.
     bool isSigned() const { return getIsSigned(); }
     /// Return true if this is an unsigned integer type.
     bool isUnsigned() const { return !getIsSigned(); }
+    /// Return true if this is a _BitInt type.
+    bool isBitInt() const { return getIsBitInt(); }
     /// Return type alias.
     std::string getAlias() const {
-      return (isSigned() ? 's' : 'u') + std::to_string(getWidth()) + 'i';
+      std::string alias =
+          (isSigned() ? 's' : 'u') + std::to_string(getWidth()) + 'i';
+      if (isBitInt())
+        alias += "_bitint";
+      return alias;
     }
     /// Return true if this is a fundamental integer type (i.e. signed or
     /// unsigned integer types whose bit width is 8, 16, 32, or 64).
+    /// _BitInt types are never fundamental even if their width matches.
     bool isFundamental() const {
-      return isFundamentalIntType(*this);
+      return !isBitInt() && isFundamentalIntType(*this);
     }
     bool isSignedFundamental() const {
       return isFundamentalSIntType(*this);

diff  --git a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp 
b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
index 2f783ba2f2999..9b493263b76c2 100644
--- a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
@@ -568,7 +568,8 @@ mlir::Type CIRGenTypes::convertType(QualType type) {
       resultType = cgm.sInt32Ty;
     } else {
       resultType = cir::IntType::get(&getMLIRContext(), bitIntTy->getNumBits(),
-                                     bitIntTy->isSigned());
+                                     bitIntTy->isSigned(),
+                                     /*isBitInt=*/true);
     }
     break;
   }

diff  --git a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp 
b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
index b637484ac93d1..466064d783f2c 100644
--- a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
@@ -26,6 +26,7 @@
 #include "llvm/ADT/APInt.h"
 #include "llvm/ADT/APSInt.h"
 #include "llvm/ADT/TypeSwitch.h"
+#include "llvm/Support/MathExtras.h"
 
 
//===----------------------------------------------------------------------===//
 // CIR Helpers
@@ -541,15 +542,28 @@ Type IntType::parse(mlir::AsmParser &parser) {
     return {};
   }
 
+  bool isBitInt = false;
+  if (succeeded(parser.parseOptionalComma())) {
+    llvm::StringRef kw;
+    if (parser.parseKeyword(&kw) || kw != "bitint") {
+      parser.emitError(loc, "expected 'bitint'");
+      return {};
+    }
+    isBitInt = true;
+  }
+
   if (parser.parseGreater())
     return {};
 
-  return IntType::get(context, width, isSigned);
+  return IntType::get(context, width, isSigned, isBitInt);
 }
 
 void IntType::print(mlir::AsmPrinter &printer) const {
   char sign = isSigned() ? 's' : 'u';
-  printer << '<' << sign << ", " << getWidth() << '>';
+  printer << '<' << sign << ", " << getWidth();
+  if (isBitInt())
+    printer << ", bitint";
+  printer << '>';
 }
 
 llvm::TypeSize
@@ -560,12 +574,20 @@ IntType::getTypeSizeInBits(const mlir::DataLayout 
&dataLayout,
 
 uint64_t IntType::getABIAlignment(const mlir::DataLayout &dataLayout,
                                   mlir::DataLayoutEntryListRef params) const {
-  return (uint64_t)(getWidth() / 8);
+  unsigned width = getWidth();
+  if (isBitInt()) {
+    // _BitInt alignment: min(PowerOf2Ceil(width), 64 bits) in bytes.
+    // Matches Clang's TargetInfo::getBitIntAlign with default max = 64.
+    uint64_t alignBits =
+        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);
 }
 
 mlir::LogicalResult
 IntType::verify(llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
-                unsigned width, bool isSigned) {
+                unsigned width, bool isSigned, bool isBitInt) {
   if (width < IntType::minBitwidth() || width > IntType::maxBitwidth())
     return emitError() << "IntType only supports widths from "
                        << IntType::minBitwidth() << " up to "

diff  --git a/clang/test/CIR/CodeGen/bitint.c b/clang/test/CIR/CodeGen/bitint.c
new file mode 100644
index 0000000000000..014b315c907ba
--- /dev/null
+++ b/clang/test/CIR/CodeGen/bitint.c
@@ -0,0 +1,49 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o 
%t.cir
+// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o 
%t-cir.ll
+// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
+// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s
+
+// _BitInt types are distinguished from regular integer types via the
+// "bitint" keyword in CIR.  Verify that the type alias includes "_bitint"
+// and that regular __int128 does not.
+
+// CIR-DAG: !s32i_bitint = !cir.int<s, 32, bitint>
+// CIR-DAG: !s128i_bitint = !cir.int<s, 128, bitint>
+// CIR-DAG: !u64i_bitint = !cir.int<u, 64, bitint>
+// CIR-DAG: !s128i = !cir.int<s, 128>
+
+// _BitInt(128) has alignment 8 while __int128 has alignment 16.
+signed _BitInt(128) bitint128_var;
+__int128 int128_var;
+
+// CIR: cir.global external @bitint128_var = #cir.int<0> : !s128i_bitint 
{alignment = 8 : i64}
+// CIR: cir.global external @int128_var = #cir.int<0> : !s128i {alignment = 16 
: i64}
+
+// LLVM: @bitint128_var = global i128 0, align 8
+// LLVM: @int128_var = global i128 0, align 16
+
+// OGCG: @bitint128_var = global i128 0, align 8
+// OGCG: @int128_var = global i128 0, align 16
+
+void take_bitint_32(_BitInt(32) x) {}
+// CIR: cir.func {{.*}} @take_bitint_32(%arg0: !s32i_bitint
+// LLVM: define {{.*}} void @take_bitint_32(i32 {{.*}})
+// OGCG: define {{.*}} void @take_bitint_32(i32 {{.*}})
+
+void take_bitint_128(signed _BitInt(128) x) {}
+// CIR: cir.func {{.*}} @take_bitint_128(%arg0: !s128i_bitint
+// LLVM: define {{.*}} void @take_bitint_128(i128 {{.*}})
+// OGCG: define {{.*}} void @take_bitint_128(i128 {{.*}})
+
+void take_unsigned_bitint(unsigned _BitInt(64) x) {}
+// CIR: cir.func {{.*}} @take_unsigned_bitint(%arg0: !u64i_bitint
+// LLVM: define {{.*}} void @take_unsigned_bitint(i64 {{.*}})
+// OGCG: define {{.*}} void @take_unsigned_bitint(i64 {{.*}})
+
+// Regular __int128 should NOT have the bitint flag.
+void take_int128(__int128 x) {}
+// CIR: cir.func {{.*}} @take_int128(%arg0: !s128i
+// LLVM: define {{.*}} void @take_int128(i128 {{.*}})
+// OGCG: define {{.*}} void @take_int128(i128 {{.*}})

diff  --git a/clang/test/CIR/CodeGenBuiltins/builtins-overflow.cpp 
b/clang/test/CIR/CodeGenBuiltins/builtins-overflow.cpp
index 1c674ff5a297a..8089a538d733b 100644
--- a/clang/test/CIR/CodeGenBuiltins/builtins-overflow.cpp
+++ b/clang/test/CIR/CodeGenBuiltins/builtins-overflow.cpp
@@ -40,11 +40,11 @@ bool test_add_overflow_xint31_xint31_xint31(_BitInt(31) x, 
_BitInt(31) y, _BitIn
 }
 
 //      CIR: cir.func {{.*}} 
@_Z38test_add_overflow_xint31_xint31_xint31DB31_S_PS_
-//      CIR:   %[[#LHS:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.int<s, 
31>>, !cir.int<s, 31>
-// CIR-NEXT:   %[[#RHS:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.int<s, 
31>>, !cir.int<s, 31>
-// CIR-NEXT:   %[[#RES_PTR:]] = cir.load{{.*}} %{{.+}} : 
!cir.ptr<!cir.ptr<!cir.int<s, 31>>>, !cir.ptr<!cir.int<s, 31>>
-// CIR-NEXT:   %[[RES:.+]], %{{.+}} = cir.add.overflow %[[#LHS]], %[[#RHS]] : 
!cir.int<s, 31> -> !cir.int<s, 31>
-// CIR-NEXT:   cir.store{{.*}} %[[RES]], %[[#RES_PTR]] : !cir.int<s, 31>, 
!cir.ptr<!cir.int<s, 31>>
+//      CIR:   %[[#LHS:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.int<s, 31, 
bitint>>, !cir.int<s, 31, bitint>
+// CIR-NEXT:   %[[#RHS:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.int<s, 31, 
bitint>>, !cir.int<s, 31, bitint>
+// CIR-NEXT:   %[[#RES_PTR:]] = cir.load{{.*}} %{{.+}} : 
!cir.ptr<!cir.ptr<!cir.int<s, 31, bitint>>>, !cir.ptr<!cir.int<s, 31, bitint>>
+//      CIR:   %[[RES:.+]], %{{.+}} = cir.add.overflow %{{.+}}, %{{.+}} : 
!cir.int<s, 31> -> !cir.int<s, 31, bitint>
+// CIR-NEXT:   cir.store{{.*}} %[[RES]], %[[#RES_PTR]] : !cir.int<s, 31, 
bitint>, !cir.ptr<!cir.int<s, 31, bitint>>
 //      CIR: }
 
 bool test_sub_overflow_uint_uint_uint(unsigned x, unsigned y, unsigned *res) {
@@ -76,11 +76,11 @@ bool test_sub_overflow_xint31_xint31_xint31(_BitInt(31) x, 
_BitInt(31) y, _BitIn
 }
 
 //      CIR: cir.func {{.*}} 
@_Z38test_sub_overflow_xint31_xint31_xint31DB31_S_PS_
-//      CIR:   %[[#LHS:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.int<s, 
31>>, !cir.int<s, 31>
-// CIR-NEXT:   %[[#RHS:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.int<s, 
31>>, !cir.int<s, 31>
-// CIR-NEXT:   %[[#RES_PTR:]] = cir.load{{.*}} %{{.+}} : 
!cir.ptr<!cir.ptr<!cir.int<s, 31>>>, !cir.ptr<!cir.int<s, 31>>
-// CIR-NEXT:   %[[RES:.+]], %{{.+}} = cir.sub.overflow %[[#LHS]], %[[#RHS]] : 
!cir.int<s, 31> -> !cir.int<s, 31>
-// CIR-NEXT:   cir.store{{.*}} %[[RES]], %[[#RES_PTR]] : !cir.int<s, 31>, 
!cir.ptr<!cir.int<s, 31>>
+//      CIR:   %[[#LHS:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.int<s, 31, 
bitint>>, !cir.int<s, 31, bitint>
+// CIR-NEXT:   %[[#RHS:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.int<s, 31, 
bitint>>, !cir.int<s, 31, bitint>
+// CIR-NEXT:   %[[#RES_PTR:]] = cir.load{{.*}} %{{.+}} : 
!cir.ptr<!cir.ptr<!cir.int<s, 31, bitint>>>, !cir.ptr<!cir.int<s, 31, bitint>>
+//      CIR:   %[[RES:.+]], %{{.+}} = cir.sub.overflow %{{.+}}, %{{.+}} : 
!cir.int<s, 31> -> !cir.int<s, 31, bitint>
+// CIR-NEXT:   cir.store{{.*}} %[[RES]], %[[#RES_PTR]] : !cir.int<s, 31, 
bitint>, !cir.ptr<!cir.int<s, 31, bitint>>
 //      CIR: }
 
 bool test_mul_overflow_uint_uint_uint(unsigned x, unsigned y, unsigned *res) {
@@ -112,11 +112,11 @@ bool test_mul_overflow_xint31_xint31_xint31(_BitInt(31) 
x, _BitInt(31) y, _BitIn
 }
 
 //      CIR: cir.func {{.*}} 
@_Z38test_mul_overflow_xint31_xint31_xint31DB31_S_PS_
-//      CIR:   %[[#LHS:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.int<s, 
31>>, !cir.int<s, 31>
-// CIR-NEXT:   %[[#RHS:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.int<s, 
31>>, !cir.int<s, 31>
-// CIR-NEXT:   %[[#RES_PTR:]] = cir.load{{.*}} %{{.+}} : 
!cir.ptr<!cir.ptr<!cir.int<s, 31>>>, !cir.ptr<!cir.int<s, 31>>
-// CIR-NEXT:   %[[RES:.+]], %{{.+}} = cir.mul.overflow %[[#LHS]], %[[#RHS]] : 
!cir.int<s, 31> -> !cir.int<s, 31>
-// CIR-NEXT:   cir.store{{.*}} %[[RES]], %[[#RES_PTR]] : !cir.int<s, 31>, 
!cir.ptr<!cir.int<s, 31>>
+//      CIR:   %[[#LHS:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.int<s, 31, 
bitint>>, !cir.int<s, 31, bitint>
+// CIR-NEXT:   %[[#RHS:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.int<s, 31, 
bitint>>, !cir.int<s, 31, bitint>
+// CIR-NEXT:   %[[#RES_PTR:]] = cir.load{{.*}} %{{.+}} : 
!cir.ptr<!cir.ptr<!cir.int<s, 31, bitint>>>, !cir.ptr<!cir.int<s, 31, bitint>>
+//      CIR:   %[[RES:.+]], %{{.+}} = cir.mul.overflow %{{.+}}, %{{.+}} : 
!cir.int<s, 31> -> !cir.int<s, 31, bitint>
+// CIR-NEXT:   cir.store{{.*}} %[[RES]], %[[#RES_PTR]] : !cir.int<s, 31, 
bitint>, !cir.ptr<!cir.int<s, 31, bitint>>
 //      CIR: }
 
 bool test_mul_overflow_ulong_ulong_long(unsigned long x, unsigned long y, 
unsigned long *res) {

diff  --git a/clang/test/CIR/IR/bitint.cir b/clang/test/CIR/IR/bitint.cir
new file mode 100644
index 0000000000000..5dddddc833777
--- /dev/null
+++ b/clang/test/CIR/IR/bitint.cir
@@ -0,0 +1,20 @@
+// RUN: cir-opt %s -o %t.cir
+// RUN: FileCheck --input-file=%t.cir %s
+
+!s32i = !cir.int<s, 32>
+!s32i_bitint = !cir.int<s, 32, bitint>
+!u64i_bitint = !cir.int<u, 64, bitint>
+!s128i_bitint = !cir.int<s, 128, bitint>
+
+module {
+  // CHECK: cir.func @round_trip_bitint(%arg0: !s32i_bitint, %arg1: 
!u64i_bitint, %arg2: !s128i_bitint)
+  cir.func @round_trip_bitint(%arg0: !s32i_bitint, %arg1: !u64i_bitint, %arg2: 
!s128i_bitint) {
+    cir.return
+  }
+
+  // Regular int should NOT print bitint.
+  // CHECK: cir.func @round_trip_regular(%arg0: !s32i)
+  cir.func @round_trip_regular(%arg0: !s32i) {
+    cir.return
+  }
+}

diff  --git a/clang/test/CIR/global-var-simple.cpp 
b/clang/test/CIR/global-var-simple.cpp
index 4608089058fb4..68e44c926110c 100644
--- a/clang/test/CIR/global-var-simple.cpp
+++ b/clang/test/CIR/global-var-simple.cpp
@@ -53,10 +53,10 @@ char32_t c32;
 // CHECK: cir.global external @c32 = #cir.int<0> : !u32i
 
 _BitInt(20) sb20;
-// CHECK: cir.global external @sb20 = #cir.int<0> : !cir.int<s, 20>
+// CHECK: cir.global external @sb20 = #cir.int<0> : !cir.int<s, 20, bitint>
 
 unsigned _BitInt(48) ub48;
-// CHECK: cir.global external @ub48 = #cir.int<0> : !cir.int<u, 48>
+// CHECK: cir.global external @ub48 = #cir.int<0> : !cir.int<u, 48, bitint>
 
 bool boolfalse = false;
 // CHECK: cir.global external @boolfalse = #false


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

Reply via email to