https://github.com/kumarak updated https://github.com/llvm/llvm-project/pull/204360
>From 23fe8191f022af0a10d5208571fc0c9de9af9dea Mon Sep 17 00:00:00 2001 From: AkshayK <[email protected]> Date: Wed, 17 Jun 2026 10:16:06 -0400 Subject: [PATCH 1/2] [CIR] Pointer and vptr width from a CIR-native data-layout entry Port of llvm/llvm-project#204185. Attach a cir.ptr data-layout entry at module setup storing {size, abi-align} read from the target DataLayout; PointerType and VPtrType read their width from it (falling back to 64/8 when absent), and the CIR->LLVM lowering strips the entry. Fixes record-layout crashes on targets with 32-bit pointers (e.g. nvptx, spirv32). --- clang/lib/CIR/CodeGen/CIRGenerator.cpp | 25 ++++++++- clang/lib/CIR/Dialect/IR/CIRTypes.cpp | 56 +++++++++++++++++-- .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 17 ++++++ .../test/CIR/CodeGen/pointer-width-32bit.cpp | 44 +++++++++++++++ 4 files changed, 135 insertions(+), 7 deletions(-) create mode 100644 clang/test/CIR/CodeGen/pointer-width-32bit.cpp diff --git a/clang/lib/CIR/CodeGen/CIRGenerator.cpp b/clang/lib/CIR/CodeGen/CIRGenerator.cpp index d4fcbb6e42f3e..61efaebad9b82 100644 --- a/clang/lib/CIR/CodeGen/CIRGenerator.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenerator.cpp @@ -21,6 +21,7 @@ #include "clang/AST/DeclGroup.h" #include "clang/CIR/CIRGenerator.h" #include "clang/CIR/InitAllDialects.h" +#include "clang/CIR/MissingFeatures.h" #include "llvm/IR/DataLayout.h" using namespace cir; @@ -42,7 +43,29 @@ static void setMLIRDataLayout(mlir::ModuleOp &mod, const llvm::DataLayout &dl) { mlir::MLIRContext *mlirContext = mod.getContext(); mlir::DataLayoutSpecInterface dlSpec = mlir::translateDataLayout(dl, mlirContext); - mod->setAttr(mlir::DLTIDialect::kDataLayoutAttrName, dlSpec); + + // Add a CIR-native pointer data-layout entry so cir.ptr / cir.vptr size and + // alignment are driven by the data layout rather than hardcoded. + // The value stores {size-in-bits, abi-align-in-bits} keyed on cir.ptr. + // + // TODO(cir): Only the default address space is recorded and + // address-space-dependent pointer sizes are not modeled yet. Emit + // per-address-space entries. + assert(!cir::MissingFeatures::dataLayoutPtrHandlingBasedOnLangAS()); + constexpr unsigned kBitsInByte = 8; + unsigned ptrSizeBits = dl.getPointerSizeInBits(/*AS=*/0); + unsigned ptrAlignBits = + dl.getPointerABIAlignment(/*AS=*/0).value() * kBitsInByte; + auto ptrKey = cir::PointerType::get(cir::VoidType::get(mlirContext)); + auto ptrVal = mlir::DenseI32ArrayAttr::get( + mlirContext, + {static_cast<int32_t>(ptrSizeBits), static_cast<int32_t>(ptrAlignBits)}); + llvm::SmallVector<mlir::DataLayoutEntryInterface> entries( + dlSpec.getEntries().begin(), dlSpec.getEntries().end()); + entries.push_back(mlir::DataLayoutEntryAttr::get(ptrKey, ptrVal)); + + mod->setAttr(mlir::DLTIDialect::kDataLayoutAttrName, + mlir::DataLayoutSpecAttr::get(mlirContext, entries)); } void CIRGenerator::Initialize(ASTContext &astContext) { diff --git a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp index 9c2a40e3681aa..04da6c85bbbb1 100644 --- a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp @@ -580,20 +580,62 @@ void RecordType::removeABIConversionNamePrefix() { // Data Layout information for types //===----------------------------------------------------------------------===// +// A CIR-native pointer data-layout entry stores {size-in-bits, +// abi-align-in-bits} as a dense i32 array keyed on a cir.ptr type (see +// setMLIRDataLayout in CIRGenerator). +namespace { +constexpr static uint64_t kBitsInByte = 8; + +// Defaults used only when the module carries no cir.ptr data-layout entry +// (e.g. CIR parsed from text without a data layout). These mirror the MLIR LLVM +// dialect's pointer defaults. +constexpr static uint64_t kDefaultPointerSizeBits = 64; +constexpr static uint64_t kDefaultPointerAlignment = 8; + +enum class CIRPtrDLPos { Size = 0, AbiAlign = 1 }; + +// Returns the requested field of the cir.ptr data-layout entry. +std::optional<uint64_t> getPointerSpecValue(mlir::DataLayoutEntryListRef params, + CIRPtrDLPos pos) { + for (mlir::DataLayoutEntryInterface entry : params) { + if (!entry.isTypeEntry()) + continue; + auto spec = mlir::dyn_cast<mlir::DenseI32ArrayAttr>(entry.getValue()); + assert(spec && spec.size() == 2 && + "malformed cir.ptr data layout entry: expected a pair of i32 " + "{size-in-bits, abi-align-in-bits}"); + return static_cast<uint64_t>(spec[static_cast<int>(pos)]); + } + return std::nullopt; +} +} // namespace + llvm::TypeSize PointerType::getTypeSizeInBits(const ::mlir::DataLayout &dataLayout, ::mlir::DataLayoutEntryListRef params) const { + // The pointer width comes from the CIR-native data-layout entry keyed on + // cir.ptr, which records the width for the default address space; fall back + // to 64 bits if the module carries no such entry. // FIXME: improve this in face of address spaces assert(!cir::MissingFeatures::dataLayoutPtrHandlingBasedOnLangAS()); - return llvm::TypeSize::getFixed(64); + if (std::optional<uint64_t> size = + getPointerSpecValue(params, CIRPtrDLPos::Size)) + return llvm::TypeSize::getFixed(*size); + return llvm::TypeSize::getFixed(kDefaultPointerSizeBits); } uint64_t PointerType::getABIAlignment(const ::mlir::DataLayout &dataLayout, ::mlir::DataLayoutEntryListRef params) const { + // As with the size, the alignment is taken from the default-address-space + // cir.ptr data-layout entry. Address-space-dependent alignments are not yet + // modeled. // FIXME: improve this in face of address spaces assert(!cir::MissingFeatures::dataLayoutPtrHandlingBasedOnLangAS()); - return 8; + if (std::optional<uint64_t> align = + getPointerSpecValue(params, CIRPtrDLPos::AbiAlign)) + return *align / kBitsInByte; + return kDefaultPointerAlignment; } llvm::TypeSize @@ -1112,14 +1154,16 @@ DataMemberType::getABIAlignment(const ::mlir::DataLayout &dataLayout, llvm::TypeSize VPtrType::getTypeSizeInBits(const mlir::DataLayout &dataLayout, mlir::DataLayoutEntryListRef params) const { - // FIXME: consider size differences under different ABIs - return llvm::TypeSize::getFixed(64); + // The vtable pointer is an ordinary data pointer; route the query through a + // cir.ptr so it picks up the same data-layout-driven width. + return dataLayout.getTypeSizeInBits( + cir::PointerType::get(cir::VoidType::get(getContext()))); } uint64_t VPtrType::getABIAlignment(const mlir::DataLayout &dataLayout, mlir::DataLayoutEntryListRef params) const { - // FIXME: consider alignment differences under different ABIs - return 8; + return dataLayout.getTypeABIAlignment( + cir::PointerType::get(cir::VoidType::get(getContext()))); } //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index e0fc9e58ed4b7..00c94b37e1a6c 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -3794,6 +3794,23 @@ void ConvertCIRToLLVMPass::runOnOperation() { if (failed(applyPartialConversion(ops, target, std::move(patterns)))) signalPassFailure(); + // The CIR-native pointer data-layout entry (keyed on cir.ptr) drives pointer + // widths during CIR codegen and lowering, but cir.ptr has no meaning once the + // module is translated to LLVM IR. Drop it so the resulting data layout only + // references LLVM types. + if (auto dlSpec = mlir::dyn_cast_or_null<mlir::DataLayoutSpecAttr>( + module->getAttr(mlir::DLTIDialect::kDataLayoutAttrName))) { + llvm::SmallVector<mlir::DataLayoutEntryInterface> kept; + for (mlir::DataLayoutEntryInterface entry : dlSpec.getEntries()) { + if (entry.isTypeEntry() && + mlir::isa<cir::PointerType>(mlir::cast<mlir::Type>(entry.getKey()))) + continue; + kept.push_back(entry); + } + module->setAttr(mlir::DLTIDialect::kDataLayoutAttrName, + mlir::DataLayoutSpecAttr::get(module.getContext(), kept)); + } + // Emit the llvm.global_ctors array. buildCtorDtorList(module, cir::CIRDialect::getGlobalCtorsAttrName(), "llvm.global_ctors", [](mlir::Attribute attr) { diff --git a/clang/test/CIR/CodeGen/pointer-width-32bit.cpp b/clang/test/CIR/CodeGen/pointer-width-32bit.cpp new file mode 100644 index 0000000000000..15f3ec92d7e16 --- /dev/null +++ b/clang/test/CIR/CodeGen/pointer-width-32bit.cpp @@ -0,0 +1,44 @@ +// RUN: %clang_cc1 -std=c++20 -triple nvptx-nvidia-cuda -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s +// RUN: %clang_cc1 -std=c++20 -triple nvptx-nvidia-cuda -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s +// RUN: %clang_cc1 -std=c++20 -triple nvptx-nvidia-cuda -emit-llvm %s -o %t.ll +// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s + +// On a target with 32-bit pointers (e.g. nvptx) both a data pointer (!cir.ptr) +// and the vtable pointer (!cir.vptr) are 4 bytes wide. The pointer width is +// carried by a CIR-native data-layout entry keyed on cir.ptr, so the field +// following a pointer lands at the AST-mandated offset. Sizing pointers as a +// hardcoded 64 bits previously tripped the record layout builder (insertPadding: +// assertion `offset >= size`) on every record containing a pointer. + +struct S { + int *p; + int x; +}; + +S s; + +class A { +public: + virtual void f(); + int x; +}; + +void A::f() {} + +// The module carries a CIR-native pointer data-layout entry ({size, abi-align} +// in bits) that drives both cir.ptr and cir.vptr widths. The 4-byte pointer is +// immediately followed by 'x' at offset 4 with no padding, and each record is +// 4-byte aligned. +// 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> = array<i32: 32, 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 >From bfec19785b8b6dd358c96d08c4e8c4c62a15f85b Mon Sep 17 00:00:00 2001 From: AkshayK <[email protected]> Date: Tue, 30 Jun 2026 12:39:21 -0400 Subject: [PATCH 2/2] [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 | 38 ++++++++++++++++++ clang/lib/CIR/CodeGen/CIRGenFunction.h | 4 ++ .../TargetLowering/LowerItaniumCXXABI.cpp | 8 ++++ .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 26 +++++++++---- .../CodeGen/ARM/arm-aggregate-copy-size.cpp | 23 +++++++++++ .../CIR/CodeGen/ARM/arm-record-layout.cpp | 39 +++++++++++++++++++ .../CIR/CodeGen/ARM/arm-throw-alloc-size.cpp | 23 +++++++++++ .../CodeGenBuiltins/ARM/arm-neon-vget-lane.c | 27 +++++++++++++ 9 files changed, 182 insertions(+), 10 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-neon-vget-lane.c diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp index 3b8149411e7c4..5f6bbb9fe9170 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp @@ -2744,9 +2744,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 e3418d561df34..2432b534ce8a0 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp @@ -1844,6 +1844,44 @@ 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-read intrinsics are implemented for 32-bit ARM so far; + // they lower to a vector element extraction, matching classic CodeGen + // (clang/lib/CodeGen/TargetBuiltins/ARM.cpp) and the AArch64 path. Every other + // ARM builtin is reported as not-yet-implemented rather than silently ignored. + 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)); + return mlir::Value{}; +} + 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 322355fde3957..39455339fba29 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.h +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h @@ -1542,6 +1542,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 5218d4979f353..f5a0f51f7ab86 100644 --- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp +++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp @@ -144,6 +144,14 @@ std::unique_ptr<CIRCXXABI> createItaniumCXXABI(LowerModule &lm) { /*useARMMethodPtrABI=*/true, /*use32BitVTableOffsetABI=*/true); + case clang::TargetCXXABI::GenericARM: + // 32-bit ARM uses the ARM method-pointer encoding but, unlike AppleARM64, + // does not use 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 00c94b37e1a6c..656240a26223f 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -212,9 +212,14 @@ mlir::LogicalResult CIRToLLVMCopyOpLowering::matchAndRewrite( cir::CopyOp op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const { mlir::DataLayout layout(op->getParentOfType<mlir::ModuleOp>()); + // The llvm.memcpy length is size_t-wide; its width is target-dependent (e.g. + // 32 bits on 32-bit ARM), so drive it from the data layout rather than + // hardcoding i64. + auto llvmPtrTy = mlir::LLVM::LLVMPointerType::get(rewriter.getContext()); + mlir::Type lenTy = + rewriter.getIntegerType(layout.getTypeSizeInBits(llvmPtrTy)); const mlir::Value length = mlir::LLVM::ConstantOp::create( - rewriter, op.getLoc(), rewriter.getI64Type(), - op.getCopySizeInBytes(layout)); + rewriter, op.getLoc(), lenTy, op.getCopySizeInBytes(layout)); assert(!cir::MissingFeatures::aggValueSlotVolatile()); rewriter.replaceOpWithNewOp<mlir::LLVM::MemcpyOp>( op, adaptor.getDst(), adaptor.getSrc(), length, op.getIsVolatile()); @@ -3971,15 +3976,22 @@ 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)`. The + // thrown_size parameter is size_t, whose width is target-dependent (e.g. 32 + // bits on 32-bit ARM), so drive it from the data layout rather than + // hardcoding i64; otherwise the call mismatches the runtime on 32-bit + // targets. 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::DataLayout layout(op->getParentOfType<mlir::ModuleOp>()); + auto sizeTTy = mlir::IntegerType::get(rewriter.getContext(), + layout.getTypeSizeInBits(llvmPtrTy)); + auto fnTy = mlir::LLVM::LLVMFunctionType::get(llvmPtrTy, {sizeTTy}); createLLVMFuncOpIfNotExist(rewriter, op, fnName, fnTy); - auto exceptionSize = mlir::LLVM::ConstantOp::create(rewriter, op.getLoc(), - adaptor.getSizeAttr()); + auto exceptionSize = mlir::LLVM::ConstantOp::create( + rewriter, op.getLoc(), sizeTTy, + rewriter.getIntegerAttr(sizeTTy, op.getSize())); auto allocaExceptionCall = mlir::LLVM::CallOp::create( rewriter, op.getLoc(), mlir::TypeRange{llvmPtrTy}, fnName, 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..0d687d85d06b3 --- /dev/null +++ b/clang/test/CIR/CodeGen/ARM/arm-aggregate-copy-size.cpp @@ -0,0 +1,23 @@ +// The length operand of the llvm.memcpy emitted for a cir.copy (e.g. passing an +// aggregate by value) is size_t-wide, whose width is target-dependent. On +// 32-bit ARM it must be i32, not the hardcoded i64 used by 64-bit targets. +// +// 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 + +struct P { int x; int y; }; +int sum(P p); +int use() { P p; p.x = 1; p.y = 2; return sum(p); } + +// The aggregate pass-by-value lowers to a cir.copy; its memcpy length width is +// resolved later, during lowering to LLVM, from the data layout. +// 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..53a8d6024f0f5 --- /dev/null +++ b/clang/test/CIR/CodeGen/ARM/arm-record-layout.cpp @@ -0,0 +1,39 @@ +// 32-bit ARM lowers end-to-end through CIR, including the GenericARM CXXABI +// path (virtual classes / vtables). A record containing a pointer lays out with +// a 4-byte pointer followed by the next field with no padding, and both records +// are 4-byte aligned. +// +// +// 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> = array<i32: 32, 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..0624905590a1f --- /dev/null +++ b/clang/test/CIR/CodeGen/ARM/arm-throw-alloc-size.cpp @@ -0,0 +1,23 @@ +// The thrown_size argument to __cxa_allocate_exception is size_t, whose width +// is target-dependent. On 32-bit ARM it must be i32, not the hardcoded i64 +// used by 64-bit targets. +// +// 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 + +void f() { throw 42; } + +// The thrown size is carried as an attribute in CIR; its size_t width for the +// __cxa_allocate_exception call is resolved later, during lowering to LLVM. +// CIR-LABEL: cir.func{{.*}} @_Z1fv() +// CIR: cir.alloc.exception 4 + +// ARM: declare ptr @__cxa_allocate_exception(i32) +// ARM: 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-neon-vget-lane.c b/clang/test/CIR/CodeGenBuiltins/ARM/arm-neon-vget-lane.c new file mode 100644 index 0000000000000..f045ed753ecd5 --- /dev/null +++ b/clang/test/CIR/CodeGenBuiltins/ARM/arm-neon-vget-lane.c @@ -0,0 +1,27 @@ +// The NEON lane-read intrinsics (vget_lane/vgetq_lane) lower to __builtin_neon_* +// builtins on 32-bit ARM (unlike AArch64, where arm_neon.h uses generic vector +// subscripting). Make sure CIR codegen lowers them to a vector element +// extraction instead of reporting them as unimplemented. + +// RUN: %clang_cc1 -triple armv7-unknown-linux-gnueabihf -target-feature +neon -ffreestanding -fclangir -emit-cir %s -o - | FileCheck %s --check-prefix=CIR +// RUN: %clang_cc1 -triple armv7-unknown-linux-gnueabihf -target-feature +neon -ffreestanding -fclangir -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 dso_local i32 @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 dso_local float @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 dso_local i16 @get_s16( +// LLVM: extractelement <4 x i16> %{{.*}}, i32 3 +short get_s16(int16x4_t v) { return vget_lane_s16(v, 3); } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
