https://github.com/adams381 created 
https://github.com/llvm/llvm-project/pull/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.


>From 5106a63c70f646b67fe9389c1afef627316f5842 Mon Sep 17 00:00:00 2001
From: Adam Smith <[email protected]>
Date: Mon, 23 Mar 2026 11:31:49 -0700
Subject: [PATCH] [CIR][ABI] Add _BitInt flag to IntType

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) that the ABI lowering
pass needs to handle differently.

The flag is set during CIRGen for `Type::BitInt`, printed/parsed as
`!cir.int<s, 128, bitint>`, and excluded from `isFundamental()`.

Made-with: Cursor
---
 .../include/clang/CIR/Dialect/IR/CIRTypes.td  | 19 +++++++++--
 clang/lib/CIR/CodeGen/CIRGenTypes.cpp         |  3 +-
 clang/lib/CIR/Dialect/IR/CIRTypes.cpp         | 19 +++++++++--
 clang/test/CIR/CodeGen/bitint.c               | 32 +++++++++++++++++++
 .../CIR/CodeGenBuiltins/builtins-overflow.cpp | 30 ++++++++---------
 clang/test/CIR/IR/bitint.cir                  | 20 ++++++++++++
 clang/test/CIR/global-var-simple.cpp          |  4 +--
 7 files changed, 103 insertions(+), 24 deletions(-)
 create mode 100644 clang/test/CIR/CodeGen/bitint.c
 create mode 100644 clang/test/CIR/IR/bitint.cir

diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td 
b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
index 450c02135e033..f14d6099304ce 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
@@ -50,21 +50,34 @@ def CIR_IntType : CIR_Type<"Int", "int", [
     fundamental integer types. Said types are: `signed char`, `short`, `int`,
     `long`, `long long`, and their unsigned variations.
   }];
-  let parameters = (ins "unsigned":$width, "bool":$isSigned);
+  let parameters = (ins "unsigned":$width, "bool":$isSigned,
+                        DefaultValuedParameter<"bool", "false">:$bitInt);
+  let builders = [
+    TypeBuilder<(ins "unsigned":$width, "bool":$isSigned), [{
+      return $_get($_ctxt, width, isSigned, /*bitInt=*/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 getBitInt(); }
     /// 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 2092964bac065..c86ddbb44a501 100644
--- a/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenTypes.cpp
@@ -564,7 +564,8 @@ mlir::Type CIRGenTypes::convertType(QualType type) {
       resultType = cgm.sInt32Ty;
     } else {
       resultType = cir::IntType::get(&getMLIRContext(), bitIntTy->getNumBits(),
-                                     bitIntTy->isSigned());
+                                     bitIntTy->isSigned(),
+                                     /*bitInt=*/true);
     }
     break;
   }
diff --git a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp 
b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
index d96975b3e6aa7..1da59b7815ab5 100644
--- a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
@@ -499,15 +499,28 @@ Type IntType::parse(mlir::AsmParser &parser) {
     return {};
   }
 
+  bool bitInt = false;
+  if (succeeded(parser.parseOptionalComma())) {
+    llvm::StringRef kw;
+    if (parser.parseKeyword(&kw) || kw != "bitint") {
+      parser.emitError(loc, "expected 'bitint'");
+      return {};
+    }
+    bitInt = true;
+  }
+
   if (parser.parseGreater())
     return {};
 
-  return IntType::get(context, width, isSigned);
+  return IntType::get(context, width, isSigned, bitInt);
 }
 
 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
@@ -523,7 +536,7 @@ uint64_t IntType::getABIAlignment(const mlir::DataLayout 
&dataLayout,
 
 mlir::LogicalResult
 IntType::verify(llvm::function_ref<mlir::InFlightDiagnostic()> emitError,
-                unsigned width, bool isSigned) {
+                unsigned width, bool isSigned, bool bitInt) {
   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..1f02c6f3eaaba
--- /dev/null
+++ b/clang/test/CIR/CodeGen/bitint.c
@@ -0,0 +1,32 @@
+// 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>
+
+void take_bitint_32(_BitInt(32) x) {}
+// LLVM: define {{.*}} void @take_bitint_32(i32 {{.*}})
+// OGCG: define {{.*}} void @take_bitint_32(i32 {{.*}})
+
+void take_bitint_128(signed _BitInt(128) x) {}
+// LLVM: define {{.*}} void @take_bitint_128(i128 {{.*}})
+// OGCG: define {{.*}} void @take_bitint_128(i128 {{.*}})
+
+void take_unsigned_bitint(unsigned _BitInt(64) x) {}
+// 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) {}
+// 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