https://github.com/xakep8 updated 
https://github.com/llvm/llvm-project/pull/229202

>From b248e0cd5e29960eb26898f9247e0b6304103da1 Mon Sep 17 00:00:00 2001
From: Kunal Dubey <[email protected]>
Date: Tue, 6 Oct 2026 13:35:57 +0530
Subject: [PATCH] [LLVMABI][AArch64] Support aggregate arguments

Implement AArch64 argument classification for fixed-size aggregates.
---
 .../Transforms/CallConvLoweringPass.cpp       |   7 +-
 clang/lib/CodeGen/QualTypeMapper.cpp          |  39 ++--
 clang/lib/CodeGen/QualTypeMapper.h            |   4 +-
 .../AArch64/abi-classify-arg-pointer-like.m   |  46 ++++
 .../CodeGen/AArch64/abi-classify-arg-types.c  |  94 ++++++--
 .../AArch64/abi-classify-arg-types.cpp        |  30 ++-
 .../unittests/CodeGen/QualTypeMapperTest.cpp  |  71 ++++++
 llvm/include/llvm/ABI/Types.h                 |  31 ++-
 llvm/lib/ABI/Targets/AArch64.cpp              |  56 ++++-
 llvm/lib/ABI/Targets/AMDGPU.cpp               |   6 +-
 llvm/unittests/ABI/AArch64TargetInfoTest.cpp  | 207 +++++++++++++++++-
 llvm/unittests/ABI/AMDGPUTargetInfoTest.cpp   |   9 +-
 llvm/unittests/ABI/TypesTest.cpp              |  24 +-
 llvm/unittests/ABI/X86TargetInfoTest.cpp      |  12 +-
 mlir/lib/ABI/ABITypeMapper.cpp                |   3 +-
 15 files changed, 582 insertions(+), 57 deletions(-)
 create mode 100644 clang/test/CodeGen/AArch64/abi-classify-arg-pointer-like.m

diff --git a/clang/lib/CIR/Dialect/Transforms/CallConvLoweringPass.cpp 
b/clang/lib/CIR/Dialect/Transforms/CallConvLoweringPass.cpp
index 402cd09afd63700..4d320aa159da97a 100644
--- a/clang/lib/CIR/Dialect/Transforms/CallConvLoweringPass.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/CallConvLoweringPass.cpp
@@ -361,16 +361,19 @@ static const llvm::abi::Type *mapCIRType(mlir::Type type,
                 dyn_cast_if_present<cir::TargetAddressSpaceAttr>(
                     ptrTy.getAddrSpace()))
           addrSpace = targetAsAttr.getValue();
+        // CIR does not preserve source-level pointer-kind information.
         return tb.getPointerType(dl.getTypeSizeInBits(type),
                                  llvm::Align(dl.getTypeABIAlignment(type)),
-                                 addrSpace);
+                                 addrSpace, llvm::abi::PointerFlags::None);
       })
       .Case([&](cir::VPtrType) {
         // cir::VPtrType carries no address-space parameter yet, so this
         // always maps into the default one until that gap closes.
         assert(!cir::MissingFeatures::addressSpace());
         return tb.getPointerType(dl.getTypeSizeInBits(type),
-                                 llvm::Align(dl.getTypeABIAlignment(type)));
+                                 llvm::Align(dl.getTypeABIAlignment(type)),
+                                 /*Addrspace=*/0,
+                                 
llvm::abi::PointerFlags::IsPointerOrReference);
       })
       .Case([&](cir::BoolType) {
         return tb.getIntegerType(dl.getTypeSizeInBits(type),
diff --git a/clang/lib/CodeGen/QualTypeMapper.cpp 
b/clang/lib/CodeGen/QualTypeMapper.cpp
index 5044883a49ca2e8..841e0dcdc905589 100644
--- a/clang/lib/CodeGen/QualTypeMapper.cpp
+++ b/clang/lib/CodeGen/QualTypeMapper.cpp
@@ -103,11 +103,14 @@ const llvm::abi::Type 
*QualTypeMapper::convertTypeImpl(QualType QT) {
   case Type::Builtin:
     return convertBuiltinType(cast<BuiltinType>(QT));
   case Type::Pointer:
-    return 
createPointerTypeForPointee(cast<PointerType>(QT)->getPointeeType());
+    return createPointerTypeForPointee(
+        cast<PointerType>(QT)->getPointeeType(),
+        llvm::abi::PointerFlags::IsPointerOrReference);
   case Type::LValueReference:
   case Type::RValueReference:
     return createPointerTypeForPointee(
-        cast<ReferenceType>(QT)->getPointeeType());
+        cast<ReferenceType>(QT)->getPointeeType(),
+        llvm::abi::PointerFlags::IsPointerOrReference);
   case Type::ConstantArray:
   case Type::ArrayParameter:
   case Type::IncompleteArray:
@@ -129,7 +132,8 @@ const llvm::abi::Type 
*QualTypeMapper::convertTypeImpl(QualType QT) {
   }
   case Type::BlockPointer:
   case Type::Pipe:
-    return createPointerTypeForPointee(ASTCtx.VoidPtrTy);
+    return createPointerTypeForPointee(ASTCtx.VoidPtrTy,
+                                       llvm::abi::PointerFlags::None);
   case Type::ConstantMatrix: {
     const auto *MT = cast<ConstantMatrixType>(QT);
     return Builder.getArrayType(convertType(MT->getElementType()),
@@ -146,13 +150,18 @@ const llvm::abi::Type 
*QualTypeMapper::convertTypeImpl(QualType QT) {
   }
   case Type::ObjCObject:
   case Type::ObjCInterface:
-  case Type::ObjCObjectPointer:
+  case Type::ObjCObjectPointer: {
     // Objective-C objects are represented as pointers in the ABI.
+    llvm::abi::PointerFlags Flags = llvm::abi::PointerFlags::None;
+    if (QT.hasAddressSpace())
+      Flags |= llvm::abi::PointerFlags::IsPointeeAddressSpaceQualified;
     return Builder.getPointerType(
         ASTCtx.getTargetInfo().getPointerWidth(QT.getAddressSpace()),
         llvm::Align(
             ASTCtx.getTargetInfo().getPointerAlign(QT.getAddressSpace()) / 8),
-        ASTCtx.getTargetInfo().getTargetAddressSpace(QT.getAddressSpace()));
+        ASTCtx.getTargetInfo().getTargetAddressSpace(QT.getAddressSpace()),
+        Flags);
+  }
   case Type::OverflowBehavior:
     return convertType(cast<OverflowBehaviorType>(QT)->getUnderlyingType());
   case Type::Auto:
@@ -178,7 +187,7 @@ QualTypeMapper::convertBuiltinType(const BuiltinType *BT) {
     return Builder.getVoidType();
 
   case BuiltinType::NullPtr:
-    return createPointerTypeForPointee(QT);
+    return createPointerTypeForPointee(QT, llvm::abi::PointerFlags::None);
 
   case BuiltinType::Bool:
     return Builder.getIntegerType(1, getTypeAlign(QT), /*Signed=*/false,
@@ -265,13 +274,13 @@ QualTypeMapper::convertBuiltinType(const BuiltinType *BT) 
{
   case BuiltinType::OCLClkEvent:
   case BuiltinType::OCLQueue:
   case BuiltinType::OCLReserveID:
-    return createPointerTypeForPointee(QT);
+    return createPointerTypeForPointee(QT, llvm::abi::PointerFlags::None);
 
   // Objective-C builtin types are represented as opaque pointers.
   case BuiltinType::ObjCId:
   case BuiltinType::ObjCClass:
   case BuiltinType::ObjCSel:
-    return createPointerTypeForPointee(QT);
+    return createPointerTypeForPointee(QT, llvm::abi::PointerFlags::None);
 
     // AArch64 SVE data and predicate types, including the x2/x3/x4 tuples.
 #define SVE_VECTOR_TYPE(Name, MangledName, Id, SingletonId)                    
\
@@ -356,7 +365,8 @@ QualTypeMapper::convertArrayType(const clang::ArrayType 
*AT) {
   if (isa<IncompleteArrayType>(AT))
     return Builder.getArrayType(ElementType, 0, 0);
   if (const auto *VAT = dyn_cast<VariableArrayType>(AT))
-    return createPointerTypeForPointee(VAT->getPointeeType());
+    return createPointerTypeForPointee(VAT->getPointeeType(),
+                                       llvm::abi::PointerFlags::None);
   llvm::reportFatalInternalError(
       "unexpected array type in ABI lowering (dependent array types should be "
       "resolved before reaching this point)");
@@ -480,8 +490,8 @@ QualTypeMapper::convertCXXRecordType(const CXXRecordDecl 
*RD) {
 
   // Add vtable pointer for polymorphic classes
   if (RD->isPolymorphic()) {
-    const llvm::abi::Type *VtablePointer =
-        createPointerTypeForPointee(ASTCtx.VoidPtrTy);
+    const llvm::abi::Type *VtablePointer = createPointerTypeForPointee(
+        ASTCtx.VoidPtrTy, llvm::abi::PointerFlags::IsPointerOrReference);
     Fields.emplace_back(VtablePointer, 0);
   }
 
@@ -620,7 +630,8 @@ llvm::Align QualTypeMapper::getTypeAlign(QualType QT) const 
{
 }
 
 const llvm::abi::Type *
-QualTypeMapper::createPointerTypeForPointee(QualType PointeeType) {
+QualTypeMapper::createPointerTypeForPointee(QualType PointeeType,
+                                            llvm::abi::PointerFlags Flags) {
   auto AddrSpace = PointeeType.getAddressSpace();
   auto PointerSize = ASTCtx.getTargetInfo().getPointerWidth(AddrSpace);
   llvm::Align Alignment =
@@ -632,8 +643,10 @@ QualTypeMapper::createPointerTypeForPointee(QualType 
PointeeType) {
       PointeeType->isFunctionType() && !PointeeType.hasAddressSpace()
           ? DL.getProgramAddressSpace()
           : ASTCtx.getTargetInfo().getTargetAddressSpace(AddrSpace);
+  if (PointeeType.hasAddressSpace())
+    Flags |= llvm::abi::PointerFlags::IsPointeeAddressSpaceQualified;
   return Builder.getPointerType(PointerSize, llvm::Align(Alignment.value() / 
8),
-                                TargetAddrSpace);
+                                TargetAddrSpace, Flags);
 }
 
 /// Processes the fields of a record (struct/class/union) and populates
diff --git a/clang/lib/CodeGen/QualTypeMapper.h 
b/clang/lib/CodeGen/QualTypeMapper.h
index f6bb43482c705ea..c909468fc04bb02 100644
--- a/clang/lib/CodeGen/QualTypeMapper.h
+++ b/clang/lib/CodeGen/QualTypeMapper.h
@@ -51,7 +51,9 @@ class QualTypeMapper {
 
   const llvm::abi::RecordType *convertStructType(const clang::RecordDecl *RD);
   const llvm::abi::RecordType *convertUnionType(const clang::RecordDecl *RD);
-  const llvm::abi::Type *createPointerTypeForPointee(QualType PointeeType);
+  const llvm::abi::Type *
+  createPointerTypeForPointee(QualType PointeeType,
+                              llvm::abi::PointerFlags Flags);
   const llvm::abi::RecordType *convertCXXRecordType(const CXXRecordDecl *RD);
 
   void computeFieldInfo(const clang::RecordDecl *RD,
diff --git a/clang/test/CodeGen/AArch64/abi-classify-arg-pointer-like.m 
b/clang/test/CodeGen/AArch64/abi-classify-arg-pointer-like.m
new file mode 100644
index 000000000000000..feea53e9c9b2f85
--- /dev/null
+++ b/clang/test/CodeGen/AArch64/abi-classify-arg-pointer-like.m
@@ -0,0 +1,46 @@
+// RUN: %clang_cc1 -triple aarch64-linux-gnu -fblocks -emit-llvm -o - %s | 
FileCheck %s
+// RUN: %clang_cc1 -triple aarch64-linux-gnu -fblocks 
-fexperimental-abi-lowering -emit-llvm -o - %s 2>&1 | FileCheck %s 
--implicit-check-not="not yet implemented"
+
+// Objective-C object pointers and block pointers are pointer representations,
+// but they are not ordinary C/C++ pointers or references and therefore use
+// integer coercions for aggregate arguments.
+
+@class Object;
+
+typedef struct {
+  id value;
+} ObjCIdAgg;
+void arg_objc_id(ObjCIdAgg a) {}
+// CHECK: define{{.*}} void @arg_objc_id(i64 %{{.*}})
+
+typedef struct {
+  Class value;
+} ObjCClassAgg;
+void arg_objc_class(ObjCClassAgg a) {}
+// CHECK: define{{.*}} void @arg_objc_class(i64 %{{.*}})
+
+typedef struct {
+  SEL value;
+} ObjCSelAgg;
+void arg_objc_sel(ObjCSelAgg a) {}
+// SEL canonicalizes to an ordinary pointer type.
+// CHECK: define{{.*}} void @arg_objc_sel(ptr %{{.*}})
+
+typedef struct {
+  Object *value;
+} ObjCObjectPointerAgg;
+void arg_objc_object_pointer(ObjCObjectPointerAgg a) {}
+// CHECK: define{{.*}} void @arg_objc_object_pointer(i64 %{{.*}})
+
+typedef struct {
+  id first;
+  id second;
+} ObjCIdPairAgg;
+void arg_objc_id_pair(ObjCIdPairAgg a) {}
+// CHECK: define{{.*}} void @arg_objc_id_pair([2 x i64] %{{.*}})
+
+typedef struct {
+  void (^value)(void);
+} BlockPointerAgg;
+void arg_block_pointer(BlockPointerAgg a) {}
+// CHECK: define{{.*}} void @arg_block_pointer(i64 %{{.*}})
diff --git a/clang/test/CodeGen/AArch64/abi-classify-arg-types.c 
b/clang/test/CodeGen/AArch64/abi-classify-arg-types.c
index 274c6010ea7e472..7950e3320d379ed 100644
--- a/clang/test/CodeGen/AArch64/abi-classify-arg-types.c
+++ b/clang/test/CodeGen/AArch64/abi-classify-arg-types.c
@@ -1,17 +1,17 @@
-// RUN: %clang_cc1 -triple arm64-apple-ios7.0 -target-abi darwinpcs 
-fenable-matrix -fexperimental-max-bitint-width=1024 -emit-llvm -o - %s | 
FileCheck %s --check-prefixes=CHECK,DARWIN,LONG64,NOHFAALIGN,NOHUGEVEC,NOANDROID
-// RUN: %clang_cc1 -triple arm64-apple-ios7.0 -target-abi darwinpcs 
-fenable-matrix -fexperimental-max-bitint-width=1024 
-fexperimental-abi-lowering -emit-llvm -o - %s 2>&1 | FileCheck %s 
--check-prefixes=CHECK,DARWIN,LONG64,NOHFAALIGN,NOHUGEVEC,NOANDROID 
--implicit-check-not="not yet implemented"
-// RUN: %clang_cc1 -triple arm64_32-apple-ios7.0 -target-abi darwinpcs 
-fenable-matrix -fexperimental-max-bitint-width=1024 -emit-llvm -o - %s | 
FileCheck %s --check-prefixes=CHECK,DARWIN,LONG32,NOHFAALIGN,HUGEVEC,NOANDROID
-// RUN: %clang_cc1 -triple arm64_32-apple-ios7.0 -target-abi darwinpcs 
-fenable-matrix -fexperimental-max-bitint-width=1024 
-fexperimental-abi-lowering -emit-llvm -o - %s 2>&1 | FileCheck %s 
--check-prefixes=CHECK,DARWIN,LONG32,NOHFAALIGN,HUGEVEC,NOANDROID 
--implicit-check-not="not yet implemented"
-// RUN: %clang_cc1 -triple aarch64-linux-gnu -fenable-matrix 
-fexperimental-max-bitint-width=1024 -emit-llvm -o - %s | FileCheck %s 
--check-prefixes=CHECK,AAPCS,LONG64,AAPCS64,NOHUGEVEC,NOANDROID
-// RUN: %clang_cc1 -triple aarch64-linux-gnu -fenable-matrix 
-fexperimental-max-bitint-width=1024 -fexperimental-abi-lowering -emit-llvm -o 
- %s 2>&1 | FileCheck %s 
--check-prefixes=CHECK,AAPCS,LONG64,AAPCS64,NOHUGEVEC,NOANDROID 
--implicit-check-not="not yet implemented"
-// RUN: %clang_cc1 -triple aarch64_be-linux-gnu -fenable-matrix 
-fexperimental-max-bitint-width=1024 -emit-llvm -o - %s | FileCheck %s 
--check-prefixes=CHECK,AAPCS,LONG64,AAPCS64,NOHUGEVEC,NOANDROID
-// RUN: %clang_cc1 -triple aarch64_be-linux-gnu -fenable-matrix 
-fexperimental-max-bitint-width=1024 -fexperimental-abi-lowering -emit-llvm -o 
- %s 2>&1 | FileCheck %s 
--check-prefixes=CHECK,AAPCS,LONG64,AAPCS64,NOHUGEVEC,NOANDROID 
--implicit-check-not="not yet implemented"
-// RUN: %clang_cc1 -triple aarch64-linux-android -fenable-matrix 
-fexperimental-max-bitint-width=1024 -emit-llvm -o - %s | FileCheck %s 
--check-prefixes=CHECK,AAPCS,LONG64,AAPCS64,NOHUGEVEC,ANDROID
-// RUN: %clang_cc1 -triple aarch64-linux-android -fenable-matrix 
-fexperimental-max-bitint-width=1024 -fexperimental-abi-lowering -emit-llvm -o 
- %s 2>&1 | FileCheck %s 
--check-prefixes=CHECK,AAPCS,LONG64,AAPCS64,NOHUGEVEC,ANDROID 
--implicit-check-not="not yet implemented"
-// RUN: %clang_cc1 -triple aarch64-pc-windows-msvc -fenable-matrix 
-fexperimental-max-bitint-width=1024 -emit-llvm -o - %s | FileCheck %s 
--check-prefixes=CHECK,AAPCS,LONG32,NOHFAALIGN,NOHUGEVEC,NOANDROID
-// RUN: %clang_cc1 -triple aarch64-pc-windows-msvc -fenable-matrix 
-fexperimental-max-bitint-width=1024 -fexperimental-abi-lowering -emit-llvm -o 
- %s 2>&1 | FileCheck %s 
--check-prefixes=CHECK,AAPCS,LONG32,NOHFAALIGN,NOHUGEVEC,NOANDROID 
--implicit-check-not="not yet implemented"
-// RUN: %clang_cc1 -triple arm64ec-pc-windows-msvc -fenable-matrix 
-fexperimental-max-bitint-width=1024 -emit-llvm -o - %s | FileCheck %s 
--check-prefixes=CHECK,AAPCS,LONG32,NOHFAALIGN,NOHUGEVEC,NOANDROID
-// RUN: %clang_cc1 -triple arm64ec-pc-windows-msvc -fenable-matrix 
-fexperimental-max-bitint-width=1024 -fexperimental-abi-lowering -emit-llvm -o 
- %s 2>&1 | FileCheck %s 
--check-prefixes=CHECK,AAPCS,LONG32,NOHFAALIGN,NOHUGEVEC,NOANDROID 
--implicit-check-not="not yet implemented"
+// RUN: %clang_cc1 -triple arm64-apple-ios7.0 -target-abi darwinpcs 
-fenable-matrix -fexperimental-max-bitint-width=1024 -emit-llvm -o - %s | 
FileCheck %s 
--check-prefixes=CHECK,DARWIN,LONG64,NOHFAALIGN,NOHUGEVEC,NOANDROID,PTR64
+// RUN: %clang_cc1 -triple arm64-apple-ios7.0 -target-abi darwinpcs 
-fenable-matrix -fexperimental-max-bitint-width=1024 
-fexperimental-abi-lowering -emit-llvm -o - %s 2>&1 | FileCheck %s 
--check-prefixes=CHECK,DARWIN,LONG64,NOHFAALIGN,NOHUGEVEC,NOANDROID,PTR64 
--implicit-check-not="not yet implemented"
+// RUN: %clang_cc1 -triple arm64_32-apple-ios7.0 -target-abi darwinpcs 
-fenable-matrix -fexperimental-max-bitint-width=1024 -emit-llvm -o - %s | 
FileCheck %s 
--check-prefixes=CHECK,DARWIN,LONG32,NOHFAALIGN,HUGEVEC,NOANDROID,PTR32
+// RUN: %clang_cc1 -triple arm64_32-apple-ios7.0 -target-abi darwinpcs 
-fenable-matrix -fexperimental-max-bitint-width=1024 
-fexperimental-abi-lowering -emit-llvm -o - %s 2>&1 | FileCheck %s 
--check-prefixes=CHECK,DARWIN,LONG32,NOHFAALIGN,HUGEVEC,NOANDROID,PTR32 
--implicit-check-not="not yet implemented"
+// RUN: %clang_cc1 -triple aarch64-linux-gnu -fenable-matrix 
-fexperimental-max-bitint-width=1024 -emit-llvm -o - %s | FileCheck %s 
--check-prefixes=CHECK,AAPCS,LONG64,AAPCS64,NOHUGEVEC,NOANDROID,PTR64
+// RUN: %clang_cc1 -triple aarch64-linux-gnu -fenable-matrix 
-fexperimental-max-bitint-width=1024 -fexperimental-abi-lowering -emit-llvm -o 
- %s 2>&1 | FileCheck %s 
--check-prefixes=CHECK,AAPCS,LONG64,AAPCS64,NOHUGEVEC,NOANDROID,PTR64 
--implicit-check-not="not yet implemented"
+// RUN: %clang_cc1 -triple aarch64_be-linux-gnu -fenable-matrix 
-fexperimental-max-bitint-width=1024 -emit-llvm -o - %s | FileCheck %s 
--check-prefixes=CHECK,AAPCS,LONG64,AAPCS64,NOHUGEVEC,NOANDROID,PTR64
+// RUN: %clang_cc1 -triple aarch64_be-linux-gnu -fenable-matrix 
-fexperimental-max-bitint-width=1024 -fexperimental-abi-lowering -emit-llvm -o 
- %s 2>&1 | FileCheck %s 
--check-prefixes=CHECK,AAPCS,LONG64,AAPCS64,NOHUGEVEC,NOANDROID,PTR64 
--implicit-check-not="not yet implemented"
+// RUN: %clang_cc1 -triple aarch64-linux-android -fenable-matrix 
-fexperimental-max-bitint-width=1024 -emit-llvm -o - %s | FileCheck %s 
--check-prefixes=CHECK,AAPCS,LONG64,AAPCS64,NOHUGEVEC,ANDROID,PTR64
+// RUN: %clang_cc1 -triple aarch64-linux-android -fenable-matrix 
-fexperimental-max-bitint-width=1024 -fexperimental-abi-lowering -emit-llvm -o 
- %s 2>&1 | FileCheck %s 
--check-prefixes=CHECK,AAPCS,LONG64,AAPCS64,NOHUGEVEC,ANDROID,PTR64 
--implicit-check-not="not yet implemented"
+// RUN: %clang_cc1 -triple aarch64-pc-windows-msvc -fenable-matrix 
-fexperimental-max-bitint-width=1024 -emit-llvm -o - %s | FileCheck %s 
--check-prefixes=CHECK,AAPCS,LONG32,NOHFAALIGN,NOHUGEVEC,NOANDROID,PTR64
+// RUN: %clang_cc1 -triple aarch64-pc-windows-msvc -fenable-matrix 
-fexperimental-max-bitint-width=1024 -fexperimental-abi-lowering -emit-llvm -o 
- %s 2>&1 | FileCheck %s 
--check-prefixes=CHECK,AAPCS,LONG32,NOHFAALIGN,NOHUGEVEC,NOANDROID,PTR64 
--implicit-check-not="not yet implemented"
+// RUN: %clang_cc1 -triple arm64ec-pc-windows-msvc -fenable-matrix 
-fexperimental-max-bitint-width=1024 -emit-llvm -o - %s | FileCheck %s 
--check-prefixes=CHECK,AAPCS,LONG32,NOHFAALIGN,NOHUGEVEC,NOANDROID,PTR64
+// RUN: %clang_cc1 -triple arm64ec-pc-windows-msvc -fenable-matrix 
-fexperimental-max-bitint-width=1024 -fexperimental-abi-lowering -emit-llvm -o 
- %s 2>&1 | FileCheck %s 
--check-prefixes=CHECK,AAPCS,LONG32,NOHFAALIGN,NOHUGEVEC,NOANDROID,PTR64 
--implicit-check-not="not yet implemented"
 
 // This test is verifying that the LLVM ABI library classifies argument types 
in
 // the same way that Clang does without the library.
@@ -113,6 +113,72 @@ void arg_bitint128(_BitInt(128) x) {}
 void arg_bitint129(_BitInt(129) x) {}
 // CHECK: define{{.*}} void @arg_bitint129(ptr nofreeobj noundef align 16 
dead_on_return dereferenceable(32) %{{.*}})
 
+// Non-homogeneous fixed-size aggregates of at most 16 bytes are passed
+// directly. Larger aggregates are passed indirectly.
+typedef struct {
+  char x[3];
+} Agg3;
+void arg_agg3(Agg3 a) {}
+// PTR64: define{{.*}} void @arg_agg3(i64 %{{.*}})
+// PTR32: define{{.*}} void @arg_agg3(i32 %{{.*}})
+
+typedef struct {
+  char x[9];
+} Agg9;
+void arg_agg9(Agg9 a) {}
+// PTR64: define{{.*}} void @arg_agg9([2 x i64] %{{.*}})
+// PTR32: define{{.*}} void @arg_agg9([3 x i32] %{{.*}})
+
+typedef struct {
+  long long x, y;
+} Agg16;
+void arg_agg16(Agg16 a) {}
+// CHECK: define{{.*}} void @arg_agg16([2 x i64] %{{.*}})
+
+typedef struct {
+  _Alignas(16) char x[16];
+} Agg16Align16;
+void arg_agg16_align16(Agg16Align16 a) {}
+// CHECK: define{{.*}} void @arg_agg16_align16(i128 %{{.*}})
+
+typedef struct {
+  char x[17];
+} Agg17;
+void arg_agg17(Agg17 a) {}
+// CHECK: define{{.*}} void @arg_agg17(ptr nofreeobj noundef align 1 
{{(dead_on_return )?}}dereferenceable(17) %{{.*}})
+
+// Aggregates made entirely of 64-bit default-address-space pointers retain
+// pointer types in their coercion.
+typedef struct {
+  int *p;
+} PtrAgg1;
+void arg_ptr_agg1(PtrAgg1 a) {}
+// PTR64: define{{.*}} void @arg_ptr_agg1(ptr %{{.*}})
+// PTR32: define{{.*}} void @arg_ptr_agg1(i32 %{{.*}})
+
+typedef struct {
+  int *p, *q;
+} PtrAgg2;
+void arg_ptr_agg2(PtrAgg2 a) {}
+// PTR64: define{{.*}} void @arg_ptr_agg2([2 x ptr] %{{.*}})
+// PTR32: define{{.*}} void @arg_ptr_agg2([2 x i32] %{{.*}})
+
+typedef int __attribute__((address_space(0))) as0_int;
+typedef struct {
+  as0_int *p;
+} ExplicitAS0PtrAgg;
+void arg_explicit_as0_ptr_agg(ExplicitAS0PtrAgg a) {}
+// PTR64: define{{.*}} void @arg_explicit_as0_ptr_agg(i64 %{{.*}})
+// PTR32: define{{.*}} void @arg_explicit_as0_ptr_agg(i32 %{{.*}})
+
+typedef int __attribute__((address_space(1))) as1_int;
+typedef struct {
+  as1_int *p;
+} NonDefaultASPtrAgg;
+void arg_nondefault_as_ptr_agg(NonDefaultASPtrAgg a) {}
+// PTR64: define{{.*}} void @arg_nondefault_as_ptr_agg(i64 %{{.*}})
+// PTR32: define{{.*}} void @arg_nondefault_as_ptr_agg(i32 %{{.*}})
+
 // Homogeneous floating-point aggregates are coerced to an array of the base
 // type. AAPCS sets alignstack from unadjusted alignment (8, or 16 if the
 // unadjusted alignment is at least 16). DarwinPCS and Win64 do not.
diff --git a/clang/test/CodeGen/AArch64/abi-classify-arg-types.cpp 
b/clang/test/CodeGen/AArch64/abi-classify-arg-types.cpp
index 8e0bbb0e06b5778..fa384187a43eb08 100644
--- a/clang/test/CodeGen/AArch64/abi-classify-arg-types.cpp
+++ b/clang/test/CodeGen/AArch64/abi-classify-arg-types.cpp
@@ -1,11 +1,11 @@
-// RUN: %clang_cc1 -triple arm64-apple-ios7.0 -target-abi darwinpcs -std=c++20 
-emit-llvm -o - %s | FileCheck %s --check-prefixes=CHECK,NOHFAALIGN
-// RUN: %clang_cc1 -triple arm64-apple-ios7.0 -target-abi darwinpcs -std=c++20 
-fexperimental-abi-lowering -emit-llvm -o - %s 2>&1 | FileCheck %s 
--check-prefixes=CHECK,NOHFAALIGN --implicit-check-not="not yet implemented"
-// RUN: %clang_cc1 -triple arm64_32-apple-ios7.0 -target-abi darwinpcs 
-std=c++20 -emit-llvm -o - %s | FileCheck %s --check-prefixes=CHECK,NOHFAALIGN
-// RUN: %clang_cc1 -triple arm64_32-apple-ios7.0 -target-abi darwinpcs 
-std=c++20 -fexperimental-abi-lowering -emit-llvm -o - %s 2>&1 | FileCheck %s 
--check-prefixes=CHECK,NOHFAALIGN --implicit-check-not="not yet implemented"
-// RUN: %clang_cc1 -triple aarch64-linux-gnu -std=c++20 -emit-llvm -o - %s | 
FileCheck %s --check-prefixes=CHECK,AAPCS64
-// RUN: %clang_cc1 -triple aarch64-linux-gnu -std=c++20 
-fexperimental-abi-lowering -emit-llvm -o - %s 2>&1 | FileCheck %s 
--check-prefixes=CHECK,AAPCS64 --implicit-check-not="not yet implemented"
-// RUN: %clang_cc1 -triple aarch64_be-linux-gnu -std=c++20 -emit-llvm -o - %s 
| FileCheck %s --check-prefixes=CHECK,AAPCS64
-// RUN: %clang_cc1 -triple aarch64_be-linux-gnu -std=c++20 
-fexperimental-abi-lowering -emit-llvm -o - %s 2>&1 | FileCheck %s 
--check-prefixes=CHECK,AAPCS64 --implicit-check-not="not yet implemented"
+// RUN: %clang_cc1 -triple arm64-apple-ios7.0 -target-abi darwinpcs -std=c++20 
-emit-llvm -o - %s | FileCheck %s --check-prefixes=CHECK,NOHFAALIGN,PTR64
+// RUN: %clang_cc1 -triple arm64-apple-ios7.0 -target-abi darwinpcs -std=c++20 
-fexperimental-abi-lowering -emit-llvm -o - %s 2>&1 | FileCheck %s 
--check-prefixes=CHECK,NOHFAALIGN,PTR64 --implicit-check-not="not yet 
implemented"
+// RUN: %clang_cc1 -triple arm64_32-apple-ios7.0 -target-abi darwinpcs 
-std=c++20 -emit-llvm -o - %s | FileCheck %s 
--check-prefixes=CHECK,NOHFAALIGN,PTR32
+// RUN: %clang_cc1 -triple arm64_32-apple-ios7.0 -target-abi darwinpcs 
-std=c++20 -fexperimental-abi-lowering -emit-llvm -o - %s 2>&1 | FileCheck %s 
--check-prefixes=CHECK,NOHFAALIGN,PTR32 --implicit-check-not="not yet 
implemented"
+// RUN: %clang_cc1 -triple aarch64-linux-gnu -std=c++20 -emit-llvm -o - %s | 
FileCheck %s --check-prefixes=CHECK,AAPCS64,PTR64
+// RUN: %clang_cc1 -triple aarch64-linux-gnu -std=c++20 
-fexperimental-abi-lowering -emit-llvm -o - %s 2>&1 | FileCheck %s 
--check-prefixes=CHECK,AAPCS64,PTR64 --implicit-check-not="not yet implemented"
+// RUN: %clang_cc1 -triple aarch64_be-linux-gnu -std=c++20 -emit-llvm -o - %s 
| FileCheck %s --check-prefixes=CHECK,AAPCS64,PTR64
+// RUN: %clang_cc1 -triple aarch64_be-linux-gnu -std=c++20 
-fexperimental-abi-lowering -emit-llvm -o - %s 2>&1 | FileCheck %s 
--check-prefixes=CHECK,AAPCS64,PTR64 --implicit-check-not="not yet implemented"
 
 // This test is verifying that the LLVM ABI library classifies C++ record
 // arguments that cannot be passed in registers the same way Clang does without
@@ -42,6 +42,20 @@ void arg_nontrivial_dtor_and_copy(NonTrivialDtorAndCopy a) {}
 void arg_explicit_copy(ExplicitCopy a) {}
 // CHECK: define{{.*}} void @arg_explicit_copy(ptr nofreeobj noundef align 2 
dead_on_return dereferenceable(2) %{{.*}})
 
+struct ReferenceAgg {
+  int &r;
+};
+void arg_reference_agg(ReferenceAgg a) {}
+// PTR64: define{{.*}} void @arg_reference_agg(ptr %{{.*}})
+// PTR32: define{{.*}} void @arg_reference_agg(i32 %{{.*}})
+
+struct NullPtrAgg {
+  decltype(nullptr) p;
+};
+void arg_nullptr_agg(NullPtrAgg a) {}
+// PTR64: define{{.*}} void @arg_nullptr_agg(i64 %{{.*}})
+// PTR32: define{{.*}} void @arg_nullptr_agg(i32 %{{.*}})
+
 // Homogeneous aggregates that can pass in registers are coerced to an array of
 // the base type, including inherited members, nested records, and zero-length
 // bitfields.
diff --git a/clang/unittests/CodeGen/QualTypeMapperTest.cpp 
b/clang/unittests/CodeGen/QualTypeMapperTest.cpp
index 6fdd4318bf4f0d3..ad510640387ed73 100644
--- a/clang/unittests/CodeGen/QualTypeMapperTest.cpp
+++ b/clang/unittests/CodeGen/QualTypeMapperTest.cpp
@@ -292,4 +292,75 @@ TEST_F(QualTypeMapperSVETest, PlainVectorIsGeneric) {
   EXPECT_EQ(Int32x4->getSizeInBits(), llvm::TypeSize::getFixed(128));
 }
 
+class QualTypeMapperPointerTest : public ::testing::Test {
+protected:
+  QualTypeMapperPointerTest()
+      : AST(makeInputs()), Mapper(AST.context(), DL, Alloc) {}
+
+  const llvm::abi::PointerType *mapTypedef(StringRef Name) {
+    for (Decl *D : AST.context().getTranslationUnitDecl()->decls())
+      if (const auto *TD = dyn_cast<TypedefNameDecl>(D))
+        if (TD->getName() == Name)
+          return dyn_cast<llvm::abi::PointerType>(
+              Mapper.convertType(TD->getUnderlyingType()));
+    ADD_FAILURE() << "no typedef named " << Name;
+    return nullptr;
+  }
+
+private:
+  static TestInputs makeInputs() {
+    TestInputs Inputs(R"c(
+typedef int *ordinary_pointer_t;
+typedef int &reference_t;
+typedef decltype(nullptr) nullptr_t;
+typedef int __attribute__((address_space(1))) *address_space_pointer_t;
+typedef void (^block_pointer_t)(void);
+typedef id objc_id_t;
+typedef Class objc_class_t;
+typedef SEL objc_selector_t;
+@interface Object
+@end
+typedef Object *objc_object_pointer_t;
+)c");
+    Inputs.Language = TestLanguage::Lang_OBJCXX;
+    Inputs.ExtraArgs = {"-triple", "aarch64-unknown-linux-gnu", "-fblocks"};
+    return Inputs;
+  }
+
+  TestAST AST;
+  llvm::DataLayout DL;
+  llvm::BumpPtrAllocator Alloc;
+  CodeGen::QualTypeMapper Mapper;
+};
+
+TEST_F(QualTypeMapperPointerTest, SourceTypeFlags) {
+  const auto *Ordinary = mapTypedef("ordinary_pointer_t");
+  ASSERT_NE(Ordinary, nullptr);
+  EXPECT_TRUE(Ordinary->isPointerOrReference());
+  EXPECT_FALSE(Ordinary->isPointeeAddressSpaceQualified());
+
+  const auto *Reference = mapTypedef("reference_t");
+  ASSERT_NE(Reference, nullptr);
+  EXPECT_TRUE(Reference->isPointerOrReference());
+  EXPECT_FALSE(Reference->isPointeeAddressSpaceQualified());
+
+  const auto *AddressSpace = mapTypedef("address_space_pointer_t");
+  ASSERT_NE(AddressSpace, nullptr);
+  EXPECT_TRUE(AddressSpace->isPointerOrReference());
+  EXPECT_TRUE(AddressSpace->isPointeeAddressSpaceQualified());
+
+  for (StringRef Name : {"nullptr_t", "block_pointer_t", "objc_id_t",
+                         "objc_class_t", "objc_object_pointer_t"}) {
+    SCOPED_TRACE(Name);
+    const auto *Pointer = mapTypedef(Name);
+    ASSERT_NE(Pointer, nullptr);
+    EXPECT_FALSE(Pointer->isPointerOrReference());
+  }
+
+  // SEL is canonically an ordinary pointer on this target.
+  const auto *Selector = mapTypedef("objc_selector_t");
+  ASSERT_NE(Selector, nullptr);
+  EXPECT_TRUE(Selector->isPointerOrReference());
+}
+
 } // namespace
diff --git a/llvm/include/llvm/ABI/Types.h b/llvm/include/llvm/ABI/Types.h
index b7083d181eae88f..405c4f02a4f1c9e 100644
--- a/llvm/include/llvm/ABI/Types.h
+++ b/llvm/include/llvm/ABI/Types.h
@@ -27,6 +27,8 @@
 namespace llvm {
 namespace abi {
 
+LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
+
 enum class TypeKind {
   Void,
   Atomic,
@@ -202,11 +204,32 @@ class PointerLikeType : public Type {
   }
 };
 
+/// Source-level pointer properties, independent of the target address space.
+enum class PointerFlags {
+  None = 0,
+  IsPointerOrReference = 1 << 0,
+  IsPointeeAddressSpaceQualified = 1 << 1,
+  LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/IsPointeeAddressSpaceQualified)
+};
+
 class PointerType : public PointerLikeType {
+  PointerFlags Flags;
+
 public:
-  PointerType(uint64_t Size, Align ABIAlign, unsigned AddressSpace = 0)
+  PointerType(uint64_t Size, Align ABIAlign, unsigned AddressSpace,
+              PointerFlags Flags)
       : PointerLikeType(TypeKind::Pointer, TypeSize::getFixed(Size), ABIAlign,
-                        AddressSpace) {}
+                        AddressSpace),
+        Flags(Flags) {}
+
+  PointerFlags getFlags() const { return Flags; }
+  bool isPointerOrReference() const {
+    return (Flags & PointerFlags::IsPointerOrReference) != PointerFlags::None;
+  }
+  bool isPointeeAddressSpaceQualified() const {
+    return (Flags & PointerFlags::IsPointeeAddressSpaceQualified) !=
+           PointerFlags::None;
+  }
 
   static bool classof(const Type *T) {
     return T->getKind() == TypeKind::Pointer;
@@ -499,9 +522,9 @@ class TypeBuilder {
   }
 
   const PointerType *getPointerType(uint64_t Size, Align Align,
-                                    unsigned Addrspace = 0) {
+                                    unsigned Addrspace, PointerFlags Flags) {
     return new (Allocator.Allocate<PointerType>())
-        PointerType(Size, Align, Addrspace);
+        PointerType(Size, Align, Addrspace, Flags);
   }
 
   const ArrayType *getArrayType(const Type *ElementType, uint64_t NumElements,
diff --git a/llvm/lib/ABI/Targets/AArch64.cpp b/llvm/lib/ABI/Targets/AArch64.cpp
index 9573f31e1a4053f..954a4db37ef62d0 100644
--- a/llvm/lib/ABI/Targets/AArch64.cpp
+++ b/llvm/lib/ABI/Targets/AArch64.cpp
@@ -84,6 +84,29 @@ static void reportNYI(StringRef Feature) {
       << " is not yet implemented for AArch64 in the LLVM ABI library.\n";
 }
 
+static bool containsOnlyPointers(const Type *Ty) {
+  while (const auto *AT = dyn_cast<ArrayType>(Ty))
+    Ty = AT->getElementType();
+
+  if (const auto *PT = dyn_cast<PointerType>(Ty))
+    return PT->getSizeInBits().getFixedValue() == 64 &&
+           PT->isPointerOrReference() && !PT->isPointeeAddressSpaceQualified();
+
+  const auto *RT = dyn_cast<RecordType>(Ty);
+  if (!RT || RT->isEmpty())
+    return false;
+
+  for (const FieldInfo &Base : RT->getBaseClasses())
+    if (!containsOnlyPointers(Base.FieldType))
+      return false;
+
+  for (const FieldInfo &Field : RT->getFields())
+    if (!containsOnlyPointers(Field.FieldType))
+      return false;
+
+  return true;
+}
+
 ArgInfo AArch64TargetInfo::classifyReturnType(const Type *RetTy,
                                               bool IsVariadicFn) const {
   if (RetTy->isVoid())
@@ -227,8 +250,37 @@ ArgInfo AArch64TargetInfo::classifyArgumentType(
     return ArgInfo::getDirect(CoerceTy, /*Offset=*/0, llvm::Align(TyAlign));
   }
 
-  reportNYI("Aggregate argument type handling");
-  return ArgInfo::getIgnore();
+  if (Ty->isSVESizelessType()) {
+    reportNYI("Pure scalable aggregate argument type handling");
+    return ArgInfo::getIgnore();
+  }
+
+  // Non-homogeneous aggregates up to 16 bytes are passed directly in registers
+  // or on the stack.
+  if (Size <= 128) {
+    llvm::Align Alignment =
+        Opts.Kind == AArch64ABIKind::AAPCS
+            ? (Ty->getUnadjustedAlignment() < llvm::Align(16) ? llvm::Align(8)
+                                                              : 
llvm::Align(16))
+            : std::max(Ty->getAlignment(), llvm::Align(Opts.IsILP32 ? 4 : 8));
+    uint64_t AlignmentInBits = Alignment.value() * 8;
+    Size = llvm::alignTo(Size, AlignmentInBits);
+
+    const Type *BaseTy;
+    if ((Size == 64 || Size == 128) && Alignment == llvm::Align(8) &&
+        containsOnlyPointers(Ty))
+      BaseTy = TB.getPointerType(64, llvm::Align(8), /*Addrspace=*/0,
+                                 PointerFlags::None);
+    else
+      BaseTy = TB.getIntegerType(AlignmentInBits, Alignment, /*Signed=*/false);
+
+    if (Size == AlignmentInBits)
+      return ArgInfo::getDirect(BaseTy);
+    return ArgInfo::getDirect(
+        TB.getArrayType(BaseTy, Size / AlignmentInBits, Size));
+  }
+
+  return getNaturalAlignIndirect(Ty, getAllocaAddrSpace(), /*ByVal=*/false);
 }
 
 bool AArch64TargetInfo::passAsAggregateType(const Type *Ty) const {
diff --git a/llvm/lib/ABI/Targets/AMDGPU.cpp b/llvm/lib/ABI/Targets/AMDGPU.cpp
index c6488a1c539fd47..30e189f42701157 100644
--- a/llvm/lib/ABI/Targets/AMDGPU.cpp
+++ b/llvm/lib/ABI/Targets/AMDGPU.cpp
@@ -138,9 +138,9 @@ ArgInfo AMDGPUTargetInfo::classifyKernelArgumentType(const 
Type *Ty) const {
   if (CoerceGenericPtrArgToGlobal) {
     if (const auto *PtrTy = dyn_cast<PointerType>(Ty);
         PtrTy && PtrTy->getAddrSpace() == AMDGPUAS::FLAT_ADDRESS) {
-      const Type *Coerced =
-          TB.getPointerType(PtrTy->getSizeInBits().getFixedValue(),
-                            PtrTy->getAlignment(), AMDGPUAS::GLOBAL_ADDRESS);
+      const Type *Coerced = TB.getPointerType(
+          PtrTy->getSizeInBits().getFixedValue(), PtrTy->getAlignment(),
+          AMDGPUAS::GLOBAL_ADDRESS, PointerFlags::None);
       return ArgInfo::getDirect(Coerced, /*Offset=*/0, /*Align=*/std::nullopt,
                                 /*CanBeFlattened=*/false);
     }
diff --git a/llvm/unittests/ABI/AArch64TargetInfoTest.cpp 
b/llvm/unittests/ABI/AArch64TargetInfoTest.cpp
index bbb9a52eb482827..d93de25293c59e2 100644
--- a/llvm/unittests/ABI/AArch64TargetInfoTest.cpp
+++ b/llvm/unittests/ABI/AArch64TargetInfoTest.cpp
@@ -106,7 +106,9 @@ class AArch64TargetInfoTest : public ::testing::Test {
         F16(TB.getFloatType(llvm::APFloat::IEEEhalf(), llvm::Align(2))),
         F32(TB.getFloatType(llvm::APFloat::IEEEsingle(), llvm::Align(4))),
         F64(TB.getFloatType(llvm::APFloat::IEEEdouble(), llvm::Align(8))),
-        Ptr(TB.getPointerType(64, llvm::Align(8))), Void(TB.getVoidType()),
+        Ptr(TB.getPointerType(64, llvm::Align(8), /*Addrspace=*/0,
+                              llvm::abi::PointerFlags::IsPointerOrReference)),
+        Void(TB.getVoidType()),
         Matrix(TB.getArrayType(F32, /*NumElements=*/4, /*SizeInBits=*/128,
                                /*IsMatrixType=*/true)),
         V2F32(TB.getVectorType(F32, llvm::ElementCount::getFixed(2),
@@ -213,12 +215,57 @@ static void expectExtendInteger(const ArgInfo &Info, 
const ABIType *Ty,
   EXPECT_EQ(Info.getCoerceToType(), Ty);
 }
 
-static void expectDirectCoercedInteger(const ArgInfo &Info, uint64_t BitWidth) 
{
+static void
+expectDirectCoercedInteger(const ArgInfo &Info, uint64_t BitWidth,
+                           llvm::MaybeAlign ExpectedAlignment = std::nullopt) {
   EXPECT_TRUE(Info.isDirect());
   const llvm::abi::IntegerType *IT =
       llvm::dyn_cast<llvm::abi::IntegerType>(Info.getCoerceToType());
   ASSERT_NE(IT, nullptr);
   EXPECT_EQ(IT->getSizeInBits().getFixedValue(), BitWidth);
+  if (ExpectedAlignment)
+    EXPECT_EQ(IT->getAlignment(), *ExpectedAlignment);
+}
+
+static void expectDirectCoercedIntegerArray(const ArgInfo &Info,
+                                            uint64_t BitWidth,
+                                            uint64_t NumElements,
+                                            llvm::Align Alignment) {
+  EXPECT_TRUE(Info.isDirect());
+  const auto *AT = 
llvm::dyn_cast<llvm::abi::ArrayType>(Info.getCoerceToType());
+  ASSERT_NE(AT, nullptr);
+  EXPECT_EQ(AT->getNumElements(), NumElements);
+  EXPECT_EQ(AT->getSizeInBits().getFixedValue(), BitWidth * NumElements);
+  EXPECT_EQ(AT->getAlignment(), Alignment);
+  const auto *IT = 
llvm::dyn_cast<llvm::abi::IntegerType>(AT->getElementType());
+  ASSERT_NE(IT, nullptr);
+  EXPECT_EQ(IT->getSizeInBits().getFixedValue(), BitWidth);
+  EXPECT_EQ(IT->getAlignment(), Alignment);
+}
+
+static void expectDirectCoercedPointer(const ArgInfo &Info) {
+  EXPECT_TRUE(Info.isDirect());
+  const auto *PT =
+      llvm::dyn_cast<llvm::abi::PointerType>(Info.getCoerceToType());
+  ASSERT_NE(PT, nullptr);
+  EXPECT_EQ(PT->getSizeInBits().getFixedValue(), 64u);
+  EXPECT_EQ(PT->getAlignment(), llvm::Align(8));
+  EXPECT_EQ(PT->getAddrSpace(), 0u);
+}
+
+static void expectDirectCoercedPointerArray(const ArgInfo &Info,
+                                            uint64_t NumElements) {
+  EXPECT_TRUE(Info.isDirect());
+  const auto *AT = 
llvm::dyn_cast<llvm::abi::ArrayType>(Info.getCoerceToType());
+  ASSERT_NE(AT, nullptr);
+  EXPECT_EQ(AT->getNumElements(), NumElements);
+  EXPECT_EQ(AT->getSizeInBits().getFixedValue(), NumElements * 64);
+  EXPECT_EQ(AT->getAlignment(), llvm::Align(8));
+  const auto *PT = 
llvm::dyn_cast<llvm::abi::PointerType>(AT->getElementType());
+  ASSERT_NE(PT, nullptr);
+  EXPECT_EQ(PT->getSizeInBits().getFixedValue(), 64u);
+  EXPECT_EQ(PT->getAlignment(), llvm::Align(8));
+  EXPECT_EQ(PT->getAddrSpace(), 0u);
 }
 
 static void expectDirectCoercedI32Vector(const ArgInfo &Info,
@@ -901,6 +948,162 @@ TEST_F(AArch64TargetInfoTest, 
ClassifyArgumentTransparentUnion) {
   }
 }
 
+TEST_F(AArch64TargetInfoTest, ClassifyArgumentFixedAggregatesAAPCS) {
+  const ABIType *Agg24 =
+      makeRecord({FieldInfo(TB.getArrayType(I8, 3, /*SizeInBits=*/24), 0)}, 24,
+                 llvm::Align(1), llvm::Align(1));
+  const ABIType *Agg72 =
+      makeRecord({FieldInfo(TB.getArrayType(I8, 9, /*SizeInBits=*/72), 0)}, 72,
+                 llvm::Align(1), llvm::Align(1));
+  const ABIType *Agg128Align8 =
+      makeRecord({FieldInfo(I64, 0), FieldInfo(I64, 64)}, 128, llvm::Align(8),
+                 llvm::Align(8));
+  const ABIType *Agg128Align16 =
+      makeRecord({FieldInfo(I128, 0)}, 128, llvm::Align(16), llvm::Align(16));
+  const ABIType *Agg136 =
+      makeRecord({FieldInfo(TB.getArrayType(I8, 17, /*SizeInBits=*/136), 0)},
+                 136, llvm::Align(1), llvm::Align(1));
+
+  std::unique_ptr<TargetInfo> TI =
+      createAArch64TargetInfo(TB, AArch64ABIOptions(AArch64ABIKind::AAPCS));
+  auto Classify = [&](const ABIType *Ty) -> ArgInfo {
+    std::unique_ptr<FunctionInfo> FI =
+        FunctionInfo::create(llvm::CallingConv::C, Void, {Ty});
+    TI->computeInfo(*FI);
+    return FI->getArgInfo(0).Info;
+  };
+
+  expectDirectCoercedInteger(Classify(Agg24), 64, llvm::Align(8));
+  expectDirectCoercedIntegerArray(Classify(Agg72), 64, 2, llvm::Align(8));
+  expectDirectCoercedIntegerArray(Classify(Agg128Align8), 64, 2,
+                                  llvm::Align(8));
+  expectDirectCoercedInteger(Classify(Agg128Align16), 128, llvm::Align(16));
+  expectNaturalAlignIndirect(Classify(Agg136), llvm::Align(1),
+                             /*ByVal=*/false);
+}
+
+TEST_F(AArch64TargetInfoTest, ClassifyArgumentFixedAggregatesILP32) {
+  const ABIType *Agg24 =
+      makeRecord({FieldInfo(TB.getArrayType(I8, 3, /*SizeInBits=*/24), 0)}, 24,
+                 llvm::Align(1), llvm::Align(1));
+  const ABIType *Agg72 =
+      makeRecord({FieldInfo(TB.getArrayType(I8, 9, /*SizeInBits=*/72), 0)}, 72,
+                 llvm::Align(1), llvm::Align(1));
+
+  AArch64ABIOptions Opts(AArch64ABIKind::DarwinPCS);
+  Opts.IsILP32 = true;
+  std::unique_ptr<TargetInfo> TI = createAArch64TargetInfo(TB, Opts);
+
+  {
+    std::unique_ptr<FunctionInfo> FI =
+        FunctionInfo::create(llvm::CallingConv::C, Void, {Agg24});
+    TI->computeInfo(*FI);
+    expectDirectCoercedInteger(FI->getArgInfo(0).Info, 32, llvm::Align(4));
+  }
+  {
+    std::unique_ptr<FunctionInfo> FI =
+        FunctionInfo::create(llvm::CallingConv::C, Void, {Agg72});
+    TI->computeInfo(*FI);
+    expectDirectCoercedIntegerArray(FI->getArgInfo(0).Info, 32, 3,
+                                    llvm::Align(4));
+  }
+}
+
+TEST_F(AArch64TargetInfoTest, ClassifyArgumentAggregateAlignmentByABI) {
+  const ABIType *RecordAligned16 =
+      makeRecord({FieldInfo(TB.getArrayType(I8, 16, /*SizeInBits=*/128), 0)},
+                 128, llvm::Align(16), llvm::Align(1));
+
+  for (AArch64ABIKind Kind :
+       {AArch64ABIKind::AAPCS, AArch64ABIKind::DarwinPCS}) {
+    std::unique_ptr<TargetInfo> TI =
+        createAArch64TargetInfo(TB, AArch64ABIOptions(Kind));
+    std::unique_ptr<FunctionInfo> FI =
+        FunctionInfo::create(llvm::CallingConv::C, Void, {RecordAligned16});
+    TI->computeInfo(*FI);
+    if (Kind == AArch64ABIKind::AAPCS)
+      expectDirectCoercedIntegerArray(FI->getArgInfo(0).Info, 64, 2,
+                                      llvm::Align(8));
+    else
+      expectDirectCoercedInteger(FI->getArgInfo(0).Info, 128, llvm::Align(16));
+  }
+}
+
+TEST_F(AArch64TargetInfoTest, ClassifyArgumentPointerAggregates) {
+  const ABIType *Ptr1 =
+      makeRecord({FieldInfo(Ptr, 0)}, 64, llvm::Align(8), llvm::Align(8));
+  const ABIType *Reference =
+      TB.getPointerType(64, llvm::Align(8), /*Addrspace=*/0,
+                        llvm::abi::PointerFlags::IsPointerOrReference);
+  const ABIType *ReferenceRecord =
+      makeRecord({FieldInfo(Reference, 0)}, 64, llvm::Align(8), 
llvm::Align(8));
+  const ABIType *Ptr2 = makeRecord({FieldInfo(Ptr, 0), FieldInfo(Ptr, 64)}, 
128,
+                                   llvm::Align(8), llvm::Align(8));
+  const ABIType *PtrArray =
+      makeRecord({FieldInfo(TB.getArrayType(Ptr, 2, /*SizeInBits=*/128), 0)},
+                 128, llvm::Align(8), llvm::Align(8));
+  const ABIType *NestedPtrs =
+      makeRecord({FieldInfo(Ptr1, 0), FieldInfo(Ptr, 64)}, 128, llvm::Align(8),
+                 llvm::Align(8));
+  const ABIType *PointerBase =
+      makeRecord({FieldInfo(Ptr, 0)}, 64, llvm::Align(8), llvm::Align(8),
+                 passableRecordFlags(/*IsCXX=*/true));
+  const ABIType *DerivedPtrs =
+      makeRecord({FieldInfo(Ptr, 64)}, 128, llvm::Align(8), llvm::Align(8),
+                 passableRecordFlags(/*IsCXX=*/true),
+                 /*Bases=*/{FieldInfo(PointerBase, 0)});
+  const ABIType *Mixed = makeRecord({FieldInfo(Ptr, 0), FieldInfo(I64, 64)},
+                                    128, llvm::Align(8), llvm::Align(8));
+  const ABIType *NonzeroTargetASPtr =
+      TB.getPointerType(64, llvm::Align(8), /*Addrspace=*/1,
+                        llvm::abi::PointerFlags::IsPointerOrReference);
+  const ABIType *NonzeroTargetAS = makeRecord(
+      {FieldInfo(NonzeroTargetASPtr, 0)}, 64, llvm::Align(8), llvm::Align(8));
+  const ABIType *AS1Ptr = TB.getPointerType(
+      64, llvm::Align(8), /*Addrspace=*/1,
+      llvm::abi::PointerFlags::IsPointerOrReference |
+          llvm::abi::PointerFlags::IsPointeeAddressSpaceQualified);
+  const ABIType *NonDefaultAS =
+      makeRecord({FieldInfo(AS1Ptr, 0)}, 64, llvm::Align(8), llvm::Align(8));
+  const ABIType *ExplicitAS0Ptr = TB.getPointerType(
+      64, llvm::Align(8), /*Addrspace=*/0,
+      llvm::abi::PointerFlags::IsPointerOrReference |
+          llvm::abi::PointerFlags::IsPointeeAddressSpaceQualified);
+  const ABIType *ExplicitAS0 = makeRecord({FieldInfo(ExplicitAS0Ptr, 0)}, 64,
+                                          llvm::Align(8), llvm::Align(8));
+  const ABIType *OtherPointerLike = TB.getPointerType(
+      64, llvm::Align(8), /*Addrspace=*/0, llvm::abi::PointerFlags::None);
+  const ABIType *OtherPointerLikeRecord = makeRecord(
+      {FieldInfo(OtherPointerLike, 0)}, 64, llvm::Align(8), llvm::Align(8));
+
+  for (AArch64ABIKind Kind :
+       {AArch64ABIKind::AAPCS, AArch64ABIKind::DarwinPCS, 
AArch64ABIKind::Win64,
+        AArch64ABIKind::AAPCSSoft}) {
+    std::unique_ptr<TargetInfo> TI =
+        createAArch64TargetInfo(TB, AArch64ABIOptions(Kind));
+
+    auto Classify = [&](const ABIType *Ty) {
+      std::unique_ptr<FunctionInfo> FI =
+          FunctionInfo::create(llvm::CallingConv::C, Void, {Ty});
+      TI->computeInfo(*FI);
+      return FI->getArgInfo(0).Info;
+    };
+
+    expectDirectCoercedPointer(Classify(Ptr1));
+    expectDirectCoercedPointer(Classify(ReferenceRecord));
+    expectDirectCoercedPointerArray(Classify(Ptr2), 2);
+    expectDirectCoercedPointerArray(Classify(PtrArray), 2);
+    expectDirectCoercedPointerArray(Classify(NestedPtrs), 2);
+    expectDirectCoercedPointerArray(Classify(DerivedPtrs), 2);
+    expectDirectCoercedPointer(Classify(NonzeroTargetAS));
+    expectDirectCoercedIntegerArray(Classify(Mixed), 64, 2, llvm::Align(8));
+    expectDirectCoercedInteger(Classify(NonDefaultAS), 64, llvm::Align(8));
+    expectDirectCoercedInteger(Classify(ExplicitAS0), 64, llvm::Align(8));
+    expectDirectCoercedInteger(Classify(OtherPointerLikeRecord), 64,
+                               llvm::Align(8));
+  }
+}
+
 // Homogeneous floating-point aggregates of at most four members are returned
 // directly under AAPCS, DarwinPCS, and Win64.
 TEST_F(AArch64TargetInfoTest, ClassifyReturnHFADirect) {
diff --git a/llvm/unittests/ABI/AMDGPUTargetInfoTest.cpp 
b/llvm/unittests/ABI/AMDGPUTargetInfoTest.cpp
index ecb298b69215e55..6d0e466c41d19a1 100644
--- a/llvm/unittests/ABI/AMDGPUTargetInfoTest.cpp
+++ b/llvm/unittests/ABI/AMDGPUTargetInfoTest.cpp
@@ -469,7 +469,8 @@ TEST_F(AMDGPUTargetInfoTest, 
KernelGenericPointerCoercesToGlobalUnderHIP) {
   std::unique_ptr<FunctionInfo> FI;
   std::unique_ptr<TargetInfo> TI = hipTarget();
   const ABIType *GenericPtr =
-      TB.getPointerType(64, llvm::Align(8), llvm::AMDGPUAS::FLAT_ADDRESS);
+      TB.getPointerType(64, llvm::Align(8), llvm::AMDGPUAS::FLAT_ADDRESS,
+                        llvm::abi::PointerFlags::IsPointerOrReference);
   const ArgInfo &Info = classifyKernelArg(GenericPtr, FI, TI);
   expectDirectPointerAS(Info, llvm::AMDGPUAS::GLOBAL_ADDRESS);
   EXPECT_FALSE(Info.getCanBeFlattened());
@@ -480,7 +481,8 @@ TEST_F(AMDGPUTargetInfoTest, 
KernelGlobalPointerUnchangedUnderHIP) {
   std::unique_ptr<FunctionInfo> FI;
   std::unique_ptr<TargetInfo> TI = hipTarget();
   const ABIType *GlobalPtr =
-      TB.getPointerType(64, llvm::Align(8), llvm::AMDGPUAS::GLOBAL_ADDRESS);
+      TB.getPointerType(64, llvm::Align(8), llvm::AMDGPUAS::GLOBAL_ADDRESS,
+                        llvm::abi::PointerFlags::IsPointerOrReference);
   expectDirectPointerAS(classifyKernelArg(GlobalPtr, FI, TI),
                         llvm::AMDGPUAS::GLOBAL_ADDRESS);
 }
@@ -490,7 +492,8 @@ TEST_F(AMDGPUTargetInfoTest, 
KernelGenericPointerUnchangedByDefault) {
   std::unique_ptr<FunctionInfo> FI;
   std::unique_ptr<TargetInfo> TI;
   const ABIType *GenericPtr =
-      TB.getPointerType(64, llvm::Align(8), llvm::AMDGPUAS::FLAT_ADDRESS);
+      TB.getPointerType(64, llvm::Align(8), llvm::AMDGPUAS::FLAT_ADDRESS,
+                        llvm::abi::PointerFlags::IsPointerOrReference);
   expectDirectPointerAS(
       classifyArg(GenericPtr, FI, TI, CallingConv::AMDGPU_KERNEL),
       llvm::AMDGPUAS::FLAT_ADDRESS);
diff --git a/llvm/unittests/ABI/TypesTest.cpp b/llvm/unittests/ABI/TypesTest.cpp
index 93fbde360330cd8..ead185a5b6083fc 100644
--- a/llvm/unittests/ABI/TypesTest.cpp
+++ b/llvm/unittests/ABI/TypesTest.cpp
@@ -60,6 +60,26 @@ TEST_F(ABITypesTest, AtomicTypeProperties) {
   EXPECT_FALSE(Atomic->isEmptyRecord());
 }
 
+TEST_F(ABITypesTest, PointerSourceFlagsAreExplicit) {
+  const auto *NonzeroTargetAS =
+      TB.getPointerType(64, Align(8), /*Addrspace=*/1,
+                        llvm::abi::PointerFlags::IsPointerOrReference);
+  EXPECT_TRUE(NonzeroTargetAS->isPointerOrReference());
+  EXPECT_FALSE(NonzeroTargetAS->isPointeeAddressSpaceQualified());
+
+  const auto *ExplicitSourceAS0 = TB.getPointerType(
+      64, Align(8), /*Addrspace=*/0,
+      llvm::abi::PointerFlags::IsPointerOrReference |
+          llvm::abi::PointerFlags::IsPointeeAddressSpaceQualified);
+  EXPECT_TRUE(ExplicitSourceAS0->isPointerOrReference());
+  EXPECT_TRUE(ExplicitSourceAS0->isPointeeAddressSpaceQualified());
+
+  const auto *OtherPointerRepresentation = TB.getPointerType(
+      64, Align(8), /*Addrspace=*/0, llvm::abi::PointerFlags::None);
+  EXPECT_FALSE(OtherPointerRepresentation->isPointerOrReference());
+  EXPECT_FALSE(OtherPointerRepresentation->isPointeeAddressSpaceQualified());
+}
+
 TEST_F(ABITypesTest, EmptyCRecord) {
   const RecordType *Empty = makeRecord({}, 0, RecordFlags::CanPassInRegisters);
   EXPECT_TRUE(Empty->isEmpty());
@@ -128,7 +148,9 @@ TEST_F(ABITypesTest, DirectVirtualBasesAndVTablePointer) {
   const RecordType *IntField = makeRecord(
       {FieldInfo(TB.getIntegerType(32, Align(4), /*Signed=*/true), 0)}, 32,
       CXXFlags, /*Bases=*/{}, /*VBases=*/{}, Align(4));
-  const llvm::abi::Type *VPtr = TB.getPointerType(64, Align(8));
+  const llvm::abi::Type *VPtr =
+      TB.getPointerType(64, Align(8), /*Addrspace=*/0,
+                        llvm::abi::PointerFlags::IsPointerOrReference);
   FieldInfo VTable(VPtr, 0);
 
   // Empty vbase with vtable
diff --git a/llvm/unittests/ABI/X86TargetInfoTest.cpp 
b/llvm/unittests/ABI/X86TargetInfoTest.cpp
index 021add1d8ac26fb..171db4ed69fa6e7 100644
--- a/llvm/unittests/ABI/X86TargetInfoTest.cpp
+++ b/llvm/unittests/ABI/X86TargetInfoTest.cpp
@@ -328,7 +328,9 @@ TEST_F(X86TargetInfoTest, 
UnionTailPaddingSizesHighHalfFromUnion) {
   const ABIType *U32 = TB.getIntegerType(32, llvm::Align(4), /*Signed=*/false);
   const ABIType *Words = TB.getArrayType(U32, /*NumElements=*/3,
                                          /*SizeInBits=*/96);
-  const ABIType *Ptr = TB.getPointerType(64, llvm::Align(8));
+  const ABIType *Ptr =
+      TB.getPointerType(64, llvm::Align(8), /*Addrspace=*/0,
+                        llvm::abi::PointerFlags::IsPointerOrReference);
   const ABIType *U =
       unionOf({FieldInfo(Words), FieldInfo(Ptr)}, 128, llvm::Align(8));
   llvm::ArrayRef<FieldInfo> Pair = directPair(classifyArg(U, FI, TI));
@@ -344,7 +346,9 @@ TEST_F(X86TargetInfoTest, 
UnionTailPaddingNarrowsHighHalfToByte) {
   std::unique_ptr<TargetInfo> TI;
   const ABIType *Bytes = TB.getArrayType(I8, /*NumElements=*/9,
                                          /*SizeInBits=*/72);
-  const ABIType *Ptr = TB.getPointerType(64, llvm::Align(8));
+  const ABIType *Ptr =
+      TB.getPointerType(64, llvm::Align(8), /*Addrspace=*/0,
+                        llvm::abi::PointerFlags::IsPointerOrReference);
   const ABIType *U =
       unionOf({FieldInfo(Bytes), FieldInfo(Ptr)}, 128, llvm::Align(8));
   llvm::ArrayRef<FieldInfo> Pair = directPair(classifyArg(U, FI, TI));
@@ -360,7 +364,9 @@ TEST_F(X86TargetInfoTest, 
UnionTailPaddingKeepsHighHalfPastOneByte) {
   std::unique_ptr<TargetInfo> TI;
   const ABIType *Bytes = TB.getArrayType(I8, /*NumElements=*/10,
                                          /*SizeInBits=*/80);
-  const ABIType *Ptr = TB.getPointerType(64, llvm::Align(8));
+  const ABIType *Ptr =
+      TB.getPointerType(64, llvm::Align(8), /*Addrspace=*/0,
+                        llvm::abi::PointerFlags::IsPointerOrReference);
   const ABIType *U =
       unionOf({FieldInfo(Bytes), FieldInfo(Ptr)}, 128, llvm::Align(8));
   llvm::ArrayRef<FieldInfo> Pair = directPair(classifyArg(U, FI, TI));
diff --git a/mlir/lib/ABI/ABITypeMapper.cpp b/mlir/lib/ABI/ABITypeMapper.cpp
index fe63df659302a32..2abe8734b2c1bb9 100644
--- a/mlir/lib/ABI/ABITypeMapper.cpp
+++ b/mlir/lib/ABI/ABITypeMapper.cpp
@@ -95,7 +95,8 @@ const llvm::abi::Type 
*ABITypeMapper::mapMemRefType(mlir::MemRefType type) {
     if (auto intAttr = dyn_cast<IntegerAttr>(as))
       addrSpace = intAttr.getInt();
   return builder.getPointerType(sizeInBits.getFixedValue(),
-                                llvm::Align(abiAlign), addrSpace);
+                                llvm::Align(abiAlign), addrSpace,
+                                llvm::abi::PointerFlags::None);
 }
 
 const llvm::abi::Type *ABITypeMapper::mapNoneType(mlir::NoneType type) {

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

Reply via email to