llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Akshay K (kumarak)
<details>
<summary>Changes</summary>
This PR adds 32-bit ARM support to ClangIR. Before this, CIR assumed 64-bit
pointers and the generic Itanium C++ ABI, so 32-bit ARM targets crashed.
The changes are built on two foundational fixes that are also useful on their
own (nvptx/spirv32 and other 32-bit targets); they are sent up separately, and
this work stacks on top of them (#<!-- -->203942 and #<!-- -->204185)
PR changes include:
- CXXABI dispatch: handle GenericARM in the transform-pass CXXABI dispatch,
selecting the ARM method-pointer ABI and matching non-virtual member-pointer
layout.
- Array cookie: use the two-word `{element-size, element-count}` cookie for
`new[]`/`delete[]` of types with a non-trivial
destructor.
- ABI matching(constructor/destructor): return this from constructors and
non-deleting destructors, and mark the this argument with the returned
parameter attribute, mirroring CodeGenModule::SetFunctionAttributes.
- Target-dependent widths: drive the `size_t` width of
`__cxa_allocate_exception` and the `llvm.memcpy` length emitted for `cir.copy`
from the data layout instead of hardcoding `i64`, so 32-bit targets emit `i32`.
- NEON lane handling: implement the `vget_lane`/`vgetq_lane family` as a
vector element extraction (they lower to `__builtin_neon_*` on ARM, unlike
AArch64); other ARM builtins still report NYI rather than miscompiling.
- Added new unit tests covering the supported 32-bit ARM ABI features and
associated code generation behavior.
---
Patch is 43.84 KiB, truncated to 20.00 KiB below, full version:
https://github.com/llvm/llvm-project/pull/204360.diff
24 Files Affected:
- (modified) clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp (+34-3)
- (modified) clang/lib/CIR/CodeGen/CIRGenCXX.cpp (+7-2)
- (modified) clang/lib/CIR/CodeGen/CIRGenCXXABI.cpp (+4)
- (modified) clang/lib/CIR/CodeGen/CIRGenCXXABI.h (+4)
- (modified) clang/lib/CIR/CodeGen/CIRGenCall.cpp (+3-7)
- (modified) clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp (+5-3)
- (modified) clang/lib/CIR/CodeGen/CIRGenFunction.cpp (+5-3)
- (modified) clang/lib/CIR/CodeGen/CIRGenFunction.h (+4)
- (modified) clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp (+48-7)
- (modified) clang/lib/CIR/CodeGen/CIRGenModule.cpp (+12)
- (modified) clang/lib/CIR/CodeGen/CIRGenerator.cpp (+24-1)
- (modified) clang/lib/CIR/Dialect/IR/CIRTypes.cpp (+50-6)
- (modified) clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp (+10-1)
- (modified)
clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp (+24-4)
- (modified) clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp (+36-7)
- (added) clang/test/CIR/CodeGen/arm-aggregate-copy-size.cpp (+16)
- (added) clang/test/CIR/CodeGen/arm-array-cookie.cpp (+32)
- (added) clang/test/CIR/CodeGen/arm-global-dtor.cpp (+29)
- (added) clang/test/CIR/CodeGen/arm-neon-vget-lane.c (+20)
- (added) clang/test/CIR/CodeGen/arm-record-layout.cpp (+39)
- (added) clang/test/CIR/CodeGen/arm-this-return.cpp (+28)
- (added) clang/test/CIR/CodeGen/arm-throw-alloc-size.cpp (+16)
- (added) clang/test/CIR/CodeGen/pointer-width-32bit.cpp (+44)
- (added) clang/test/CIR/CodeGen/unary-expr-or-type-trait-32bit.cpp (+38)
``````````diff
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index a483eb635f0e2..8a9c0c7edd088 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -24,6 +24,7 @@
#include "clang/Basic/Builtins.h"
#include "clang/Basic/DiagnosticFrontend.h"
#include "clang/Basic/OperatorKinds.h"
+#include "clang/Basic/TargetBuiltins.h"
#include "clang/CIR/Dialect/IR/CIRTypes.h"
#include "clang/CIR/MissingFeatures.h"
#include "llvm/IR/Intrinsics.h"
@@ -2647,6 +2648,38 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl
&gd, unsigned builtinID,
return getUndefRValue(e->getType());
}
+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.
+ switch (builtinID) {
+ default:
+ return std::nullopt;
+ 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);
+ }
+ }
+}
+
static std::optional<mlir::Value>
emitTargetArchBuiltinExpr(CIRGenFunction *cgf, unsigned builtinID,
const CallExpr *e, ReturnValueSlot &returnValue,
@@ -2666,9 +2699,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/CIRGenCXX.cpp
b/clang/lib/CIR/CodeGen/CIRGenCXX.cpp
index 9c008acbc6f68..54659c03da092 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCXX.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCXX.cpp
@@ -176,8 +176,13 @@ static void emitDeclDestroy(CIRGenFunction &cgf, const
VarDecl *vd,
mlir::cast<cir::PointerType>(thisAddr.getType()).getAddrSpace());
if (realPtrTy != thisAddr.getType())
thisAddr = builder.createBitcast(thisAddr.getLoc(), thisAddr, realPtrTy);
- builder.createCallOp(cgf.getLoc(vd->getSourceRange()),
- mlir::FlatSymbolRefAttr::get(fnOp.getSymNameAttr()),
+ // Build the call against the destructor's actual signature rather than
+ // forcing a void result. Under the ARM C++ ABI structors return `this`,
+ // so a void-typed call would have fewer results than the callee and fail
+ // verification. The FuncOp overload derives the result type from the
+ // destructor itself; the returned `this` is unused here and is discarded
+ // when LoweringPrepare registers the destructor with __cxa_atexit.
+ builder.createCallOp(cgf.getLoc(vd->getSourceRange()), fnOp,
mlir::ValueRange{thisAddr});
assert(fnOp && "expected cir.func");
// TODO(cir): This doesn't do anything but check for unhandled conditions.
diff --git a/clang/lib/CIR/CodeGen/CIRGenCXXABI.cpp
b/clang/lib/CIR/CodeGen/CIRGenCXXABI.cpp
index 83062c3906edf..ad493668ab06d 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCXXABI.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCXXABI.cpp
@@ -80,6 +80,10 @@ void CIRGenCXXABI::setCXXABIThisValue(CIRGenFunction &cgf,
cgf.cxxabiThisValue = thisPtr;
}
+mlir::Value CIRGenCXXABI::getThisValue(CIRGenFunction &cgf) {
+ return cgf.cxxabiThisValue;
+}
+
CharUnits CIRGenCXXABI::getArrayCookieSize(const CXXNewExpr *e) {
if (!requiresArrayCookie(e))
return CharUnits::Zero();
diff --git a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
index bb100f7afd929..c36fc4517f961 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
+++ b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
@@ -166,6 +166,10 @@ class CIRGenCXXABI {
/// Loads the incoming C++ this pointer as it was passed by the caller.
mlir::Value loadIncomingCXXThis(CIRGenFunction &cgf);
+ /// Returns the C++ this pointer as set by setCXXABIThisValue, before any
+ /// adjustment.
+ mlir::Value getThisValue(CIRGenFunction &cgf);
+
virtual CatchTypeInfo
getAddrOfCXXCatchHandlerType(mlir::Location loc, QualType ty,
QualType catchHandlerType) = 0;
diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.cpp
b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
index f648eff375a77..83665b5ec3947 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
@@ -839,9 +839,6 @@ CIRGenTypes::arrangeCXXStructorDeclaration(GlobalDecl gd) {
? astContext.VoidPtrTy
: astContext.VoidTy;
- assert(!theCXXABI.hasThisReturn(gd) &&
- "Please send PR with a test and remove this");
-
assert(!cir::MissingFeatures::opCallCIRGenFuncInfoExtParamInfo());
assert(!cir::MissingFeatures::opCallFnInfoOpts());
@@ -973,13 +970,12 @@ const CIRGenFunctionInfo
&CIRGenTypes::arrangeCXXConstructorCall(
: RequiredArgs::All;
GlobalDecl gd(d, ctorKind);
- if (theCXXABI.hasThisReturn(gd))
- cgm.errorNYI(d->getSourceRange(),
- "arrangeCXXConstructorCall: hasThisReturn");
if (theCXXABI.hasMostDerivedReturn(gd))
cgm.errorNYI(d->getSourceRange(),
"arrangeCXXConstructorCall: hasMostDerivedReturn");
- CanQualType resultType = astContext.VoidTy;
+ // args[0] is the implicit 'this'; ABIs that return 'this' use its type.
+ CanQualType resultType =
+ theCXXABI.hasThisReturn(gd) ? argTypes.front() : astContext.VoidTy;
assert(!cir::MissingFeatures::opCallFnInfoOpts());
assert(!cir::MissingFeatures::opCallCIRGenFuncInfoExtParamInfo());
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
index c7e19c38dbba1..5e8bb9df83ab3 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
@@ -2773,16 +2773,18 @@ mlir::Value
ScalarExprEmitter::VisitUnaryExprOrTypeTraitExpr(
e->getSourceRange(),
"VisitUnaryExprOrTypeTraitExpr: sizeOf scalable vector");
return builder.getConstant(
- loc, cir::IntAttr::get(cgf.cgm.uInt64Ty,
+ loc, cir::IntAttr::get(cgf.cgm.sizeTy,
e->EvaluateKnownConstInt(cgf.getContext())));
}
return builder.getConstant(
- loc, cir::IntAttr::get(cgf.cgm.uInt64Ty, vecTy.getSize()));
+ loc, cir::IntAttr::get(cgf.cgm.sizeTy, vecTy.getSize()));
}
+ // The result type is size_t (target-dependent width); use it so the IntAttr
+ // width matches the APInt from EvaluateKnownConstInt.
return builder.getConstant(
- loc, cir::IntAttr::get(cgf.cgm.uInt64Ty,
+ loc, cir::IntAttr::get(cgf.cgm.sizeTy,
e->EvaluateKnownConstInt(cgf.getContext())));
}
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
index 4b020c96964a7..856bcb530974c 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
@@ -1031,11 +1031,13 @@ clang::QualType
CIRGenFunction::buildFunctionArgList(clang::GlobalDecl gd,
// object as a regular parameter that fd->parameters() already enumerates.
const auto *md = dyn_cast<CXXMethodDecl>(fd);
if (md && md->isImplicitObjectMemberFunction()) {
- if (cgm.getCXXABI().hasThisReturn(gd))
- cgm.errorNYI(fd->getSourceRange(), "this return");
- else if (cgm.getCXXABI().hasMostDerivedReturn(gd))
+ if (cgm.getCXXABI().hasMostDerivedReturn(gd))
cgm.errorNYI(fd->getSourceRange(), "most derived return");
cgm.getCXXABI().buildThisParam(*this, args);
+ // ABIs that return 'this' make the function's return type the 'this'
+ // pointer, so a return slot is allocated and the prolog can store into it.
+ if (cgm.getCXXABI().hasThisReturn(gd))
+ retTy = args.front()->getType();
}
bool passedParams = true;
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h
b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index 317151c8d61c6..d3853067af5b0 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -1537,6 +1537,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/CodeGen/CIRGenItaniumCXXABI.cpp
b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
index 552d73966e97b..3953e9badf604 100644
--- a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
@@ -37,12 +37,31 @@ class CIRGenItaniumCXXABI : public CIRGenCXXABI {
/// All the vtables which have been defined.
llvm::DenseMap<const CXXRecordDecl *, cir::GlobalOp> vtables;
+ /// 32-bit ARM uses a two-word array cookie ({element_size, element_count})
+ /// rather than the generic single-size_t cookie.
+ bool useARMArrayCookieABI;
+
+ /// 32-bit ARM returns 'this' from constructors and non-deleting destructors.
+ bool useARMThisReturnABI;
+
public:
- CIRGenItaniumCXXABI(CIRGenModule &cgm) : CIRGenCXXABI(cgm) {
+ CIRGenItaniumCXXABI(CIRGenModule &cgm, bool useARMArrayCookieABI = false,
+ bool useARMThisReturnABI = false)
+ : CIRGenCXXABI(cgm), useARMArrayCookieABI(useARMArrayCookieABI),
+ useARMThisReturnABI(useARMThisReturnABI) {
assert(!cir::MissingFeatures::cxxabiUseARMMethodPtrABI());
assert(!cir::MissingFeatures::cxxabiUseARMGuardVarABI());
}
+ bool hasThisReturn(clang::GlobalDecl gd) const override {
+ if (!useARMThisReturnABI)
+ return false;
+ // Constructors and non-deleting destructors return 'this'.
+ return isa<CXXConstructorDecl>(gd.getDecl()) ||
+ (isa<CXXDestructorDecl>(gd.getDecl()) &&
+ gd.getDtorType() != Dtor_Deleting);
+ }
+
AddedStructorArgs getImplicitConstructorArgs(CIRGenFunction &cgf,
const CXXConstructorDecl *d,
CXXCtorType type,
@@ -262,8 +281,10 @@ void
CIRGenItaniumCXXABI::emitInstanceFunctionProlog(SourceLocation loc,
/// 2) in theory, an ABI could implement 'this' returns some other way;
/// HasThisReturn only specifies a contract, not the implementation
if (hasThisReturn(cgf.curGD)) {
- cgf.cgm.errorNYI(cgf.curFuncDecl->getLocation(),
- "emitInstanceFunctionProlog: hasThisReturn");
+ // Store 'this' into the return slot at function entry; the epilogue
+ // returns whatever is in that slot.
+ cgf.getBuilder().createStore(cgf.getLoc(loc), getThisValue(cgf),
+ cgf.returnValue);
}
}
@@ -1872,9 +1893,14 @@ CIRGenCXXABI
*clang::CIRGen::CreateCIRGenItaniumCXXABI(CIRGenModule &cgm) {
switch (cgm.getASTContext().getCXXABIKind()) {
case TargetCXXABI::GenericItanium:
case TargetCXXABI::GenericAArch64:
- case TargetCXXABI::GenericARM:
return new CIRGenItaniumCXXABI(cgm);
+ case TargetCXXABI::GenericARM:
+ // 32-bit ARM uses the two-word array cookie and returns 'this' from
+ // constructors and non-deleting destructors.
+ return new CIRGenItaniumCXXABI(cgm, /*useARMArrayCookieABI=*/true,
+ /*useARMThisReturnABI=*/true);
+
case TargetCXXABI::AppleARM64:
// The general Itanium ABI will do until we implement something that
// requires special handling.
@@ -2420,6 +2446,12 @@ void CIRGenItaniumCXXABI::emitVirtualObjectDelete(
/************************** Array allocation cookies
**************************/
CharUnits CIRGenItaniumCXXABI::getArrayCookieSizeImpl(QualType elementType) {
+ if (useARMArrayCookieABI) {
+ // On 32-bit ARM the cookie is always two size_t words:
+ // struct array_cookie { size_t element_size; size_t element_count; };
+ return cgm.getSizeSize() * 2;
+ }
+
// The array cookie is a size_t; pad that up to the element alignment.
// The cookie is actually right-justified in that space.
return std::max(
@@ -2444,9 +2476,7 @@ Address
CIRGenItaniumCXXABI::initializeArrayCookie(CIRGenFunction &cgf,
mlir::Location loc = cgf.getLoc(e->getSourceRange());
// The size of the cookie.
- CharUnits cookieSize =
- std::max(sizeSize, ctx.getPreferredTypeAlignInChars(elementType));
- assert(cookieSize == getArrayCookieSizeImpl(elementType));
+ CharUnits cookieSize = getArrayCookieSizeImpl(elementType);
mlir::Type u8Ty = cgf.getBuilder().getUInt8Ty();
cir::PointerType u8PtrTy = cgf.getBuilder().getUInt8PtrTy();
@@ -2472,6 +2502,17 @@ Address
CIRGenItaniumCXXABI::initializeArrayCookie(CIRGenFunction &cgf,
cookiePtr.withElementType(cgf.getBuilder(), cgf.sizeTy);
cgf.getBuilder().createStore(loc, numElements, numElementsPtr);
+ // On 32-bit ARM the cookie's first word holds the element size.
+ if (useARMArrayCookieABI) {
+ CharUnits eltSize = ctx.getTypeSizeInChars(elementType);
+ Address eltSizePtr(baseBytePtr, u8Ty, baseAlignment);
+ Address eltSizeSlot =
+ eltSizePtr.withElementType(cgf.getBuilder(), cgf.sizeTy);
+ mlir::Value eltSizeVal =
+ cgf.getBuilder().getConstInt(loc, cgf.sizeTy, eltSize.getQuantity());
+ cgf.getBuilder().createStore(loc, eltSizeVal, eltSizeSlot);
+ }
+
// Finally, compute a pointer to the actual data buffer by skipping
// over the cookie completely.
mlir::Value dataOffset =
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp
b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
index b377f84e8d370..c01c1a46d29b0 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
@@ -16,6 +16,7 @@
#include "CIRGenConstantEmitter.h"
#include "CIRGenFunction.h"
+#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
#include "mlir/Dialect/OpenMP/OpenMPOffloadUtils.h"
#include "mlir/IR/SymbolTable.h"
#include "clang/AST/ASTContext.h"
@@ -3016,6 +3017,17 @@ void CIRGenModule::setFunctionAttributes(GlobalDecl
globalDecl,
getTypes().arrangeGlobalDeclaration(globalDecl),
func, isThunk);
+ // Add the `returned` attribute for "this" on constructors/destructors that
+ // return it (e.g. under the ARM C++ ABI), except for iOS 5 and earlier where
+ // substantial code, including the libstdc++ dylib, was compiled with GCC and
+ // does not actually return "this".
+ if (!isThunk && getCXXABI().hasThisReturn(globalDecl) &&
+ !(getTriple().isiOS() && getTriple().isOSVersionLT(6))) {
+ assert(func.getNumArguments() != 0 && "unexpected this return");
+ func.setArgAttr(0, mlir::LLVM::LLVMDialect::getReturnedAttrName(),
+ mlir::UnitAttr::get(&getMLIRContext()));
+ }
+
if (!isIncompleteFunction && func.isDeclaration())
getTargetCIRGenInfo().setTargetAttributes(funcDecl, func, *this);
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 ...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/204360
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits