================
@@ -263,8 +294,77 @@ ArgInfo AArch64TargetInfo::classifyArgumentType(
           Ty, IsNamedArg, NVec, NPred, UnpaddedCoerceToSeq, NSRN, NPRN);
   }
 
-  reportNYI("Aggregate argument type handling");
-  return ArgInfo::getIgnore();
+  // Aggregates of at most 16 bytes are passed directly in registers or on
+  // the stack.
+  if (Size <= 128) {
+    uint64_t AlignBits;
+    if (Opts.Kind == AArch64ABIKind::AAPCS) {
+      // An 8-byte slot when the unadjusted alignment is below 16 bytes, and
+      // a 16-byte slot otherwise.
+      AlignBits = Ty->getUnadjustedAlignment().value() * 8;
+      AlignBits = AlignBits < 128 ? 64 : 128;
+    } else {
+      // The larger of the ABI alignment and the pointer width.
+      uint64_t PointerWidth = Opts.IsILP32 ? 32 : 64;
+      AlignBits = std::max(Ty->getAlignment().value() * 8, PointerWidth);
+    }
+    Size = llvm::alignTo(Size, AlignBits);
+
+    const Type *BaseTy;
+    if ((Size == 64 || Size == 128) && AlignBits == 64 &&
+        containsOnlyPointers(Ty)) {
+      // A record of 64-bit pointers in an 8-byte slot is coerced to a pointer
+      // or an array of pointers.
+      BaseTy = TB.getPointerType(64, llvm::Align(8));
+    } else {
+      // Every other aggregate is coerced to an integer of the slot width, or
+      // an array of those integers.
+      BaseTy = TB.getIntegerType(AlignBits, llvm::Align(AlignBits / 8),
+                                 /*Signed=*/false);
+    }
+
+    if (Size == AlignBits)
+      return ArgInfo::getDirect(BaseTy);
+    return ArgInfo::getDirect(TB.getArrayType(BaseTy, Size / AlignBits, Size));
+  }
+
+  return getNaturalAlignIndirect(Ty, getAllocaAddrSpace(), /*ByVal=*/false);
+}
+
+// True for a record whose bases and fields are 64-bit pointers in address
+// space 0, or records of such pointers. An array field is inspected through
+// its base element. False for an empty record and for a type that is not a
+// record.
+bool AArch64TargetInfo::containsOnlyPointers(const Type *Ty) const {
+  if (Ty->isEmptyRecord())
+    return false;
+
+  const auto *RT = dyn_cast<RecordType>(Ty);
+  if (!RT)
+    return false;
+
+  for (const FieldInfo &Base : RT->getBaseClasses())
+    if (!containsOnlyPointers(Base.FieldType))
+      return false;
+
+  for (const FieldInfo &Field : RT->getFields()) {
+    const Type *FT = Field.FieldType;
+    while (const auto *AT = dyn_cast<ArrayType>(FT)) {
+      // TODO: Consider whether this should accept matrix types. Clang
+      // doesn't, but that's probably an error.
+      if (AT->isMatrixType())
+        break;
+      FT = AT->getElementType();
+    }
+
+    bool IsPlainPointer = false;
+    if (const auto *PT = dyn_cast<PointerType>(FT))
+      IsPlainPointer =
+          PT->getSizeInBits().getFixedValue() == 64 && PT->getAddrSpace() == 0;
----------------
madhur13490 wrote:

I don't think this quite matches Clang. Clang checks 
!FDTy->getPointeeType().hasAddressSpace(), so any qualified address space is 
rejected, even one that ends up as target AS 0. Checking getAddrSpace() == 0 
lets those through. For example:


typedef struct { int __attribute__((address_space(0))) *p; } S0;
void f0(S0 s) {}

Clang gives i64 for this today, but I think this code would give ptr. OpenCL 
address spaces on AArch64 would have the same problem. The mapper loses that 
information when it lowers to the target AS, so we may need to carry it through.

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

Reply via email to