]> granicus.if.org Git - clang/commitdiff
[lanai] Update handling of structs in arguments to be passed in registers.
authorJacques Pienaar <jpienaar@google.com>
Tue, 26 Apr 2016 00:09:29 +0000 (00:09 +0000)
committerJacques Pienaar <jpienaar@google.com>
Tue, 26 Apr 2016 00:09:29 +0000 (00:09 +0000)
Previously aggregate types were passed byval, change the ABI to pass these in registers instead.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@267496 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/TargetInfo.cpp
test/CodeGen/lanai-arguments.c

index 8ad3290192b5fc54ae4c4039d485f3fa26b9af51..9170d5884f64f50acb50406baad1bd91316f27cc 100644 (file)
@@ -6691,6 +6691,7 @@ public:
       I.info = classifyArgumentType(I.type, State);
   }
 
+  ABIArgInfo getIndirectResult(QualType Ty, bool ByVal, CCState &State) const;
   ABIArgInfo classifyArgumentType(QualType RetTy, CCState &State) const;
 };
 } // end anonymous namespace
@@ -6712,21 +6713,72 @@ bool LanaiABIInfo::shouldUseInReg(QualType Ty, CCState &State) const {
   return true;
 }
 
+ABIArgInfo LanaiABIInfo::getIndirectResult(QualType Ty, bool ByVal,
+                                           CCState &State) const {
+  if (!ByVal) {
+    if (State.FreeRegs) {
+      --State.FreeRegs; // Non-byval indirects just use one pointer.
+      return getNaturalAlignIndirectInReg(Ty);
+    }
+    return getNaturalAlignIndirect(Ty, false);
+  }
+
+  // Compute the byval alignment.
+  constexpr unsigned MinABIStackAlignInBytes = 4;
+  unsigned TypeAlign = getContext().getTypeAlign(Ty) / 8;
+  return ABIArgInfo::getIndirect(CharUnits::fromQuantity(4), /*ByVal=*/true,
+                                 /*Realign=*/TypeAlign >
+                                     MinABIStackAlignInBytes);
+}
+
 ABIArgInfo LanaiABIInfo::classifyArgumentType(QualType Ty,
                                               CCState &State) const {
-  if (isAggregateTypeForABI(Ty))
-    return getNaturalAlignIndirect(Ty);
+  // Check with the C++ ABI first.
+  const RecordType *RT = Ty->getAs<RecordType>();
+  if (RT) {
+    CGCXXABI::RecordArgABI RAA = getRecordArgABI(RT, getCXXABI());
+    if (RAA == CGCXXABI::RAA_Indirect) {
+      return getIndirectResult(Ty, /*ByVal=*/false, State);
+    } else if (RAA == CGCXXABI::RAA_DirectInMemory) {
+      return getNaturalAlignIndirect(Ty, /*ByRef=*/true);
+    }
+  }
+
+  if (isAggregateTypeForABI(Ty)) {
+    // Structures with flexible arrays are always indirect.
+    if (RT && RT->getDecl()->hasFlexibleArrayMember())
+      return getIndirectResult(Ty, /*ByVal=*/true, State);
+
+    // Ignore empty structs/unions.
+    if (isEmptyRecord(getContext(), Ty, true))
+      return ABIArgInfo::getIgnore();
+
+    llvm::LLVMContext &LLVMContext = getVMContext();
+    unsigned SizeInRegs = (getContext().getTypeSize(Ty) + 31) / 32;
+    if (SizeInRegs <= State.FreeRegs) {
+      llvm::IntegerType *Int32 = llvm::Type::getInt32Ty(LLVMContext);
+      SmallVector<llvm::Type *, 3> Elements(SizeInRegs, Int32);
+      llvm::Type *Result = llvm::StructType::get(LLVMContext, Elements);
+      State.FreeRegs -= SizeInRegs;
+      return ABIArgInfo::getDirectInReg(Result);
+    } else {
+      State.FreeRegs = 0;
+    }
+    return getIndirectResult(Ty, true, State);
+  }
 
   // Treat an enum type as its underlying type.
   if (const auto *EnumTy = Ty->getAs<EnumType>())
     Ty = EnumTy->getDecl()->getIntegerType();
 
-  if (shouldUseInReg(Ty, State))
-    return ABIArgInfo::getDirectInReg();
-
-  if (Ty->isPromotableIntegerType())
+  bool InReg = shouldUseInReg(Ty, State);
+  if (Ty->isPromotableIntegerType()) {
+    if (InReg)
+      return ABIArgInfo::getDirectInReg();
     return ABIArgInfo::getExtend();
-
+  }
+  if (InReg)
+    return ABIArgInfo::getDirectInReg();
   return ABIArgInfo::getDirect();
 }
 
index 43a6c3280c71666b8b165ddd4a4b8a57c84d0de8..9ce4ed98a78cee9bbd69e51fb757bb765cb7f456 100644 (file)
@@ -10,7 +10,7 @@ typedef struct {
   int aa;
   int bb;
 } s1;
-// CHECK: define void @f1(%struct.s1* byval align 4 %i)
+// CHECK: define void @f1(i32 inreg %i.coerce0, i32 inreg %i.coerce1)
 void f1(s1 i) {}
 
 typedef struct {
@@ -61,8 +61,8 @@ union simple_union {
   int a;
   char b;
 };
-// Unions should be passed as byval structs.
-// CHECK: define void @f9(%union.simple_union* byval align 4 %s)
+// Unions should be passed inreg.
+// CHECK: define void @f9(i32 inreg %s.coerce)
 void f9(union simple_union s) {}
 
 typedef struct {
@@ -70,6 +70,6 @@ typedef struct {
   int b3 : 3;
   int b8 : 8;
 } bitfield1;
-// Bitfields should be passed as byval structs.
-// CHECK: define void @f10(%struct.bitfield1* byval align 4 %bf1)
+// Bitfields should be passed inreg.
+// CHECK: define void @f10(i32 inreg %bf1.coerce)
 void f10(bitfield1 bf1) {}