https://github.com/kumarak updated 
https://github.com/llvm/llvm-project/pull/204360

>From b59575acfe402cc59e8bc4bd6ae2837166d7b373 Mon Sep 17 00:00:00 2001
From: AkshayK <[email protected]>
Date: Tue, 30 Jun 2026 12:39:21 -0400
Subject: [PATCH 1/3] [CIR][ARM] Add base 32-bit ARM (GenericARM) codegen and
 lowering

Add the GenericARM transform-pass CXXABI dispatch (ARM method-pointer ABI), 
drive the size_t width of exception allocation and cir.copy memcpy from the 
data layout, and implement the NEON vget_lane/vgetq_lane intrinsics in 
CIRGenBuiltinAArch64.cpp.
---
 clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp       |  4 +-
 .../lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp  | 42 +++++++++++++++++
 clang/lib/CIR/CodeGen/CIRGenFunction.h        |  4 ++
 .../TargetLowering/LowerItaniumCXXABI.cpp     |  7 +++
 .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 18 ++++---
 .../CodeGen/ARM/arm-aggregate-copy-size.cpp   | 21 +++++++++
 .../CIR/CodeGen/ARM/arm-record-layout.cpp     | 34 ++++++++++++++
 .../CIR/CodeGen/ARM/arm-throw-alloc-size.cpp  | 22 +++++++++
 .../CIR/CodeGenBuiltins/ARM/arm-builtin-nyi.c | 16 +++++++
 .../CodeGenBuiltins/ARM/arm-neon-vget-lane.c  | 47 +++++++++++++++++++
 10 files changed, 206 insertions(+), 9 deletions(-)
 create mode 100644 clang/test/CIR/CodeGen/ARM/arm-aggregate-copy-size.cpp
 create mode 100644 clang/test/CIR/CodeGen/ARM/arm-record-layout.cpp
 create mode 100644 clang/test/CIR/CodeGen/ARM/arm-throw-alloc-size.cpp
 create mode 100644 clang/test/CIR/CodeGenBuiltins/ARM/arm-builtin-nyi.c
 create mode 100644 clang/test/CIR/CodeGenBuiltins/ARM/arm-neon-vget-lane.c

diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp 
b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index 1efe2b81d5cae..b091460f4c030 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -2791,9 +2791,7 @@ emitTargetArchBuiltinExpr(CIRGenFunction *cgf, unsigned 
builtinID,
   case llvm::Triple::armeb:
   case llvm::Triple::thumb:
   case llvm::Triple::thumbeb:
-    // These are actually NYI, but that will be reported by emitBuiltinExpr.
-    // At this point, we don't even know that the builtin is target-specific.
-    return std::nullopt;
+    return cgf->emitARMBuiltinExpr(builtinID, e, returnValue, arch);
   case llvm::Triple::aarch64:
   case llvm::Triple::aarch64_32:
   case llvm::Triple::aarch64_be:
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp 
b/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp
index 838d5af867c8d..e3aa1f11a7181 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp
@@ -2017,6 +2017,48 @@ static const std::pair<unsigned, unsigned> 
neonEquivalentIntrinsicMap[] = {
      NEON::BI__builtin_neon_vstl1q_lane_s64},
 };
 
+std::optional<mlir::Value>
+CIRGenFunction::emitARMBuiltinExpr(unsigned builtinID, const CallExpr *expr,
+                                   ReturnValueSlot returnValue,
+                                   llvm::Triple::ArchType arch) {
+  // Only the NEON lane reads are implemented so far.
+  switch (builtinID) {
+  case NEON::BI__builtin_neon_vget_lane_i8:
+  case NEON::BI__builtin_neon_vget_lane_i16:
+  case NEON::BI__builtin_neon_vget_lane_i32:
+  case NEON::BI__builtin_neon_vget_lane_i64:
+  case NEON::BI__builtin_neon_vget_lane_bf16:
+  case NEON::BI__builtin_neon_vget_lane_f32:
+  case NEON::BI__builtin_neon_vgetq_lane_i8:
+  case NEON::BI__builtin_neon_vgetq_lane_i16:
+  case NEON::BI__builtin_neon_vgetq_lane_i32:
+  case NEON::BI__builtin_neon_vgetq_lane_i64:
+  case NEON::BI__builtin_neon_vgetq_lane_bf16:
+  case NEON::BI__builtin_neon_vgetq_lane_f32:
+  case NEON::BI__builtin_neon_vduph_lane_bf16:
+  case NEON::BI__builtin_neon_vduph_laneq_bf16: {
+    mlir::Location loc = getLoc(expr->getExprLoc());
+    mlir::Value vec = emitScalarExpr(expr->getArg(0));
+    mlir::Value index = emitScalarExpr(expr->getArg(1));
+    return cir::VecExtractOp::create(builder, loc, vec, index);
+  }
+  default:
+    break;
+  }
+
+  cgm.errorNYI(expr->getSourceRange(),
+               std::string("unimplemented ARM builtin call: ") +
+                   getContext().BuiltinInfo.getName(builtinID));
+
+  // Yield an undef rather than a null value: emitBuiltinExpr forwards a null
+  // straight into an RValue, which then reaches createStore for any result
+  // that is stored to memory. Void has no value to hand back.
+  if (expr->getType()->isVoidType())
+    return mlir::Value{};
+  return getUndefConstant(getLoc(expr->getExprLoc()),
+                          convertType(expr->getType()));
+}
+
 std::optional<mlir::Value>
 CIRGenFunction::emitAArch64BuiltinExpr(unsigned builtinID, const CallExpr 
*expr,
                                        ReturnValueSlot returnValue,
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h 
b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index 9f8454309f13a..4b494222a8944 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -1622,6 +1622,10 @@ class CIRGenFunction : public CIRGenTypeCache {
   emitAArch64BuiltinExpr(unsigned builtinID, const CallExpr *expr,
                          ReturnValueSlot returnValue,
                          llvm::Triple::ArchType arch);
+  std::optional<mlir::Value> emitARMBuiltinExpr(unsigned builtinID,
+                                                const CallExpr *expr,
+                                                ReturnValueSlot returnValue,
+                                                llvm::Triple::ArchType arch);
   std::optional<mlir::Value> emitAArch64SMEBuiltinExpr(unsigned builtinID,
                                                        const CallExpr *expr);
   std::optional<mlir::Value> emitAArch64SVEBuiltinExpr(unsigned builtinID,
diff --git 
a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp 
b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp
index 6c276a83f18cf..e26307e83af8d 100644
--- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp
@@ -148,6 +148,13 @@ std::unique_ptr<CIRCXXABI> createItaniumCXXABI(LowerModule 
&lm) {
         /*useARMMethodPtrABI=*/true,
         /*use32BitVTableOffsetABI=*/true);
 
+  case clang::TargetCXXABI::GenericARM:
+    // ARM method-pointer encoding, but no 32-bit vtable offsets.
+    return std::make_unique<LowerItaniumCXXABI>(
+        lm,
+        /*useARMMethodPtrABI=*/true,
+        /*use32BitVTableOffsetABI=*/false);
+
   case clang::TargetCXXABI::GenericItanium:
     return std::make_unique<LowerItaniumCXXABI>(lm);
 
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp 
b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 717bf5e2e741e..50f82e0a445f5 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -287,13 +287,19 @@ static mlir::LLVM::CConv 
convertCallingConv(cir::CallingConv callingConv) {
   llvm_unreachable("Unknown calling convention");
 }
 
+/// Returns size_t as an integer type, mirroring CodeGenModule::SizeTy.
+static mlir::IntegerType getSizeTType(mlir::MLIRContext *ctx,
+                                      const mlir::DataLayout &dataLayout) {
+  return mlir::IntegerType::get(
+      ctx, 
dataLayout.getTypeSizeInBits(mlir::LLVM::LLVMPointerType::get(ctx)));
+}
+
 mlir::LogicalResult CIRToLLVMCopyOpLowering::matchAndRewrite(
     cir::CopyOp op, OpAdaptor adaptor,
     mlir::ConversionPatternRewriter &rewriter) const {
-  mlir::DataLayout layout(op->getParentOfType<mlir::ModuleOp>());
+  mlir::Type lenTy = getSizeTType(rewriter.getContext(), dataLayout);
   const mlir::Value length = mlir::LLVM::ConstantOp::create(
-      rewriter, op.getLoc(), rewriter.getI64Type(),
-      op.getCopySizeInBytes(layout));
+      rewriter, op.getLoc(), lenTy, op.getCopySizeInBytes(dataLayout));
   assert(!cir::MissingFeatures::aggValueSlotVolatile());
 
   uint64_t dstTypeAlign = dataLayout.getTypeABIAlignment(convertTypeForMemory(
@@ -4441,11 +4447,11 @@ mlir::LogicalResult 
CIRToLLVMThrowOpLowering::matchAndRewrite(
 mlir::LogicalResult CIRToLLVMAllocExceptionOpLowering::matchAndRewrite(
     cir::AllocExceptionOp op, OpAdaptor adaptor,
     mlir::ConversionPatternRewriter &rewriter) const {
-  // Get or create `declare ptr @__cxa_allocate_exception(i64)`
+  // Get or create `declare ptr @__cxa_allocate_exception(size_t)`.
   StringRef fnName = "__cxa_allocate_exception";
   auto llvmPtrTy = mlir::LLVM::LLVMPointerType::get(rewriter.getContext());
-  auto int64Ty = mlir::IntegerType::get(rewriter.getContext(), 64);
-  auto fnTy = mlir::LLVM::LLVMFunctionType::get(llvmPtrTy, {int64Ty});
+  mlir::IntegerType sizeTTy = getSizeTType(rewriter.getContext(), dataLayout);
+  auto fnTy = mlir::LLVM::LLVMFunctionType::get(llvmPtrTy, {sizeTTy});
 
   createLLVMFuncOpIfNotExist(rewriter, symbolTables, op, fnName, fnTy);
   auto exceptionSize = mlir::LLVM::ConstantOp::create(rewriter, op.getLoc(),
diff --git a/clang/test/CIR/CodeGen/ARM/arm-aggregate-copy-size.cpp 
b/clang/test/CIR/CodeGen/ARM/arm-aggregate-copy-size.cpp
new file mode 100644
index 0000000000000..72258e542d83d
--- /dev/null
+++ b/clang/test/CIR/CodeGen/ARM/arm-aggregate-copy-size.cpp
@@ -0,0 +1,21 @@
+// The llvm.memcpy length for a cir.copy is size_t-wide: i32 on 32-bit ARM.
+// RUN: %clang_cc1 -std=c++20 -triple arm-linux-gnueabihf -fclangir -emit-cir 
%s -o %t.cir
+// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
+// RUN: %clang_cc1 -std=c++20 -triple arm-linux-gnueabihf -fclangir -emit-llvm 
%s -o %t.ll
+// RUN: FileCheck --check-prefix=ARM --input-file=%t.ll %s
+// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir 
-emit-llvm %s -o %t-x86.ll
+// RUN: FileCheck --check-prefix=X86 --input-file=%t-x86.ll %s
+// RUN: %clang_cc1 -std=c++20 -triple arm-linux-gnueabihf -emit-llvm %s -o 
%t-ogcg.ll
+// RUN: FileCheck --check-prefix=ARM --input-file=%t-ogcg.ll %s
+
+struct P { int x; int y; };
+int sum(P p);
+int use() { P p; p.x = 1; p.y = 2; return sum(p); }
+
+// The width is resolved during lowering to LLVM, so CIR just has the copy.
+// CIR-LABEL: cir.func{{.*}} @_Z3usev()
+// CIR: cir.copy {{.*}} : !cir.ptr<!rec_P>
+
+// ARM: call void @llvm.memcpy.p0.p0.i32(ptr {{.*}}, ptr {{.*}}, i32 8, i1 
false)
+
+// X86: call void @llvm.memcpy.p0.p0.i64(ptr {{.*}}, ptr {{.*}}, i64 8, i1 
false)
diff --git a/clang/test/CIR/CodeGen/ARM/arm-record-layout.cpp 
b/clang/test/CIR/CodeGen/ARM/arm-record-layout.cpp
new file mode 100644
index 0000000000000..a939427683242
--- /dev/null
+++ b/clang/test/CIR/CodeGen/ARM/arm-record-layout.cpp
@@ -0,0 +1,34 @@
+// Records and vtables are 4-byte aligned with 4-byte pointers on 32-bit ARM.
+// RUN: %clang_cc1 -std=c++20 -triple arm-linux-gnueabihf -fclangir -emit-cir 
%s -o %t.cir
+// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
+// RUN: %clang_cc1 -std=c++20 -triple arm-linux-gnueabihf -fclangir -emit-llvm 
%s -o %t.ll
+// RUN: FileCheck --check-prefix=LLVM --input-file=%t.ll %s
+// RUN: %clang_cc1 -std=c++20 -triple arm-linux-gnueabihf -emit-llvm %s -o 
%t-ogcg.ll
+// RUN: FileCheck --check-prefix=OGCG --input-file=%t-ogcg.ll %s
+
+struct S {
+  int *p;
+  int x;
+};
+
+S s;
+
+class A {
+public:
+  virtual void f();
+  int x;
+};
+
+void A::f() {}
+
+// CIR-DAG: !rec_S = !cir.struct<"S" {!cir.ptr<!s32i>, !s32i}>
+// CIR-DAG: !rec_A = !cir.struct<class "A" {!cir.vptr, !s32i}>
+// CIR-DAG: !cir.ptr<!cir.void> = #cir.ptr_spec<size = 32, abi = 32, preferred 
= 32, index = 32>
+// CIR: cir.global external @s = #cir.zero : !rec_S {alignment = 4 : i64}
+// CIR: cir.global {{.*}}@_ZTV1A = #cir.vtable<{{.*}}{alignment = 4 : i64}
+
+// LLVM: @s = global %struct.S zeroinitializer, align 4
+// LLVM: @_ZTV1A = global { [3 x ptr] } {{.*}}, align 4
+
+// OGCG: @s = global %struct.S zeroinitializer, align 4
+// OGCG: @_ZTV1A = {{.*}}constant { [3 x ptr] } {{.*}}, align 4
diff --git a/clang/test/CIR/CodeGen/ARM/arm-throw-alloc-size.cpp 
b/clang/test/CIR/CodeGen/ARM/arm-throw-alloc-size.cpp
new file mode 100644
index 0000000000000..0d0d0db5f14fa
--- /dev/null
+++ b/clang/test/CIR/CodeGen/ARM/arm-throw-alloc-size.cpp
@@ -0,0 +1,22 @@
+// __cxa_allocate_exception's thrown_size is size_t: i32 on 32-bit ARM.
+// RUN: %clang_cc1 -std=c++20 -triple arm-linux-gnueabihf -fcxx-exceptions 
-fexceptions -fclangir -emit-cir %s -o %t.cir
+// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
+// RUN: %clang_cc1 -std=c++20 -triple arm-linux-gnueabihf -fcxx-exceptions 
-fexceptions -fclangir -emit-llvm %s -o %t.ll
+// RUN: FileCheck --check-prefix=ARM --input-file=%t.ll %s
+// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu 
-fcxx-exceptions -fexceptions -fclangir -emit-llvm %s -o %t-x86.ll
+// RUN: FileCheck --check-prefix=X86 --input-file=%t-x86.ll %s
+// RUN: %clang_cc1 -std=c++20 -triple arm-linux-gnueabihf -fcxx-exceptions 
-fexceptions -emit-llvm %s -o %t-ogcg.ll
+// RUN: FileCheck --check-prefix=ARM --input-file=%t-ogcg.ll %s
+
+void f() { throw 42; }
+
+// The width is resolved during lowering to LLVM.
+// CIR-LABEL: cir.func{{.*}} @_Z1fv()
+// CIR: cir.alloc.exception 4
+
+// CIR emits the declare first, classic CodeGen emits the call first.
+// ARM-DAG: declare ptr @__cxa_allocate_exception(i32)
+// ARM-DAG: call ptr @__cxa_allocate_exception(i32 4)
+
+// X86: declare ptr @__cxa_allocate_exception(i64)
+// X86: call ptr @__cxa_allocate_exception(i64 4)
diff --git a/clang/test/CIR/CodeGenBuiltins/ARM/arm-builtin-nyi.c 
b/clang/test/CIR/CodeGenBuiltins/ARM/arm-builtin-nyi.c
new file mode 100644
index 0000000000000..4e9c211e20026
--- /dev/null
+++ b/clang/test/CIR/CodeGenBuiltins/ARM/arm-builtin-nyi.c
@@ -0,0 +1,16 @@
+// An unimplemented ARM builtin must report NYI once and not crash. A vector
+// result is the interesting case: it is stored through memory, so returning a
+// null value here would reach createStore. Covers all four arms of the ARM
+// dispatch in emitTargetArchBuiltinExpr.
+//
+// CIRGen stops after the first NYI, so only one such call fits per file.
+
+// RUN: %clang_cc1 -triple armv7-unknown-linux-gnueabihf -target-feature +neon 
-fclangir -emit-llvm %s -verify -o /dev/null
+// RUN: %clang_cc1 -triple armebv7-unknown-linux-gnueabihf -target-feature 
+neon -fclangir -emit-llvm %s -verify -o /dev/null
+// RUN: %clang_cc1 -triple thumbv7-unknown-linux-gnueabihf -target-feature 
+neon -fclangir -emit-llvm %s -verify -o /dev/null
+// RUN: %clang_cc1 -triple thumbebv7-unknown-linux-gnueabihf -target-feature 
+neon -fclangir -emit-llvm %s -verify -o /dev/null
+
+typedef __attribute__((neon_vector_type(4))) int int32x4_t;
+
+// expected-error@+1 {{ClangIR code gen Not Yet Implemented: unimplemented ARM 
builtin call: __builtin_neon_vld1q_v}}
+int32x4_t ld(const int *p) { int32x4_t r = __builtin_neon_vld1q_v(p, 34); 
return r; }
diff --git a/clang/test/CIR/CodeGenBuiltins/ARM/arm-neon-vget-lane.c 
b/clang/test/CIR/CodeGenBuiltins/ARM/arm-neon-vget-lane.c
new file mode 100644
index 0000000000000..79f63813ded72
--- /dev/null
+++ b/clang/test/CIR/CodeGenBuiltins/ARM/arm-neon-vget-lane.c
@@ -0,0 +1,47 @@
+// vget_lane/vgetq_lane lower to __builtin_neon_* on 32-bit ARM, unlike 
AArch64.
+// CIR and classic CodeGen must produce the same extract, so both feed LLVM.
+
+// RUN: %clang_cc1 -triple armv7-unknown-linux-gnueabihf -target-feature +neon 
-target-feature +bf16 -ffreestanding -fclangir -emit-cir %s -o - | FileCheck %s 
--check-prefix=CIR
+// RUN: %clang_cc1 -triple armv7-unknown-linux-gnueabihf -target-feature +neon 
-target-feature +bf16 -ffreestanding -fclangir -emit-llvm %s -o - | FileCheck 
%s --check-prefix=LLVM
+// RUN: %clang_cc1 -triple armv7-unknown-linux-gnueabihf -target-feature +neon 
-target-feature +bf16 -ffreestanding -emit-llvm %s -o - | FileCheck %s 
--check-prefix=LLVM
+
+#include <arm_neon.h>
+
+// CIR-LABEL: cir.func{{.*}} @get_s32(
+// CIR: cir.vec.extract {{.*}} : !cir.vector<4 x !s32i>
+// LLVM-LABEL: define{{.*}} @get_s32(
+// LLVM: extractelement <4 x i32> %{{.*}}, i32 2
+int get_s32(int32x4_t v) { return vgetq_lane_s32(v, 2); }
+
+// CIR-LABEL: cir.func{{.*}} @get_f32(
+// CIR: cir.vec.extract {{.*}} : !cir.vector<4 x !cir.float>
+// LLVM-LABEL: define{{.*}} @get_f32(
+// LLVM: extractelement <4 x float> %{{.*}}, i32 1
+float get_f32(float32x4_t v) { return vgetq_lane_f32(v, 1); }
+
+// CIR-LABEL: cir.func{{.*}} @get_s16(
+// CIR: cir.vec.extract {{.*}} : !cir.vector<4 x !s16i>
+// LLVM-LABEL: define{{.*}} @get_s16(
+// LLVM: extractelement <4 x i16> %{{.*}}, i32 3
+short get_s16(int16x4_t v) { return vget_lane_s16(v, 3); }
+
+// A 64-bit lane, and the single-element vector shape.
+// CIR-LABEL: cir.func{{.*}} @get_s64(
+// CIR: cir.vec.extract {{.*}} : !cir.vector<1 x !s64i>
+// LLVM-LABEL: define{{.*}} @get_s64(
+// LLVM: extractelement <1 x i64> %{{.*}}, i32 0
+long long get_s64(int64x1_t v) { return vget_lane_s64(v, 0); }
+
+// The header bitcasts the unsigned vector to the signed builtin type, so the
+// extract is on !s8i even though the parameter is !u8i.
+// CIR-LABEL: cir.func{{.*}} @get_u8(
+// CIR: cir.vec.extract {{.*}} : !cir.vector<8 x !s8i>
+// LLVM-LABEL: define{{.*}} @get_u8(
+// LLVM: extractelement <8 x i8> %{{.*}}, i32 5
+unsigned char get_u8(uint8x8_t v) { return vget_lane_u8(v, 5); }
+
+// CIR-LABEL: cir.func{{.*}} @get_bf16(
+// CIR: cir.vec.extract {{.*}} : !cir.vector<4 x !cir.bf16>
+// LLVM-LABEL: define{{.*}} @get_bf16(
+// LLVM: extractelement <4 x bfloat> %{{.*}}, i32 1
+bfloat16_t get_bf16(bfloat16x4_t v) { return vget_lane_bf16(v, 1); }

>From 623a9b0b16055c558b344fa6ee5c24b3bb917b2e Mon Sep 17 00:00:00 2001
From: AkshayK <[email protected]>
Date: Fri, 7 Aug 2026 19:37:05 -0400
Subject: [PATCH 2/3] [CIR][ARM] Gather ARM builtin arguments into an ops
 vector

Address review feedback: build the argument-gathering loop the target-specific
builtin path will need, instead of emitting the arguments inline at the one use
site.

Mirror classic CodeGen in TargetBuiltins/ARM.cpp: query the ICE argument mask,
skip the extra Sema-only type discriminator, and constant-fold required integer
constant expressions through emitScalarOrConstFoldImmArg. vget_lane then reads
its operands from the vector. The set of builtins handled here is unchanged.
---
 .../lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp  | 31 +++++++++++++++----
 1 file changed, 25 insertions(+), 6 deletions(-)

diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp 
b/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp
index e3aa1f11a7181..3a0a1b0fec2a2 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp
@@ -2021,6 +2021,28 @@ std::optional<mlir::Value>
 CIRGenFunction::emitARMBuiltinExpr(unsigned builtinID, const CallExpr *expr,
                                    ReturnValueSlot returnValue,
                                    llvm::Triple::ArchType arch) {
+  // Find out if any arguments are required to be integer constant
+  // expressions.
+  assert(!cir::MissingFeatures::handleBuiltinICEArguments());
+  unsigned iceArguments = 0;
+  ASTContext::GetBuiltinTypeError error;
+  getContext().GetBuiltinType(builtinID, error, &iceArguments);
+  assert(error == ASTContext::GE_None && "Should not codegen an error");
+  llvm::SmallVector<mlir::Value, 4> ops;
+
+  // Skip extra arguments used to discriminate vector types and that are
+  // intended for Sema checking.
+  //
+  // Builtins that load or store through an argument also need that pointer's
+  // alignment, which classic CodeGen captures here with
+  // EmitPointerWithAlignment. None of those are implemented yet, so the loop
+  // has no such case to handle.
+  bool hasExtraArg = hasExtraNeonArgument(builtinID);
+  unsigned numArgs = expr->getNumArgs() - (hasExtraArg ? 1 : 0);
+  for (unsigned i = 0, e = numArgs; i != e; i++)
+    ops.push_back(
+        emitScalarOrConstFoldImmArg(iceArguments, i, expr->getArg(i)));
+
   // Only the NEON lane reads are implemented so far.
   switch (builtinID) {
   case NEON::BI__builtin_neon_vget_lane_i8:
@@ -2036,12 +2058,9 @@ CIRGenFunction::emitARMBuiltinExpr(unsigned builtinID, 
const CallExpr *expr,
   case NEON::BI__builtin_neon_vgetq_lane_bf16:
   case NEON::BI__builtin_neon_vgetq_lane_f32:
   case NEON::BI__builtin_neon_vduph_lane_bf16:
-  case NEON::BI__builtin_neon_vduph_laneq_bf16: {
-    mlir::Location loc = getLoc(expr->getExprLoc());
-    mlir::Value vec = emitScalarExpr(expr->getArg(0));
-    mlir::Value index = emitScalarExpr(expr->getArg(1));
-    return cir::VecExtractOp::create(builder, loc, vec, index);
-  }
+  case NEON::BI__builtin_neon_vduph_laneq_bf16:
+    return cir::VecExtractOp::create(builder, getLoc(expr->getExprLoc()),
+                                     ops[0], ops[1]);
   default:
     break;
   }

>From 6c5db3ff74a960121daa952139dfc3f870281cb7 Mon Sep 17 00:00:00 2001
From: AkshayK <[email protected]>
Date: Fri, 7 Aug 2026 19:37:12 -0400
Subject: [PATCH 3/3] [CIR][ARM] Drop the size_t lowering changes from this PR

Address review feedback: the size_t handling in the CIR to LLVM lowering is not
ARM-specific. It fixes the hardcoded i64 for the llvm.memcpy length and for
__cxa_allocate_exception on every 32-bit target, so it goes up separately along
with its own tests, which no longer need an ARM triple.

Nothing left in this PR depends on it; the two are independent.
---
 .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 18 +++++----------
 .../CodeGen/ARM/arm-aggregate-copy-size.cpp   | 21 ------------------
 .../CIR/CodeGen/ARM/arm-throw-alloc-size.cpp  | 22 -------------------
 3 files changed, 6 insertions(+), 55 deletions(-)
 delete mode 100644 clang/test/CIR/CodeGen/ARM/arm-aggregate-copy-size.cpp
 delete mode 100644 clang/test/CIR/CodeGen/ARM/arm-throw-alloc-size.cpp

diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp 
b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 50f82e0a445f5..717bf5e2e741e 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -287,19 +287,13 @@ static mlir::LLVM::CConv 
convertCallingConv(cir::CallingConv callingConv) {
   llvm_unreachable("Unknown calling convention");
 }
 
-/// Returns size_t as an integer type, mirroring CodeGenModule::SizeTy.
-static mlir::IntegerType getSizeTType(mlir::MLIRContext *ctx,
-                                      const mlir::DataLayout &dataLayout) {
-  return mlir::IntegerType::get(
-      ctx, 
dataLayout.getTypeSizeInBits(mlir::LLVM::LLVMPointerType::get(ctx)));
-}
-
 mlir::LogicalResult CIRToLLVMCopyOpLowering::matchAndRewrite(
     cir::CopyOp op, OpAdaptor adaptor,
     mlir::ConversionPatternRewriter &rewriter) const {
-  mlir::Type lenTy = getSizeTType(rewriter.getContext(), dataLayout);
+  mlir::DataLayout layout(op->getParentOfType<mlir::ModuleOp>());
   const mlir::Value length = mlir::LLVM::ConstantOp::create(
-      rewriter, op.getLoc(), lenTy, op.getCopySizeInBytes(dataLayout));
+      rewriter, op.getLoc(), rewriter.getI64Type(),
+      op.getCopySizeInBytes(layout));
   assert(!cir::MissingFeatures::aggValueSlotVolatile());
 
   uint64_t dstTypeAlign = dataLayout.getTypeABIAlignment(convertTypeForMemory(
@@ -4447,11 +4441,11 @@ mlir::LogicalResult 
CIRToLLVMThrowOpLowering::matchAndRewrite(
 mlir::LogicalResult CIRToLLVMAllocExceptionOpLowering::matchAndRewrite(
     cir::AllocExceptionOp op, OpAdaptor adaptor,
     mlir::ConversionPatternRewriter &rewriter) const {
-  // Get or create `declare ptr @__cxa_allocate_exception(size_t)`.
+  // Get or create `declare ptr @__cxa_allocate_exception(i64)`
   StringRef fnName = "__cxa_allocate_exception";
   auto llvmPtrTy = mlir::LLVM::LLVMPointerType::get(rewriter.getContext());
-  mlir::IntegerType sizeTTy = getSizeTType(rewriter.getContext(), dataLayout);
-  auto fnTy = mlir::LLVM::LLVMFunctionType::get(llvmPtrTy, {sizeTTy});
+  auto int64Ty = mlir::IntegerType::get(rewriter.getContext(), 64);
+  auto fnTy = mlir::LLVM::LLVMFunctionType::get(llvmPtrTy, {int64Ty});
 
   createLLVMFuncOpIfNotExist(rewriter, symbolTables, op, fnName, fnTy);
   auto exceptionSize = mlir::LLVM::ConstantOp::create(rewriter, op.getLoc(),
diff --git a/clang/test/CIR/CodeGen/ARM/arm-aggregate-copy-size.cpp 
b/clang/test/CIR/CodeGen/ARM/arm-aggregate-copy-size.cpp
deleted file mode 100644
index 72258e542d83d..0000000000000
--- a/clang/test/CIR/CodeGen/ARM/arm-aggregate-copy-size.cpp
+++ /dev/null
@@ -1,21 +0,0 @@
-// The llvm.memcpy length for a cir.copy is size_t-wide: i32 on 32-bit ARM.
-// RUN: %clang_cc1 -std=c++20 -triple arm-linux-gnueabihf -fclangir -emit-cir 
%s -o %t.cir
-// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
-// RUN: %clang_cc1 -std=c++20 -triple arm-linux-gnueabihf -fclangir -emit-llvm 
%s -o %t.ll
-// RUN: FileCheck --check-prefix=ARM --input-file=%t.ll %s
-// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir 
-emit-llvm %s -o %t-x86.ll
-// RUN: FileCheck --check-prefix=X86 --input-file=%t-x86.ll %s
-// RUN: %clang_cc1 -std=c++20 -triple arm-linux-gnueabihf -emit-llvm %s -o 
%t-ogcg.ll
-// RUN: FileCheck --check-prefix=ARM --input-file=%t-ogcg.ll %s
-
-struct P { int x; int y; };
-int sum(P p);
-int use() { P p; p.x = 1; p.y = 2; return sum(p); }
-
-// The width is resolved during lowering to LLVM, so CIR just has the copy.
-// CIR-LABEL: cir.func{{.*}} @_Z3usev()
-// CIR: cir.copy {{.*}} : !cir.ptr<!rec_P>
-
-// ARM: call void @llvm.memcpy.p0.p0.i32(ptr {{.*}}, ptr {{.*}}, i32 8, i1 
false)
-
-// X86: call void @llvm.memcpy.p0.p0.i64(ptr {{.*}}, ptr {{.*}}, i64 8, i1 
false)
diff --git a/clang/test/CIR/CodeGen/ARM/arm-throw-alloc-size.cpp 
b/clang/test/CIR/CodeGen/ARM/arm-throw-alloc-size.cpp
deleted file mode 100644
index 0d0d0db5f14fa..0000000000000
--- a/clang/test/CIR/CodeGen/ARM/arm-throw-alloc-size.cpp
+++ /dev/null
@@ -1,22 +0,0 @@
-// __cxa_allocate_exception's thrown_size is size_t: i32 on 32-bit ARM.
-// RUN: %clang_cc1 -std=c++20 -triple arm-linux-gnueabihf -fcxx-exceptions 
-fexceptions -fclangir -emit-cir %s -o %t.cir
-// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
-// RUN: %clang_cc1 -std=c++20 -triple arm-linux-gnueabihf -fcxx-exceptions 
-fexceptions -fclangir -emit-llvm %s -o %t.ll
-// RUN: FileCheck --check-prefix=ARM --input-file=%t.ll %s
-// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu 
-fcxx-exceptions -fexceptions -fclangir -emit-llvm %s -o %t-x86.ll
-// RUN: FileCheck --check-prefix=X86 --input-file=%t-x86.ll %s
-// RUN: %clang_cc1 -std=c++20 -triple arm-linux-gnueabihf -fcxx-exceptions 
-fexceptions -emit-llvm %s -o %t-ogcg.ll
-// RUN: FileCheck --check-prefix=ARM --input-file=%t-ogcg.ll %s
-
-void f() { throw 42; }
-
-// The width is resolved during lowering to LLVM.
-// CIR-LABEL: cir.func{{.*}} @_Z1fv()
-// CIR: cir.alloc.exception 4
-
-// CIR emits the declare first, classic CodeGen emits the call first.
-// ARM-DAG: declare ptr @__cxa_allocate_exception(i32)
-// ARM-DAG: call ptr @__cxa_allocate_exception(i32 4)
-
-// X86: declare ptr @__cxa_allocate_exception(i64)
-// X86: call ptr @__cxa_allocate_exception(i64 4)

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

Reply via email to