[clang] [CIR] Accept _BitInt up to 128 bits in x86_64 callconv lowering (PR #212668)

Adam Smith via cfe-commits cfe-commits at lists.llvm.org
Thu Jul 30 11:48:19 PDT 2026


================
@@ -0,0 +1,230 @@
+// RUN: cir-opt %s -cir-call-conv-lowering=target=x86_64 | FileCheck %s
+// RUN: cir-opt %s -cir-call-conv-lowering=target=x86_64 -cir-to-llvm -o - 2>/dev/null \
+// RUN:   | mlir-translate -mlir-to-llvmir --allow-unregistered-dialect \
+// RUN:   | FileCheck %s --check-prefix=LLVM
+
+!b17i = !cir.int<s, 17, bitint>
+!ub17i = !cir.int<u, 17, bitint>
+!b32i = !cir.int<s, 32, bitint>
+!b33i = !cir.int<s, 33, bitint>
+!ub33i = !cir.int<u, 33, bitint>
+!b40i = !cir.int<s, 40, bitint>
+!b63i = !cir.int<s, 63, bitint>
+!b64i = !cir.int<s, 64, bitint>
+!b65i = !cir.int<s, 65, bitint>
+!ub65i = !cir.int<u, 65, bitint>
+!b127i = !cir.int<s, 127, bitint>
+!b128i = !cir.int<s, 128, bitint>
+!s8i = !cir.int<s, 8>
+!rec_S = !cir.struct<"S" {!b17i}>
+!rec_P = !cir.struct<"P" {!b65i}>
+!rec_W = !cir.struct<"W" {!b128i}>
+!rec_O = !cir.struct<"O" {!b128i, !s8i}>
+!rec_Arr = !cir.struct<"Arr" {!cir.array<!b65i x 2>}>
+
+module attributes {
+  dlti.dl_spec = #dlti.dl_spec<
+    #dlti.dl_entry<i8, dense<8>: vector<2xi64>>,
+    #dlti.dl_entry<i16, dense<16>: vector<2xi64>>,
+    #dlti.dl_entry<i32, dense<32>: vector<2xi64>>,
+    #dlti.dl_entry<i64, dense<64>: vector<2xi64>>,
+    #dlti.dl_entry<i128, dense<128>: vector<2xi64>>>
+} {
+
+  // Sub-register signed _BitInt: Extend, one argument with signext.
+  cir.func @ret_b17(%arg0: !b17i) -> !b17i {
+    cir.return %arg0 : !b17i
+  }
+
+  // CHECK: cir.func{{.*}} @ret_b17(%arg0: !cir.int<s, 17, bitint> {llvm.signext}) -> (!cir.int<s, 17, bitint> {llvm.signext})
+
+  // Unsigned sub-register _BitInt: zeroext instead.
+  cir.func @ret_ub17(%arg0: !ub17i) -> !ub17i {
+    cir.return %arg0 : !ub17i
+  }
+
+  // CHECK: cir.func{{.*}} @ret_ub17(%arg0: !cir.int<u, 17, bitint> {llvm.zeroext}) -> (!cir.int<u, 17, bitint> {llvm.zeroext})
+
+  // Too wide to extend, and already the width the classifier names: unchanged.
+  cir.func @ret_b32(%arg0: !b32i) -> !b32i {
+    cir.return %arg0 : !b32i
+  }
+
+  // CHECK: cir.func{{.*}} @ret_b32(%arg0: !s32i_bitint) -> !s32i_bitint
+  // CHECK-NEXT: cir.return %arg0 : !s32i_bitint
+
+  // One bit wider is still one eightbyte, but the classifier names i64, so the
+  // value travels in that width and the narrower one is recovered from memory.
+  cir.func @ret_b33(%arg0: !b33i) -> !b33i {
+    cir.return %arg0 : !b33i
+  }
+
+  // CHECK: cir.func{{.*}} @ret_b33(%arg0: !u64i) -> !u64i
+  // CHECK: cir.cast bitcast %{{.*}} : !cir.ptr<!u64i> -> !cir.ptr<!cir.int<s, 33, bitint>>
+
+  // Signedness does not change the eightbyte it travels in.
+  cir.func @ret_ub33(%arg0: !ub33i) -> !ub33i {
+    cir.return %arg0 : !ub33i
+  }
+
+  // CHECK: cir.func{{.*}} @ret_ub33(%arg0: !u64i) -> !u64i
----------------
adams381 wrote:

Same rewrite.  `ret_ub33` is only here to show signedness picking the extension, and the one check I had was on the signature, which apart from the name is identical to `ret_b33`'s.  So the one thing the function exists to test was the one thing not being checked.

Both blocks walk the same sequence now, and after the rewrite `zext` is the only line where the lowered bodies differ:

```llvm
// LLVM-NEXT:    %[[EXT:[0-9]+]] = zext i33 %[[NARROW]] to i64
```

https://github.com/llvm/llvm-project/pull/212668


More information about the cfe-commits mailing list