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

Reply via email to