https://github.com/erichkeane created 
https://github.com/llvm/llvm-project/pull/225470

On bitint types that are not powers of 2, we have to represent them as an 
array. This patch modifies 'convertTypeForMemory' to do that. However, that 
ends up causing a couple of problems, that this also ends up fixing:

First: constant init needs to also lower to this type/get that correct,
  so this introduces 'getBitIntStorageAttr' to manage that

Second: The 'copy' op lowering was getting its layout from the lowered type, 
which is no longer correct.  Since this is suposed to be the same as what we 
get from CIR, this is jsut switched to use that instead.

Third: this ran into an issue with cir.copy in LoweringPrepare where we didn't 
properly copy the alignment over.  The result was our copy operation didn't get 
alignment correct.  This patch fixes that too.

Fourth: Load/Store/VecMaskedLoad all had to change how they got the type for 
their lowering.  Since what they care about is actually the effecitve 'type' 
itself and not the actual type of the memory the case of the array-lowering, 
this patch introduces convertTypeForLoadStore, which is the effective memory 
type(no cast required, since LLVM-IR doesn't care!), rather than the array type.

ALL the above matches classic codegen.

AI Disclosure: I went back and forth with analysis with Claude on this one, and 
it wrote most of the tests, but I did every single check-line :)

>From 9283a190d1327c108c81801c343430270578077f Mon Sep 17 00:00:00 2001
From: erichkeane <[email protected]>
Date: Tue, 22 Sep 2026 07:47:03 -0700
Subject: [PATCH] [CIR] Implement lowering for BitInt that needs to be an array

On bitint types that are not powers of 2, we have to represent them as
an array. This patch modifies 'convertTypeForMemory' to do that.
However, that ends up causing a couple of problems, that this also ends
up fixing:

First: constant init needs to also lower to this type/get that correct,
  so this introduces 'getBitIntStorageAttr' to manage that

Second: The 'copy' op lowering was getting its layout from the lowered
type, which is no longer correct.  Since this is suposed to be the same
as what we get from CIR, this is jsut switched to use that instead.

Third: this ran into an issue with cir.copy in LoweringPrepare where we
didn't properly copy the alignment over.  The result was our copy
operation didn't get alignment correct.  This patch fixes that too.

Fourth: Load/Store/VecMaskedLoad all had to change how they got the type
for their lowering.  Since what they care about is actually the
effecitve 'type' itself and not the actual type of the memory the case
of the array-lowering, this patch introduces convertTypeForLoadStore,
which is the effective memory type(no cast required, since LLVM-IR
doesn't care!), rather than the array type.

ALL the above matches classic codegen.

AI Disclosure: I went back and forth with analysis with Claude on this
one, and it wrote most of the tests, but I did every single check-line
:)
---
 clang/include/clang/CIR/LoweringHelpers.h     |  13 ++
 .../Dialect/Transforms/LoweringPrepare.cpp    |   8 +-
 .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp |  47 +++---
 clang/lib/CIR/Lowering/LoweringHelpers.cpp    |  49 +++++-
 clang/test/CIR/CodeGen/agg-init-constexpr.cpp |   4 +-
 clang/test/CIR/CodeGen/array.cpp              |   4 +-
 .../CIR/CodeGen/bitint-split-storage-nyi.c    |  65 --------
 clang/test/CIR/CodeGen/bitint-wide.c          | 145 ++++++++++++++++++
 .../local-const-aggregate-name-clash.cpp      |   2 +-
 clang/test/CIR/CodeGen/loop.cpp               |   4 +-
 clang/test/CIR/CodeGenCXX/sizeof-pack.cpp     |   4 +-
 11 files changed, 246 insertions(+), 99 deletions(-)
 delete mode 100644 clang/test/CIR/CodeGen/bitint-split-storage-nyi.c
 create mode 100644 clang/test/CIR/CodeGen/bitint-wide.c

diff --git a/clang/include/clang/CIR/LoweringHelpers.h 
b/clang/include/clang/CIR/LoweringHelpers.h
index fe61db3fc5d25a..bfd1182aa64891 100644
--- a/clang/include/clang/CIR/LoweringHelpers.h
+++ b/clang/include/clang/CIR/LoweringHelpers.h
@@ -80,4 +80,17 @@ mlir::Value createLShR(mlir::OpBuilder &bld, mlir::Value 
lhs, unsigned rhs);
 mlir::Type convertTypeForMemory(const mlir::TypeConverter &converter,
                                 mlir::DataLayout const &dataLayout,
                                 mlir::Type type);
+
+/// The type of a load/store's *value*, as opposed to convertTypeForMemory's
+/// type of the memory it lives in. The two are effectively identical except
+/// with split-storage bit-int.
+mlir::Type convertTypeForLoadStore(const mlir::TypeConverter &converter,
+                                   mlir::DataLayout const &dataLayout,
+                                   mlir::Type type);
+
+// Convert a bit-int value to its llvm value, which can be either an array, or
+// just a large-power-of-2 integer.
+mlir::Attribute getBitIntStorageAttr(mlir::ConversionPatternRewriter &rewriter,
+                                     cir::IntAttr attr,
+                                     const mlir::DataLayout &dataLayout);
 #endif
diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp 
b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
index 2ab71608329ab9..b0e6a276efac4a 100644
--- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
@@ -2378,7 +2378,13 @@ void 
LoweringPreparePass::lowerStoreOfConstAggregate(cir::StoreOp op) {
       cir::GetGlobalOp::create(builder, op.getLoc(), ptrTy, gv.getSymName());
 
   // Replace store with copy.
-  builder.createCopy(op.getAddr(), globalPtr);
+  cir::CopyOp copyOp = builder.createCopy(op.getAddr(), globalPtr);
+
+  cir::CIRDataLayout dataLayout(mlirModule);
+  if (alloca.getAlignment() != dataLayout.getABITypeAlign(ty).value()) {
+    copyOp.setDstAlignment(alloca.getAlignment());
+    copyOp.setSrcAlignment(alloca.getAlignment());
+  }
 
   // Erase the original store.
   op.erase();
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp 
b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 6c7166b4aa243e..c115b79cb62e7b 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -297,10 +297,10 @@ mlir::LogicalResult 
CIRToLLVMCopyOpLowering::matchAndRewrite(
       op.getCopySizeInBytes(layout));
   assert(!cir::MissingFeatures::aggValueSlotVolatile());
 
-  uint64_t dstTypeAlign = dataLayout.getTypeABIAlignment(convertTypeForMemory(
-      *getTypeConverter(), dataLayout, op.getDst().getType().getPointee()));
-  uint64_t srcTypeAlign = dataLayout.getTypeABIAlignment(convertTypeForMemory(
-      *getTypeConverter(), dataLayout, op.getSrc().getType().getPointee()));
+  uint64_t dstTypeAlign =
+      dataLayout.getTypeABIAlignment(op.getDst().getType().getPointee());
+  uint64_t srcTypeAlign =
+      dataLayout.getTypeABIAlignment(op.getSrc().getType().getPointee());
 
   mlir::NamedAttribute dstAlignAttr = rewriter.getNamedAttr(
       mlir::LLVM::LLVMDialect::getAlignAttrName(),
@@ -624,6 +624,14 @@ mlir::Value CIRAttrToValue::visitCirAttr(cir::BoolAttr 
boolAttr) {
 mlir::Value CIRAttrToValue::visitCirAttr(cir::IntAttr intAttr) {
   mlir::Location loc = parentOp->getLoc();
   mlir::DataLayout layout(parentOp->getParentOfType<mlir::ModuleOp>());
+
+  if (auto intTy = mlir::dyn_cast<cir::IntType>(intAttr.getType());
+      intTy && intTy.isBitInt()) {
+    mlir::Type biTy = convertTypeForMemory(*converter, layout, intTy);
+    return mlir::LLVM::ConstantOp::create(
+        rewriter, loc, biTy, getBitIntStorageAttr(rewriter, intAttr, layout));
+  }
+
   // Materialize the value at its literal width, then widen to the in-memory
   // storage type (a no-op except for _BitInt) so aggregate members built here
   // match the iM struct/array fields produced by convertTypeForMemory.
@@ -1057,9 +1065,9 @@ mlir::Value CIRAttrToValue::visitCirAttr(cir::ZeroAttr 
attr) {
 // require region initialization.
 class GlobalInitAttrRewriter {
 public:
-  GlobalInitAttrRewriter(mlir::Type type,
+  GlobalInitAttrRewriter(mlir::Type type, mlir::DataLayout const &dataLayout,
                          mlir::ConversionPatternRewriter &rewriter)
-      : llvmType(type), rewriter(rewriter) {}
+      : llvmType(type), dataLayout(dataLayout), rewriter(rewriter) {}
 
   mlir::Attribute visit(mlir::Attribute attr) {
     return llvm::TypeSwitch<mlir::Attribute, mlir::Attribute>(attr)
@@ -1069,17 +1077,15 @@ class GlobalInitAttrRewriter {
   }
 
   mlir::Attribute visitCirAttr(cir::IntAttr attr) {
-    // A _BitInt(N) global stores its value in a padded integer iM; sign/zero-
-    // extend the APInt to that width (a no-op for plain integers, whose value
-    // width already matches llvmType) so the IntegerAttr is well-typed.
+    // A split-storage _BitInt's memory representation is a byte array (see
+    // convertTypeForMemory), not a scalar, so its constant must be built as
+    // raw bytes rather than a single sign/zero-extended IntegerAttr.
+    if (auto intTy = mlir::dyn_cast<cir::IntType>(attr.getType());
+        intTy && intTy.isBitInt())
+      return getBitIntStorageAttr(rewriter, attr, dataLayout);
     llvm::APInt val = attr.getValue();
-    auto destTy = mlir::cast<mlir::IntegerType>(llvmType);
-    if (val.getBitWidth() != destTy.getWidth()) {
-      cir::IntTypeInterface cirIntTy = attr.getType();
-      val = cirIntTy.isSigned() ? val.sext(destTy.getWidth())
-                                : val.zext(destTy.getWidth());
-    }
-    return rewriter.getIntegerAttr(llvmType, val);
+
+    return rewriter.getIntegerAttr(llvmType, attr.getValue());
   }
 
   mlir::Attribute visitCirAttr(cir::FPAttr attr) {
@@ -1092,6 +1098,7 @@ class GlobalInitAttrRewriter {
 
 private:
   mlir::Type llvmType;
+  const mlir::DataLayout &dataLayout;
   mlir::ConversionPatternRewriter &rewriter;
 };
 
@@ -2372,7 +2379,7 @@ mlir::LogicalResult 
CIRToLLVMLoadOpLowering::matchAndRewrite(
     cir::LoadOp op, OpAdaptor adaptor,
     mlir::ConversionPatternRewriter &rewriter) const {
   const mlir::Type llvmTy =
-      convertTypeForMemory(*getTypeConverter(), dataLayout, op.getType());
+      convertTypeForLoadStore(*getTypeConverter(), dataLayout, op.getType());
   if (!llvmTy)
     return op.emitError()
            << "NYI: lowering load of a type with no memory representation";
@@ -2407,7 +2414,7 @@ 
cir::direct::CIRToLLVMVecMaskedLoadOpLowering::matchAndRewrite(
     cir::VecMaskedLoadOp op, OpAdaptor adaptor,
     mlir::ConversionPatternRewriter &rewriter) const {
   const mlir::Type llvmResTy =
-      convertTypeForMemory(*getTypeConverter(), dataLayout, op.getType());
+      convertTypeForLoadStore(*getTypeConverter(), dataLayout, op.getType());
   if (!llvmResTy)
     return op.emitError()
            << "NYI: lowering masked load of a type with no memory "
@@ -2431,7 +2438,7 @@ mlir::LogicalResult 
CIRToLLVMStoreOpLowering::matchAndRewrite(
   mlir::LLVM::AtomicOrdering memorder = getLLVMMemOrder(op.getMemOrder());
   mlir::Type valueType = op.getValue().getType();
   const mlir::Type llvmTy =
-      convertTypeForMemory(*getTypeConverter(), dataLayout, valueType);
+      convertTypeForLoadStore(*getTypeConverter(), dataLayout, valueType);
   if (!llvmTy)
     return op.emitError()
            << "NYI: lowering store of a type with no memory representation";
@@ -3083,7 +3090,7 @@ mlir::LogicalResult 
CIRToLLVMGlobalOpLowering::matchAndRewrite(
 
   if (init.has_value()) {
     if (mlir::isa<cir::FPAttr, cir::IntAttr, cir::BoolAttr>(init.value())) {
-      GlobalInitAttrRewriter initRewriter(llvmType, rewriter);
+      GlobalInitAttrRewriter initRewriter(llvmType, dataLayout, rewriter);
       init = initRewriter.visit(init.value());
       // If initRewriter returned a null attribute, init will have a value but
       // the value will be null. If that happens, initRewriter didn't handle 
the
diff --git a/clang/lib/CIR/Lowering/LoweringHelpers.cpp 
b/clang/lib/CIR/Lowering/LoweringHelpers.cpp
index 0b64a37cb6bf49..005a904f94f719 100644
--- a/clang/lib/CIR/Lowering/LoweringHelpers.cpp
+++ b/clang/lib/CIR/Lowering/LoweringHelpers.cpp
@@ -36,6 +36,31 @@ bool isSplitStorageBitInt(cir::IntType ty, const 
mlir::DataLayout &dataLayout) {
 }
 } // namespace
 
+mlir::Attribute getBitIntStorageAttr(mlir::ConversionPatternRewriter &rewriter,
+                                     cir::IntAttr attr,
+                                     const mlir::DataLayout &dataLayout) {
+  auto intTy = mlir::cast<cir::IntType>(attr.getType());
+  unsigned storageBits = intTy.getStorageTypeWidth(dataLayout);
+  llvm::APInt val = attr.getValue();
+  val = intTy.isSigned() ? val.sext(storageBits) : val.zext(storageBits);
+
+  if (!isSplitStorageBitInt(intTy, dataLayout))
+    return rewriter.getIntegerAttr(
+        mlir::IntegerType::get(intTy.getContext(), storageBits), val);
+
+  // If we have to do split storage, we are an array of bytes.  Split this up
+  // into the array that matches convertTypeForMemory.
+  unsigned numBytes = storageBits / 8;
+  llvm::SmallVector<mlir::APInt> bytes;
+  bytes.reserve(numBytes);
+  for (unsigned i = 0; i != numBytes; ++i)
+    bytes.emplace_back(8, val.extractBitsAsZExtValue(8, i * 8));
+
+  auto i8Ty = mlir::IntegerType::get(intTy.getContext(), 8);
+  return mlir::DenseElementsAttr::get(
+      mlir::RankedTensorType::get({numBytes}, i8Ty), bytes);
+}
+
 mlir::Type convertTypeForMemory(const mlir::TypeConverter &converter,
                                 mlir::DataLayout const &dataLayout,
                                 mlir::Type type) {
@@ -57,13 +82,15 @@ mlir::Type convertTypeForMemory(const mlir::TypeConverter 
&converter,
 
   // _BitInt(N) keeps its literal width as a value but is stored in a padded
   // integer iM in memory, the same way bool is i1 as a value and i8 in
-  // memory. The byte-array storage form for wide split widths is not
-  // implemented; a null return signals that, and op lowerings turn it into
-  // errorNYI.
+  // memory. When iM's own LLVM alloc size would overshoot the AST-exact
+  // M/8 byte count (isSplitStorageBitInt), use a byte array instead so the
+  // size stays exact.
   if (auto intTy = mlir::dyn_cast<cir::IntType>(type);
       intTy && intTy.isBitInt()) {
     if (isSplitStorageBitInt(intTy, dataLayout))
-      return {};
+      return mlir::LLVM::LLVMArrayType::get(
+          mlir::IntegerType::get(type.getContext(), 8),
+          intTy.getStorageTypeWidth(dataLayout) / 8);
     return mlir::IntegerType::get(type.getContext(),
                                   intTy.getStorageTypeWidth(dataLayout));
   }
@@ -71,6 +98,20 @@ mlir::Type convertTypeForMemory(const mlir::TypeConverter 
&converter,
   return converter.convertType(type);
 }
 
+mlir::Type convertTypeForLoadStore(const mlir::TypeConverter &converter,
+                                   mlir::DataLayout const &dataLayout,
+                                   mlir::Type type) {
+  // A split-storage _BitInt's memory type is a byte array (see
+  // convertTypeForMemory), but a load/store must still access the whole
+  // integer as-is.
+  if (auto intTy = mlir::dyn_cast<cir::IntType>(type);
+      intTy && intTy.isBitInt())
+    return mlir::IntegerType::get(type.getContext(),
+                                  intTy.getStorageTypeWidth(dataLayout));
+
+  return convertTypeForMemory(converter, dataLayout, type);
+}
+
 static unsigned getIntOrBoolBitWidth(mlir::Type ty) {
   if (auto intTy = mlir::dyn_cast<cir::IntType>(ty))
     return intTy.getWidth();
diff --git a/clang/test/CIR/CodeGen/agg-init-constexpr.cpp 
b/clang/test/CIR/CodeGen/agg-init-constexpr.cpp
index 1fab703ff893c1..250d10faa6e1de 100644
--- a/clang/test/CIR/CodeGen/agg-init-constexpr.cpp
+++ b/clang/test/CIR/CodeGen/agg-init-constexpr.cpp
@@ -23,13 +23,13 @@ extern "C" void construct() {
 // CIR-LABEL: construct()
 // CIR-NEXT: %[[WC_ALLOCA:.*]] = cir.alloca "c" {{.*}} : 
!cir.ptr<!rec_WithCtor>
 // CIR-NEXT: %[[GET_GLOBAL:.*]] = cir.get_global @__const.construct.c : 
!cir.ptr<!rec_WithCtor>
-// CIR-NEXT: cir.copy %[[GET_GLOBAL]] to %[[WC_ALLOCA]] : 
!cir.ptr<!rec_WithCtor>
+// CIR-NEXT: cir.copy %[[GET_GLOBAL]] align(8) to %[[WC_ALLOCA]] align(8) : 
!cir.ptr<!rec_WithCtor>
 // CIR-NEXT: cir.return
 
 // LLVM: @__const.construct.c = private constant %struct.WithCtor <{ i32 4, [4 
x i8] zeroinitializer, i64 10, %struct.HasVal { i32 5 }, [4 x i8] 
zeroinitializer }>
 // LLVM-LABEL: construct()
 // LLVM-NEXT: %[[WC_ALLOCA:.*]] = alloca %struct.WithCtor
-// LLVM-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 1 %1, ptr align 1 
@__const.construct.c, i64 24, i1 false)
+// LLVM-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 8 %1, ptr align 8 
@__const.construct.c, i64 24, i1 false)
 // LLVM-NEXT: ret void
 
 // OGCG-LABEL: construct()
diff --git a/clang/test/CIR/CodeGen/array.cpp b/clang/test/CIR/CodeGen/array.cpp
index 4cb3f6e0b178d7..c17ce8f30d771e 100644
--- a/clang/test/CIR/CodeGen/array.cpp
+++ b/clang/test/CIR/CodeGen/array.cpp
@@ -494,10 +494,10 @@ void array_with_complex_elements() {
 
 // CIR: %[[ARR_ADDR:.*]] = cir.alloca "arr" {{.*}} init : 
!cir.ptr<!cir.array<!cir.complex<!cir.float> x 2>>
 // CIR: %[[CONST:.*]] = cir.get_global @[[COMPLEX_ARR]] : 
!cir.ptr<!cir.array<!cir.complex<!cir.float> x 2>>
-// CIR: cir.copy %[[CONST]] to %[[ARR_ADDR]] : 
!cir.ptr<!cir.array<!cir.complex<!cir.float> x 2>>
+// CIR: cir.copy %[[CONST]] align(16) to %[[ARR_ADDR]] align(16) : 
!cir.ptr<!cir.array<!cir.complex<!cir.float> x 2>>
 
 // LLVM: %[[ARR_ADDR:.*]] = alloca [2 x { float, float }], align 16
-// LLVM: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %[[ARR_ADDR]], ptr align 
4 @[[COMPLEX_ARR:.*]], i64 16, i1 false)
+// LLVM: call void @llvm.memcpy.p0.p0.i64(ptr align 16 %[[ARR_ADDR]], ptr 
align 16 @[[COMPLEX_ARR:.*]], i64 16, i1 false)
 
 // OGCG: %[[ARR_ADDR:.*]] = alloca [2 x { float, float }], align 16
 // OGCG: call void @llvm.memcpy.p0.p0.i64(ptr align 16 %[[ARR_ADDR]], ptr 
align 16 @__const._Z27array_with_complex_elementsv.arr, i64 16, i1 false)
diff --git a/clang/test/CIR/CodeGen/bitint-split-storage-nyi.c 
b/clang/test/CIR/CodeGen/bitint-split-storage-nyi.c
deleted file mode 100644
index f8e3d3de5da074..00000000000000
--- a/clang/test/CIR/CodeGen/bitint-split-storage-nyi.c
+++ /dev/null
@@ -1,65 +0,0 @@
-// RUN: not %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm 
-DGLOBAL %s -o - 2>&1 | FileCheck %s --check-prefix=GLOBAL
-// RUN: not %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm 
-DALLOCA %s -o - 2>&1 | FileCheck %s --check-prefix=ALLOCA
-// RUN: not %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm 
-DSTORE %s -o - 2>&1 | FileCheck %s --check-prefix=STORE
-// RUN: not %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm 
-DLOAD %s -o - 2>&1 | FileCheck %s --check-prefix=LOAD
-// RUN: not %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm 
-DSTRUCT %s -o - 2>&1 | FileCheck %s --check-prefix=STRUCT
-// RUN: not %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm 
-DARRAY %s -o - 2>&1 | FileCheck %s --check-prefix=ARRAY
-// RUN: not %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm 
-DPARAM %s -o - 2>&1 | FileCheck %s --check-prefix=PARAM
-// RUN: not %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm 
-DRETURN %s -o - 2>&1 | FileCheck %s --check-prefix=RETURN
-
-#ifdef GLOBAL
-signed _BitInt(129) g129 = 1;
-// GLOBAL: NYI: lowering global of a type with no memory representation
-#endif
-
-#ifdef ALLOCA
-int use_local(int a) {
-  signed _BitInt(129) x = a;
-  return (int)x;
-}
-// ALLOCA: NYI: lowering alloca of a type with no memory representation
-#endif
-
-#ifdef STORE
-void store_lit(signed _BitInt(129) *p) { *p = (signed _BitInt(129))1; }
-// STORE: NYI: lowering store of a type with no memory representation
-#endif
-
-#ifdef LOAD
-int load_cmp(signed _BitInt(129) *p) { return *p != 0; }
-// LOAD: NYI: lowering load of a type with no memory representation
-#endif
-
-#ifdef STRUCT
-// FIXME: Make sure we test that the layout of this and the array struct are
-// 'correct' when this lowering is completed.
-struct HasWide129 {
-  int i;
-  signed _BitInt(129) bi;
-};
-struct HasWide129 g_struct;
-// STRUCT: NYI: lowering global of a type with no memory representation
-#endif
-
-#ifdef ARRAY
-struct HasWide129Array {
-  int i;
-  signed _BitInt(129) bi[2];
-};
-struct HasWide129Array g_array;
-// ARRAY: NYI: lowering global of a type with no memory representation
-#endif
-
-#ifdef PARAM
-// A split-storage width passed by value classifies Indirect, so the width
-// appears as the byval pointee.
-void take_param(signed _BitInt(129) x) {}
-// PARAM: NYI: lowering a byval/sret/byref argument whose pointee type has no 
memory representation
-#endif
-
-#ifdef RETURN
-// Returned by value it classifies Indirect too, so the width appears as the
-// sret pointee.
-signed _BitInt(129) ret_wide(void) { return 1; }
-// RETURN: NYI: lowering a byval/sret/byref argument whose pointee type has no 
memory representation
-#endif
diff --git a/clang/test/CIR/CodeGen/bitint-wide.c 
b/clang/test/CIR/CodeGen/bitint-wide.c
new file mode 100644
index 00000000000000..07b35fa0bc17f2
--- /dev/null
+++ b/clang/test/CIR/CodeGen/bitint-wide.c
@@ -0,0 +1,145 @@
+// 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-prefixes=LLVM,CIRONLY --input-file=%t-cir.ll %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
+// RUN: FileCheck --check-prefixes=LLVM,OGCG --input-file=%t.ll %s
+
+unsigned _BitInt(200) w200 = 5;
+// CIR-DAG: cir.global external @w200 = #cir.int<5> : !cir.int<u, 200, bitint> 
{alignment = 8 : i64}
+// LLVM-DAG: @w200 = global i256 5, align 8
+signed _BitInt(256) w256 = -1;
+// CIR-DAG: cir.global external @w256 = #cir.int<-1> : !s256i_bitint 
{alignment = 8 : i64}
+// LLVM-DAG: @w256 = global i256 -1, align 8
+
+signed _BitInt(129) g_neg = -1;
+// CIR-DAG: cir.global external @g_neg = #cir.int<-1> : !cir.int<s, 129, 
bitint> {alignment = 8 : i64}
+// LLVM-dAG: @g_neg = global [24 x i8] 
c"\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF", 
align 8
+
+struct HasWide129 {
+  int i;
+  signed _BitInt(129) bi;
+};
+struct HasWide129 g_struct = {7, -1};
+// CIR-DAG: cir.global external @g_struct = #cir.const_record<{#cir.int<7> : 
!s32i, #cir.zero : !cir.array<!u8i x 4>, #cir.int<-1> : !cir.int<s, 129, 
bitint>}> : !rec_HasWide129 {alignment = 8 : i64}
+// Note: CIR packs this, but classic codegen doesn't.  Layout is still
+// identical, but there is a slight IR difference.
+// LLVM-DAG: %struct.HasWide129 = type {{[<]?}}{ i32, [4 x i8], [24 x i8] 
}{{[>]?}}
+// LLVM-DAG: @g_struct = global %struct.HasWide129 {{[<]?}}{ i32 7, [4 x i8] 
zeroinitializer, [24 x i8] 
c"\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF" 
}{{[>]?}}, align 8
+
+signed _BitInt(129) g_arr[2] = {-1, -2};
+// CIR-DAG: cir.global external @g_arr = #cir.const_array<[#cir.int<-1> : 
!cir.int<s, 129, bitint>, #cir.int<-2> : !cir.int<s, 129, bitint>]> : 
!cir.array<!cir.int<s, 129, bitint> x 2> {alignment = 16 : i64}
+// LLVM-DAG: @g_arr = global [2 x [24 x i8]] {{\[\[}}24 x i8] 
c"\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF", 
[24 x i8] 
c"\FE\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF"], 
align 16
+
+struct HasWide129Array {
+  int i;
+  signed _BitInt(129) bi[2];
+};
+struct HasWide129Array g_arr2 = {7, {-1, -2}};
+// CIR-DAG: cir.global external @g_arr2 = #cir.const_record<{#cir.int<7> : 
!s32i, #cir.zero : !cir.array<!u8i x 4>, #cir.const_array<[#cir.int<-1> : 
!cir.int<s, 129, bitint>, #cir.int<-2> : !cir.int<s, 129, bitint>]> : 
!cir.array<!cir.int<s, 129, bitint> x 2>}> : !rec_HasWide129Array {alignment = 
8 : i64}
+// LLVM-DAG: %struct.HasWide129Array = type {{[<]?}}{ i32, [4 x i8], [2 x [24 
x i8]] }{{[>]?}}
+// LLVM-DAG: @g_arr2 = global %struct.HasWide129Array {{[<]?}}{ i32 7, [4 x 
i8] zeroinitializer, [2 x [24 x i8]] {{\[\[}}24 x i8] 
c"\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF", 
[24 x i8] 
c"\FE\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF"] 
}{{[>]?}}, align 8
+
+signed _BitInt(320) g320 = -1;
+// CIR-DAG: cir.global external @g320 = #cir.int<-1> : !cir.int<s, 320, 
bitint> {alignment = 8 : i64}
+// LLVM-DAG: @g320 = global [40 x i8] 
c"\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF\FF",
 align 8
+
+_BitInt(129) local_var(int a) {
+  signed _BitInt(129) x = a;
+  return x;
+}
+// CIR-LABEL: cir.func{{.*}}@local_var
+// CIR-SAME: %[[RET_ARG:.*]]: !cir.ptr<!cir.int<s, 129, bitint>>
+// CIR-SAME: %[[A_ARG:.*]]: !s32i
+// CIR: %[[A:.*]] = cir.alloca "a" align(4) init : !cir.ptr<!s32i>
+// CIR: %[[X:.*]] = cir.alloca "x" align(8) init : !cir.ptr<!cir.int<s, 129, 
bitint>>
+// CIR: cir.store %[[A_ARG]], %[[A]] : !s32i, !cir.ptr<!s32i>
+// CIR: %[[A_LOAD:.*]] = cir.load align(4) %[[A]] : !cir.ptr<!s32i>, !s32i
+// CIR: %[[CAST:.*]] = cir.cast integral %[[A_LOAD:.*]] : !s32i -> !cir.int<s, 
129, bitint>
+// CIR: cir.store align(8) %[[CAST]], %[[X]] : !cir.int<s, 129, bitint>, 
!cir.ptr<!cir.int<s, 129, bitint>>
+// CIR: %[[X_LOAD:.*]] = cir.load align(8) %[[X]] : !cir.ptr<!cir.int<s, 129, 
bitint>>, !cir.int<s, 129, bitint>
+// CIR: cir.store %[[X_LOAD]], %[[RET_ARG]] : !cir.int<s, 129, bitint>, 
!cir.ptr<!cir.int<s, 129, bitint>>
+
+// LLVM-LABEL: define{{.*}}@local_var
+// LLVM-SAME: ptr{{.*}} %[[RET_ARG:.*]],
+// LLVM-SAME: i32{{.*}} %[[ARG:.*]])
+// LLVM: %[[A:.*]] = alloca i32, align 4
+// LLVM: %[[X:.*]] = alloca [24 x i8], align 8
+// LLVM: store i32 %[[ARG]], ptr %[[A]], align 4
+// LLVM: %[[LOAD_A:.*]] = load i32, ptr %[[A]], align 4
+// LLVM: %[[EXT_A:.*]] = sext i32 %[[LOAD_A]] to i129
+// LLVM: %[[PAD_A:.*]] = sext i129 %[[EXT_A]] to i192
+// LLVM: store i192 %[[PAD_A]], ptr %[[X]], align 8
+// LLVM: %[[LOAD_X:.*]] = load i192, ptr %[[X]], align 8
+// LLVM: %[[TRUNC_X:.*]] = trunc i192 %[[LOAD_X]] to i129
+// LLVM: %[[EXT_X:.*]] = sext i129 %[[TRUNC_X]] to i192
+// LLVM: store i192 %[[EXT_X]], ptr %[[RET_ARG]], align 8
+
+_BitInt(129) local_arr(void) {
+  signed _BitInt(129) arr[2] = {-1, -2};
+  arr[1] = 3;
+
+  return arr[0];
+}
+
+// CIR-LABEL: cir.func{{.*}}@local_arr
+// CIR-SAME: %[[RET_ARG:.*]]: !cir.ptr<!cir.int<s, 129, bitint>>
+// CIR: %[[ARR:.*]] = cir.alloca "arr" align(16) init : 
!cir.ptr<!cir.array<!cir.int<s, 129, bitint> x 2>>
+// CIR: %[[CONST_ARR:.*]] = cir.get_global @__const.local_arr.arr : 
!cir.ptr<!cir.array<!cir.int<s, 129, bitint> x 2>>
+// CIR: cir.copy %[[CONST_ARR]] align(16) to %[[ARR]] align(16) : 
!cir.ptr<!cir.array<!cir.int<s, 129, bitint> x 2>>
+// CIR: %[[THREE:.*]] = cir.const #cir.int<3> : !cir.int<s, 129, bitint>
+// CIR: %[[ONE:.*]] = cir.const #cir.int<1> : !s64i
+// CIR: %[[GET_ELT_ONE:.*]] = cir.get_element %[[ARR]][%[[ONE]] : !s64i] : 
!cir.ptr<!cir.array<!cir.int<s, 129, bitint> x 2>> -> !cir.ptr<!cir.int<s, 129, 
bitint>>
+// CIR: cir.store align(8) %[[THREE]], %[[GET_ELT_ONE]] : !cir.int<s, 129, 
bitint>, !cir.ptr<!cir.int<s, 129, bitint>>
+// CIR: %[[ZERO:.*]] = cir.const #cir.int<0> : !s64i
+// CIR: %[[GET_ELT_ZERO:.*]] = cir.get_element %[[ARR]][%[[ZERO]] : !s64i] : 
!cir.ptr<!cir.array<!cir.int<s, 129, bitint> x 2>> -> !cir.ptr<!cir.int<s, 129, 
bitint>>
+// CIR: %[[LOAD_ELT_ZERO:.*]] = cir.load align(16) %[[GET_ELT_ZERO]] : 
!cir.ptr<!cir.int<s, 129, bitint>>, !cir.int<s, 129, bitint>
+// CIR: cir.store %[[LOAD_ELT_ZERO]], %[[RET_ARG]] : !cir.int<s, 129, bitint>, 
!cir.ptr<!cir.int<s, 129, bitint>>
+
+// LLVM-LABEL: define{{.*}}@local_arr
+// LLVM-SAME: ptr{{.*}}%[[RET_ARG:.*]])
+// LLVM: %[[ARR:.*]] = alloca [2 x [24 x i8]], align 16
+// LLVM: call void @llvm.memcpy.p0.p0.i64(ptr align 16 %[[ARR]], ptr align 16 
@__const.local_arr.arr, i64 48, i1 false)
+// LLVM: %[[GET_ELT_ONE:.*]] = getelementptr{{.*}} [2 x [24 x i8]], ptr 
%[[ARR]], i{{.*}} 0, i64 1
+// LLVM: store i192 3, ptr %[[GET_ELT_ONE]], align 8
+// LLVM: %[[GET_ELT_ZERO:.*]] = getelementptr{{.*}} [2 x [24 x i8]], ptr 
%[[ARR]], i{{.*}} 0, i64 0
+// LLVM: %[[LOAD_ELT_ZERO:.*]] = load i192, ptr %[[GET_ELT_ZERO]], align 16
+// LLVM: %[[TRUNC_ELT:.*]] = trunc i192 %[[LOAD_ELT_ZERO]] to i129
+// LLVM: %[[EXT_ELT:.*]] = sext i129 %[[TRUNC_ELT]] to i192
+// LLVM: store i192 %[[EXT_ELT]], ptr %[[RET_ARG]], align 8
+
+_BitInt(129) take_param(signed _BitInt(129) x) {
+return x;
+}
+
+// CIR-LABEL: cir.func{{.*}}@take_param
+// CIR-SAME: %[[RET_ARG:[^:]*]]: !cir.ptr<!cir.int<s, 129, bitint>>
+// CIR-SAME: %[[ARG:.*]]: !cir.ptr<!cir.int<s, 129, bitint>>
+// CIR: %[[LOAD_ARG:.*]] = cir.load %[[ARG]] : !cir.ptr<!cir.int<s, 129, 
bitint>>, !cir.int<s, 129, bitint>
+// CIR: %[[ALLOCA_X:.*]] = cir.alloca "x" align(8) init : !cir.ptr<!cir.int<s, 
129, bitint>>
+// CIR: cir.store %[[LOAD_ARG]], %[[ALLOCA_X]] : !cir.int<s, 129, bitint>, 
!cir.ptr<!cir.int<s, 129, bitint>>
+// CIR: %[[LOAD_X:.*]] = cir.load align(8) %[[ALLOCA_X]] : 
!cir.ptr<!cir.int<s, 129, bitint>>, !cir.int<s, 129, bitint>
+// CIR: cir.store %[[LOAD_X]], %[[RET_ARG]] : !cir.int<s, 129, bitint>, 
!cir.ptr<!cir.int<s, 129, bitint>>
+
+// LLVM-LABEL: define{{.*}}@take_param
+// LLVM-SAME: ptr{{.*}} %[[RET_ARG:.*]], 
+// LLVM-SAME: ptr{{.*}}%[[ARG:.*]])
+// OGCG: %[[X:.*]] = alloca [24 x i8], align 8
+// LLVM: %[[LOAD_ARG:.*]] = load i192, ptr %[[ARG]], align 8
+// LLVM: %[[TRUNC_ARG:.*]] = trunc i192 %[[LOAD_ARG]] to i129
+// CIRONLY: %[[X:.*]] = alloca [24 x i8], align 8
+// LLVM: %[[EXT_TRUNC_ARG:.*]] = sext i129 %[[TRUNC_ARG]] to i192
+// LLVM: store i192 %[[EXT_TRUNC_ARG]], ptr %[[X]], align 8
+// LLVM: %[[LOAD_X:.*]] = load i192, ptr %[[X]], align 8
+// LLVM: %[[TRUNC_X:.*]] = trunc i192 %[[LOAD_X]] to i129
+// LLVM: %[[EXT_X:.*]] = sext i129 %[[TRUNC_X]] to i192
+// LLVM: store i192 %[[EXT_X]], ptr %[[RET_ARG]], align 8
+
+signed _BitInt(129) ret_wide(void) { return 1; }
+
+// CIR-LABEL: cir.func{{.*}}@ret_wide
+// CIR: %[[ONE:.*]] = cir.const #cir.int<1> : !cir.int<s, 129, bitint>
+
+// LLVM-LABEL: define{{.*}}@ret_wide
+// LLVM: store i192 1, ptr %{{.*}}, align 8
+
diff --git a/clang/test/CIR/CodeGen/local-const-aggregate-name-clash.cpp 
b/clang/test/CIR/CodeGen/local-const-aggregate-name-clash.cpp
index f8ecb371c43a9a..f0475ee765d856 100644
--- a/clang/test/CIR/CodeGen/local-const-aggregate-name-clash.cpp
+++ b/clang/test/CIR/CodeGen/local-const-aggregate-name-clash.cpp
@@ -34,7 +34,7 @@ void f(bool which) {
 // LLVM-DAG: @[[GV1:.*]] = private constant [2 x i32] [i32 50, i32 60], align 4
 
 // LLVM: define{{.*}} @_Z1fb
-// LLVM:   call void @llvm.memcpy.p0.p0.i64(ptr {{[^,]+}}, ptr align 4 
@[[GV0]], i64 16, i1 false)
+// LLVM:   call void @llvm.memcpy.p0.p0.i64(ptr {{[^,]+}}, ptr align 16 
@[[GV0]], i64 16, i1 false)
 // LLVM:   call void @llvm.memcpy.p0.p0.i64(ptr {{[^,]+}}, ptr align 4 
@[[GV1]], i64 8, i1 false)
 
 // OGCG-DAG: @[[GV0:.*]] = private unnamed_addr constant [4 x i32] [i32 10, 
i32 20, i32 30, i32 40], align 16
diff --git a/clang/test/CIR/CodeGen/loop.cpp b/clang/test/CIR/CodeGen/loop.cpp
index a1c25e08bca542..f6f2ea7af0c12c 100644
--- a/clang/test/CIR/CodeGen/loop.cpp
+++ b/clang/test/CIR/CodeGen/loop.cpp
@@ -316,7 +316,7 @@ void l5() {
 // CIR:     %[[END_ADDR:.*]] = cir.alloca "__end1" {{.*}} init
 // CIR:     %[[X_ADDR:.*]] = cir.alloca "x" {{.*}} init
 // CIR:     %[[ARR_INIT:.*]] = cir.get_global @[[L5_ARR]]
-// CIR:     cir.copy %[[ARR_INIT]] to %[[ARR_ADDR]]
+// CIR:     cir.copy %[[ARR_INIT]] align(16) to %[[ARR_ADDR]] align(16)
 // CIR:     cir.store{{.*}} %[[ARR_ADDR]], %[[RANGE_ADDR]]
 // CIR:     %[[RANGE_LOAD:.*]] = cir.load %[[RANGE_ADDR]]
 // CIR:     %[[RANGE_CAST:.*]] = cir.cast array_to_ptrdecay %[[RANGE_LOAD]] : 
{{.*}}
@@ -353,7 +353,7 @@ void l5() {
 // LLVM:   %[[X_ADDR:.*]] = alloca i32
 // LLVM:   br label %[[SETUP:.*]]
 // LLVM: [[SETUP]]:
-// LLVM:   call void @llvm.memcpy{{.*}}(ptr align 4 %[[ARR_ADDR]], ptr align 4 
@[[L5_ARR]], i64 16, i1 false)
+// LLVM:   call void @llvm.memcpy{{.*}}(ptr align 16 %[[ARR_ADDR]], ptr align 
16 @[[L5_ARR]], i64 16, i1 false)
 // LLVM:   store ptr %[[ARR_ADDR]], ptr %[[RANGE_ADDR]]
 // LLVM:   %[[BEGIN:.*]] = load ptr, ptr %[[RANGE_ADDR]]
 // LLVM:   %[[BEGIN_CAST:.*]] = getelementptr i32, ptr %[[BEGIN]], i32 0
diff --git a/clang/test/CIR/CodeGenCXX/sizeof-pack.cpp 
b/clang/test/CIR/CodeGenCXX/sizeof-pack.cpp
index ba0f362281970d..a8dd41f85ba9e2 100644
--- a/clang/test/CIR/CodeGenCXX/sizeof-pack.cpp
+++ b/clang/test/CIR/CodeGenCXX/sizeof-pack.cpp
@@ -58,7 +58,7 @@ void test() {
 // CIR: %[[RETVAL:.*]] = cir.alloca "__retval" {{.*}} : !cir.ptr<!u64i>
 // CIR: %[[VAL_ARR:.*]] = cir.alloca "values" {{.*}} init : 
!cir.ptr<!cir.array<!s32i x 4>>
 // CIR: %[[GET_GLOB_VAL:.*]] = cir.get_global 
@__const._Z3fooIJ2S12S22S3EEDav.values : !cir.ptr<!cir.array<!s32i x 4>>
-// CIR: cir.copy %[[GET_GLOB_VAL]] to %[[VAL_ARR]] : !cir.ptr<!cir.array<!s32i 
x 4>>
+// CIR: cir.copy %[[GET_GLOB_VAL]] align(16) to %[[VAL_ARR]] align(16) : 
!cir.ptr<!cir.array<!s32i x 4>>
 // CIR: %[[THREE:.*]] = cir.const #cir.int<3> : !u64i
 // CIR: cir.store %[[THREE]], %[[RETVAL]] : !u64i, !cir.ptr<!u64i>
 // CIR: %[[RET_LOAD:.*]] = cir.load %[[RETVAL]]  : !cir.ptr<!u64i>, !u64i
@@ -67,7 +67,7 @@ void test() {
 // LLVM: define {{.*}}i64 @_Z3fooIJ2S12S22S3EEDav()
 // LLVM: %[[RETVAL:.*]] = alloca i64
 // LLVM: %[[VAL_ARR:.*]] = alloca [4 x i32]
-// LLVM: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %[[VAL_ARR]], ptr align 
4 @__const._Z3fooIJ2S12S22S3EEDav.values, i64 16, i1 false)
+// LLVM: call void @llvm.memcpy.p0.p0.i64(ptr align 16 %[[VAL_ARR]], ptr align 
16 @__const._Z3fooIJ2S12S22S3EEDav.values, i64 16, i1 false)
 // LLVM: store i64 3, ptr %[[RETVAL]]
 // LLVM: %[[RET_LOAD:.*]] = load i64, ptr %[[RETVAL]]
 // LLVM: ret i64 %[[RET_LOAD]]

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

Reply via email to