nickdesaulniers created this revision.
Herald added a project: All.
nickdesaulniers requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D158448

Files:
  clang/lib/CodeGen/Targets/ARM.cpp
  clang/test/CodeGen/aapcs-align.cpp
  clang/test/CodeGen/arm-arguments.c

Index: clang/test/CodeGen/arm-arguments.c
===================================================================
--- clang/test/CodeGen/arm-arguments.c
+++ clang/test/CodeGen/arm-arguments.c
@@ -158,10 +158,10 @@
 // PR11905
 struct s31 { char x; };
 void f31(struct s31 s) { }
-// AAPCS: @f31([1 x i32] %s.coerce)
+// AAPCS: @f31(i8 %s.coerce)
 // AAPCS: %s = alloca %struct.s31, align 1
-// AAPCS: [[TEMP:%.*]] = alloca [1 x i32], align 4
-// AAPCS: store [1 x i32] %s.coerce, ptr [[TEMP]], align 4
+// AAPCS: [[TEMP:%.*]] = getelementptr inbounds %struct.s31, ptr %s, i32 0, i32 0
+// AAPCS: store i8 %s.coerce, ptr [[TEMP]], align 1
 // APCS-GNU: @f31([1 x i32] %s.coerce)
 // APCS-GNU: %s = alloca %struct.s31, align 1
 // APCS-GNU: [[TEMP:%.*]] = alloca [1 x i32], align 4
@@ -184,8 +184,8 @@
 void f34(struct s34 s);
 void g34(struct s34 *s) { f34(*s); }
 // AAPCS: @g34(ptr noundef %s)
-// AAPCS: %[[a:.*]] = alloca [1 x i32]
-// AAPCS: load [1 x i32], ptr %[[a]]
+// AAPCS: %[[a:.*]] = alloca ptr, align 4
+// AAPCS: load ptr, ptr %[[a]]
 
 // rdar://12596507
 struct s35
Index: clang/test/CodeGen/aapcs-align.cpp
===================================================================
--- clang/test/CodeGen/aapcs-align.cpp
+++ clang/test/CodeGen/aapcs-align.cpp
@@ -19,10 +19,10 @@
   f0m(1, 2, 3, 4, 5, s);
 }
 // CHECK: define{{.*}} void @g0
-// CHECK: call void @f0(i32 noundef 1, [2 x i32] [i32 6, i32 7]
-// CHECK: call void @f0m(i32 noundef 1, i32 noundef 2, i32 noundef 3, i32 noundef 4, i32 noundef 5, [2 x i32] [i32 6, i32 7]
-// CHECK: declare void @f0(i32 noundef, [2 x i32])
-// CHECK: declare void @f0m(i32 noundef, i32 noundef, i32 noundef, i32 noundef, i32 noundef, [2 x i32])
+// CHECK: call void @f0(i32 noundef 1, i32 6, i32 7
+// CHECK: call void @f0m(i32 noundef 1, i32 noundef 2, i32 noundef 3, i32 noundef 4, i32 noundef 5, i32 6, i32 7)
+// CHECK: declare void @f0(i32 noundef, i32, i32)
+// CHECK: declare void @f0m(i32 noundef, i32 noundef, i32 noundef, i32 noundef, i32 noundef, i32, i32)
 
 // Aligned struct, passed according to its natural alignment.
 struct __attribute__((aligned(8))) S8 {
@@ -37,10 +37,10 @@
   f1m(1, 2, 3, 4, 5, s);
 }
 // CHECK: define{{.*}} void @g1
-// CHECK: call void @f1(i32 noundef 1, [2 x i32] [i32 6, i32 7]
-// CHECK: call void @f1m(i32 noundef 1, i32 noundef 2, i32 noundef 3, i32 noundef 4, i32 noundef 5, [2 x i32] [i32 6, i32 7]
-// CHECK: declare void @f1(i32 noundef, [2 x i32])
-// CHECK: declare void @f1m(i32 noundef, i32 noundef, i32 noundef, i32 noundef, i32 noundef, [2 x i32])
+// CHECK: call void @f1(i32 noundef 1, i32 6, i32 7)
+// CHECK: call void @f1m(i32 noundef 1, i32 noundef 2, i32 noundef 3, i32 noundef 4, i32 noundef 5, i32 6, i32 7)
+// CHECK: declare void @f1(i32 noundef, i32, i32)
+// CHECK: declare void @f1m(i32 noundef, i32 noundef, i32 noundef, i32 noundef, i32 noundef, i32, i32)
 
 // Aligned struct, passed according to its natural alignment.
 struct alignas(16) S16 {
@@ -56,10 +56,10 @@
   f2m(1, 2, 3, 4, 5, s);
 }
 // CHECK: define{{.*}} void @g2
-// CHECK: call void @f2(i32 noundef 1, [4 x i32] [i32 6, i32 7
-// CHECK: call void @f2m(i32 noundef 1, i32 noundef 2, i32 noundef 3, i32 noundef 4, i32 noundef 5, [4 x i32] [i32 6, i32 7
-// CHECK: declare void @f2(i32 noundef, [4 x i32])
-// CHECK: declare void @f2m(i32 noundef, i32 noundef, i32 noundef, i32 noundef, i32 noundef, [4 x i32])
+// CHECK: call void @f2(i32 noundef 1, i32 6, i32 7)
+// CHECK: call void @f2m(i32 noundef 1, i32 noundef 2, i32 noundef 3, i32 noundef 4, i32 noundef 5, i32 6, i32 7)
+// CHECK: declare void @f2(i32 noundef, i32, i32)
+// CHECK: declare void @f2m(i32 noundef, i32 noundef, i32 noundef, i32 noundef, i32 noundef, i32, i32)
 
 // Increased natural alignment.
 struct SF8 {
@@ -75,10 +75,10 @@
   f3m(1, 2, 3, 4, 5, s);
 }
 // CHECK: define{{.*}} void @g3
-// CHECK: call void @f3(i32 noundef 1, [1 x i64] [i64 30064771078]
-// CHECK: call void @f3m(i32 noundef 1, i32 noundef 2, i32 noundef 3, i32 noundef 4, i32 noundef 5, [1 x i64] [i64 30064771078]
-// CHECK: declare void @f3(i32 noundef, [1 x i64])
-// CHECK: declare void @f3m(i32 noundef, i32 noundef, i32 noundef, i32 noundef, i32 noundef, [1 x i64])
+// CHECK: call void @f3(i32 noundef 1, i32 6, i32 7)
+// CHECK: call void @f3m(i32 noundef 1, i32 noundef 2, i32 noundef 3, i32 noundef 4, i32 noundef 5, i32 6, i32 7)
+// CHECK: declare void @f3(i32 noundef, i32, i32)
+// CHECK: declare void @f3m(i32 noundef, i32 noundef, i32 noundef, i32 noundef, i32 noundef, i32, i32)
 
 // Increased natural alignment, capped to 8 though.
 struct SF16 {
@@ -114,10 +114,10 @@
   f5m(1, 2, 3, 4, 5, s);
 }
 // CHECK: define{{.*}} void @g5
-// CHECK: call void @f5(i32 noundef 1, [3 x i32] [i32 6, i32 7, i32 0])
-// CHECK: call void @f5m(i32 noundef 1, i32 noundef 2, i32 noundef 3, i32 noundef 4, i32 noundef 5, [3 x i32] [i32 6, i32 7, i32 0])
-// CHECK: declare void @f5(i32 noundef, [3 x i32])
-// CHECK: declare void @f5m(i32 noundef, i32 noundef, i32 noundef, i32 noundef, i32 noundef, [3 x i32])
+// CHECK: call void @f5(i32 noundef 1, i32 6, i64 0)
+// CHECK: call void @f5m(i32 noundef 1, i32 noundef 2, i32 noundef 3, i32 noundef 4, i32 noundef 5, i32 6, i64 0)
+// CHECK: declare void @f5(i32 noundef, i32, i64)
+// CHECK: declare void @f5m(i32 noundef, i32 noundef, i32 noundef, i32 noundef, i32 noundef, i32, i64)
 
 
 // Packed and aligned, alignement causes padding at the end.
@@ -134,8 +134,8 @@
   f6m(1, 2, 3, 4, 5, s);
 }
 // CHECK: define{{.*}} void @g6
-// CHECK: call void @f6(i32 noundef 1, [4 x i32] [i32 6, i32 7, i32 0, i32 undef])
-// CHECK: call void @f6m(i32 noundef 1, i32 noundef 2, i32 noundef 3, i32 noundef 4, i32 noundef 5, [4 x i32] [i32 6, i32 7, i32 0, i32 undef])
-// CHECK: declare void @f6(i32 noundef, [4 x i32])
-// CHECK: declare void @f6m(i32 noundef, i32 noundef, i32 noundef, i32 noundef, i32 noundef, [4 x i32])
+// CHECK: call void @f6(i32 noundef 1, i32 6, i64 0)
+// CHECK: call void @f6m(i32 noundef 1, i32 noundef 2, i32 noundef 3, i32 noundef 4, i32 noundef 5, i32 6, i64 0)
+// CHECK: declare void @f6(i32 noundef, i32, i64)
+// CHECK: declare void @f6m(i32 noundef, i32 noundef, i32 noundef, i32 noundef, i32 noundef, i32, i64)
 }
Index: clang/lib/CodeGen/Targets/ARM.cpp
===================================================================
--- clang/lib/CodeGen/Targets/ARM.cpp
+++ clang/lib/CodeGen/Targets/ARM.cpp
@@ -330,6 +330,50 @@
   return ABIArgInfo::getDirect(nullptr, 0, nullptr, false, Align);
 }
 
+static bool isIntegerLikeType(QualType Ty, ASTContext &Context,
+                              llvm::LLVMContext &VMContext);
+
+// Returns true if `Ty` could be flattened into a valid ABIArgInfo `A`.
+static bool canFlatten(const RecordType *Ty, ASTContext &Ctx, llvm::LLVMContext &LLVMCtx, ABIArgInfo *A) {
+  // AAPCS32 6.5 Parameter Passing
+  // The base standard provides for passing arguments in core registers (r0-r3)
+  // and on the stack.
+  // ...
+  // When a Composite Type argument is assigned to core registers (either fully
+  // or partially), the behavior is as if the argument had been stored to memory
+  // at a word-aligned (4-byte) address and then loaded into consecutive
+  // registers using a suitable load-multiple instruction.
+
+  const RecordDecl *RD = Ty->getDecl();
+  const long NumFields = std::distance(RD->field_begin(), RD->field_end());
+  if (NumFields < 0 || NumFields > 4)
+    return false;
+
+  llvm::SmallVector<llvm::Type*, 4> ParamTypes;
+  uint64_t TotalSize = 0;
+  for (FieldDecl *FD : RD->fields()) {
+    QualType FieldType = FD->getType();
+    if (!FieldType->isIntegerType())
+      return false;
+
+    // Size in bits.
+    uint64_t TypeSize = Ctx.getTypeSize(FieldType);
+    if (TypeSize > 64)
+      return false;
+
+    TotalSize += TypeSize;
+    if (TotalSize > 16 * 8)
+      return false;
+
+    llvm::Type *T = llvm::Type::getIntNTy(LLVMCtx, TypeSize);
+    ParamTypes.push_back(T);
+  }
+
+  // llvm::dbgs() << llvm::StructType::get(LLVMCtx, ParamTypes) << "\n";
+  *A = ABIArgInfo::getDirect(llvm::StructType::get(LLVMCtx, ParamTypes));
+  return true;
+}
+
 ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty, bool isVariadic,
                                             unsigned functionCallConv) const {
   // 6.1.2.1 The following argument types are VFP CPRCs:
@@ -427,11 +471,16 @@
     return coerceToIntArray(Ty, getContext(), getVMContext());
   }
 
+  // Try to flatten small structs.
+  if (getABIKind() == ARMABIKind::AAPCS && Ty->isStructureType()) {
+    ABIArgInfo A;
+    if (canFlatten(Ty->getAs<RecordType>(), getContext(), getVMContext(), &A))
+      return A;
+  }
+
   // Otherwise, pass by coercing to a structure of the appropriate size.
   llvm::Type* ElemTy;
   unsigned SizeRegs;
-  // FIXME: Try to match the types of the arguments more accurately where
-  // we can.
   if (TyAlign <= 4) {
     ElemTy = llvm::Type::getInt32Ty(getVMContext());
     SizeRegs = (getContext().getTypeSize(Ty) + 31) / 32;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to