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
