[llvm-commits] [llvm-gcc-4.2] r113726 - in /llvm-gcc-4.2/trunk/gcc: config/arm/llvm-arm-target.h config/arm/llvm-arm.cpp config/i386/llvm-i386-target.h config/i386/llvm-i386.cpp llvm-abi-default.cpp llvm-abi.h llvm-convert.cpp llvm-types.cpp

Rafael Espindola rafael.espindola at gmail.com
Sun Sep 12 02:00:41 PDT 2010


Author: rafael
Date: Sun Sep 12 04:00:41 2010
New Revision: 113726

URL: http://llvm.org/viewvc/llvm-project?rev=113726&view=rev
Log:
Fixed version of 113694. The problem with the original one is that it would
cause double accounting of sret parameters.

 Original message:

 Lower ARM function signatures a bit more. I implemented only AAPCS since that
is what I can test. With this patch we convert

struct foo {double a; int b;};
void f(int, struct foo);
void g(int a, double b, int c) {
 struct foo x = {b, c};
 f(a, x);
}

 into

------------------------------------------------------
define void @g(i32 %a.0, i32, i32 %b.0, i32 %b.1, i32 %c.0) nounwind optsize {
entry:
 tail call void @f(i32 %a.0, i32 undef, i32 %b.0, i32 %b.1, i32 %c.0,
i32 0) nounwind
 ret void
}
declare void @f(i32, i32, i32, i32, i32, i32)
----------------------------------------------------

 instead of

 ---------------------------------------------------
define void @g(i32 %a, double %b, i32 %c) nounwind optsize {
entry:
 %tmp11 = bitcast double %b to i64
 %tmp5 = zext i32 %c to i64
 tail call void @f(i32 %a, i64 %tmp11, i64 %tmp5) nounwind
 ret void
}
declare void @f(i32, i64, i64)
--------------------------------------------------

 The IL for

 ------------------------------------------
 double foo(double X, double Y) { return X+Y; }
-----------------------------------------

 now shows that the arguments being passed in the integer registres:

 ----------------------------------------------------------------------
define double @foo(i32 %X.0, i32 %X.1, i32 %Y.0, i32 %Y.1) nounwind
readnone optsize {
entry:
 %tmp17 = zext i32 %X.0 to i64
 %tmp12 = zext i32 %X.1 to i64
 %tmp13 = shl i64 %tmp12, 32
 %ins15 = or i64 %tmp13, %tmp17
 %tmp6 = zext i32 %Y.0 to i64
 %tmp3 = zext i32 %Y.1 to i64
 %tmp4 = shl i64 %tmp3, 32
 %ins = or i64 %tmp4, %tmp6
 %tmp10 = bitcast i64 %ins15 to double
 %tmp2 = bitcast i64 %ins to double
 %0 = fadd double %tmp10, %tmp2
 ret double %0
}
---------------------------------------------------------------------

 And the produces assembly is the same as before:

 ----------------------------------------------------------------
foo:
       vmov    d0, r2, r3
       vmov    d1, r0, r1
       vadd.f64        d0, d1, d0
       vmov    r0, r1, d0
       bx      lr
----------------------------------------------------------------

Modified:
    llvm-gcc-4.2/trunk/gcc/config/arm/llvm-arm-target.h
    llvm-gcc-4.2/trunk/gcc/config/arm/llvm-arm.cpp
    llvm-gcc-4.2/trunk/gcc/config/i386/llvm-i386-target.h
    llvm-gcc-4.2/trunk/gcc/config/i386/llvm-i386.cpp
    llvm-gcc-4.2/trunk/gcc/llvm-abi-default.cpp
    llvm-gcc-4.2/trunk/gcc/llvm-abi.h
    llvm-gcc-4.2/trunk/gcc/llvm-convert.cpp
    llvm-gcc-4.2/trunk/gcc/llvm-types.cpp

Modified: llvm-gcc-4.2/trunk/gcc/config/arm/llvm-arm-target.h
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/gcc/config/arm/llvm-arm-target.h?rev=113726&r1=113725&r2=113726&view=diff
==============================================================================
--- llvm-gcc-4.2/trunk/gcc/config/arm/llvm-arm-target.h (original)
+++ llvm-gcc-4.2/trunk/gcc/config/arm/llvm-arm-target.h Sun Sep 12 04:00:41 2010
@@ -55,13 +55,22 @@
 #define LLVM_SHOULD_PASS_AGGREGATE_IN_MIXED_REGS(T, TY, CC, E)    \
    llvm_arm_should_pass_aggregate_in_mixed_regs((T), (TY), (CC), (E))
 
+struct DefaultABIClient;
+extern bool
+llvm_arm_try_pass_aggregate_custom(tree, std::vector<const Type*>&,
+				   CallingConv::ID&,
+				   struct DefaultABIClient*);
+
+#define LLVM_TRY_PASS_AGGREGATE_CUSTOM(T, E, CC, C)	\
+  llvm_arm_try_pass_aggregate_custom((T), (E), (CC), (C))
+
 extern
 bool llvm_arm_aggregate_partially_passed_in_regs(std::vector<const Type*>&,
                                                  std::vector<const Type*>&,
-                                                 bool, CallingConv::ID&);
+                                                 CallingConv::ID&);
 
-#define LLVM_AGGREGATE_PARTIALLY_PASSED_IN_REGS(E, SE, ISR, CC)   \
-   llvm_arm_aggregate_partially_passed_in_regs((E), (SE), (ISR), (CC))
+#define LLVM_AGGREGATE_PARTIALLY_PASSED_IN_REGS(E, SE, CC)   \
+   llvm_arm_aggregate_partially_passed_in_regs((E), (SE), (CC))
 
 extern const Type *llvm_arm_aggr_type_for_struct_return(tree type,
                                                         CallingConv::ID &CC);

Modified: llvm-gcc-4.2/trunk/gcc/config/arm/llvm-arm.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/gcc/config/arm/llvm-arm.cpp?rev=113726&r1=113725&r2=113726&view=diff
==============================================================================
--- llvm-gcc-4.2/trunk/gcc/config/arm/llvm-arm.cpp (original)
+++ llvm-gcc-4.2/trunk/gcc/config/arm/llvm-arm.cpp Sun Sep 12 04:00:41 2010
@@ -2557,6 +2557,91 @@
   }
 }
 
+static unsigned count_num_words(std::vector<const Type*> &ScalarElts) {
+  unsigned NumWords = 0;
+  for (unsigned i = 0, e = ScalarElts.size(); i != e; ++i) {
+    const Type *Ty = ScalarElts[i];
+    if (Ty->isPointerTy()) {
+      NumWords++;
+    } else if (Ty->isIntegerTy()) {
+      const unsigned TypeSize = Ty->getPrimitiveSizeInBits();
+      const unsigned NumWordsForType = (TypeSize + 31) / 32;
+
+      NumWords += NumWordsForType;
+    } else {
+      assert (0 && "Unexpected type.");
+    }
+  }
+  return NumWords;
+}
+
+// This function is used only on AAPCS. The difference from the generic
+// handling of arguments is that arguments larger than 32 bits are split
+// and padding arguments are added as necessary for alignment. This makes
+// the IL a bit more explicit about how arguments are handled.
+extern bool
+llvm_arm_try_pass_aggregate_custom(tree type,
+                                   std::vector<const Type*>& ScalarElts,
+				   CallingConv::ID& CC,
+				   struct DefaultABIClient* C) {
+  if (CC != CallingConv::ARM_AAPCS && CC != CallingConv::C)
+    return false;
+
+  if (CC == CallingConv::C && !TARGET_AAPCS_BASED)
+    return false;
+
+  if (TARGET_HARD_FLOAT_ABI)
+    return false;
+  const Type *Ty = ConvertType(type);
+  if (Ty->isPointerTy())
+    return false;
+
+  const unsigned Size = TREE_INT_CST_LOW(TYPE_SIZE(type))/8;
+  const unsigned Alignment = TYPE_ALIGN(type)/8;
+  const unsigned NumWords = count_num_words(ScalarElts);
+  const bool AddPad = Alignment >= 8 && (NumWords % 2);
+
+  // First, build a type that will be bitcast to the original one and
+  // from where elements will be extracted.
+  std::vector<const Type*> Elts;
+  const Type* Int32Ty = Type::getInt32Ty(getGlobalContext());
+  const unsigned NumRegularArgs = Size / 4;
+  for (unsigned i = 0; i < NumRegularArgs; ++i) {
+    Elts.push_back(Int32Ty);
+  }
+  const unsigned RestSize = Size % 4;
+  const llvm::Type *RestType = NULL;
+  if (RestSize> 2) {
+    RestType = Type::getInt32Ty(getGlobalContext());
+  } else if (RestSize > 1) {
+    RestType = Type::getInt16Ty(getGlobalContext());
+  } else if (RestSize > 0) {
+    RestType = Type::getInt8Ty(getGlobalContext());
+  }
+  if (RestType)
+    Elts.push_back(RestType);
+  const StructType *STy = StructType::get(getGlobalContext(), Elts, false);
+
+  if (AddPad) {
+    ScalarElts.push_back(Int32Ty);
+    C->HandlePad(Int32Ty);
+  }
+
+  for (unsigned i = 0; i < NumRegularArgs; ++i) {
+    C->EnterField(i, STy);
+    C->HandleScalarArgument(Int32Ty, 0);
+    ScalarElts.push_back(Int32Ty);
+    C->ExitField();
+  }
+  if (RestType) {
+    C->EnterField(NumRegularArgs, STy);
+    C->HandleScalarArgument(RestType, 0, RestSize);
+    ScalarElts.push_back(RestType);
+    C->ExitField();
+  }
+  return true;
+}
+
 // Target hook for llvm-abi.h. It returns true if an aggregate of the
 // specified type should be passed in a number of registers of mixed types.
 // It also returns a vector of types that correspond to the registers used
@@ -2658,7 +2743,6 @@
 bool
 llvm_arm_aggregate_partially_passed_in_regs(std::vector<const Type*> &Elts,
                                             std::vector<const Type*> &ScalarElts,
-                                            bool isShadowReturn,
                                             CallingConv::ID &CC) {
   // Homogeneous aggregates are an AAPCS-VFP feature.
   if ((CC != CallingConv::ARM_AAPCS_VFP) ||

Modified: llvm-gcc-4.2/trunk/gcc/config/i386/llvm-i386-target.h
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/gcc/config/i386/llvm-i386-target.h?rev=113726&r1=113725&r2=113726&view=diff
==============================================================================
--- llvm-gcc-4.2/trunk/gcc/config/i386/llvm-i386-target.h (original)
+++ llvm-gcc-4.2/trunk/gcc/config/i386/llvm-i386-target.h Sun Sep 12 04:00:41 2010
@@ -219,12 +219,11 @@
 
 extern
 bool llvm_x86_64_aggregate_partially_passed_in_regs(std::vector<const Type*>&,
-                                                    std::vector<const Type*>&,
-                                                    bool);
+                                                    std::vector<const Type*>&);
 
-#define LLVM_AGGREGATE_PARTIALLY_PASSED_IN_REGS(E, SE, ISR, CC)       \
+#define LLVM_AGGREGATE_PARTIALLY_PASSED_IN_REGS(E, SE, CC)       \
   (TARGET_64BIT ?                                                     \
-   llvm_x86_64_aggregate_partially_passed_in_regs((E), (SE), (ISR)) : \
+   llvm_x86_64_aggregate_partially_passed_in_regs((E), (SE)) : \
    false)
 
 #endif /* LLVM_ABI_H */

Modified: llvm-gcc-4.2/trunk/gcc/config/i386/llvm-i386.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/gcc/config/i386/llvm-i386.cpp?rev=113726&r1=113725&r2=113726&view=diff
==============================================================================
--- llvm-gcc-4.2/trunk/gcc/config/i386/llvm-i386.cpp (original)
+++ llvm-gcc-4.2/trunk/gcc/config/i386/llvm-i386.cpp Sun Sep 12 04:00:41 2010
@@ -869,8 +869,7 @@
    be passed in memory. */
 bool
 llvm_x86_64_aggregate_partially_passed_in_regs(std::vector<const Type*> &Elts,
-                                         std::vector<const Type*> &ScalarElts,
-                                         bool isShadowReturn) {
+                                         std::vector<const Type*> &ScalarElts) {
   // Counting number of GPRs and XMMs used so far. According to AMD64 ABI
   // document: "If there are no registers available for any eightbyte of an
   // argument, the whole  argument is passed on the stack." X86-64 uses 6
@@ -879,7 +878,7 @@
   // both parts will be in memory.
   // FIXME: This is a temporary solution. To be removed when llvm has first
   // class aggregate values.
-  unsigned NumGPRs = isShadowReturn ? 1 : 0;
+  unsigned NumGPRs = 0;
   unsigned NumXMMs = 0;
   count_num_registers_uses(ScalarElts, NumGPRs, NumXMMs);
 

Modified: llvm-gcc-4.2/trunk/gcc/llvm-abi-default.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/gcc/llvm-abi-default.cpp?rev=113726&r1=113725&r2=113726&view=diff
==============================================================================
--- llvm-gcc-4.2/trunk/gcc/llvm-abi-default.cpp (original)
+++ llvm-gcc-4.2/trunk/gcc/llvm-abi-default.cpp Sun Sep 12 04:00:41 2010
@@ -8,7 +8,8 @@
 /// return type. It potentially breaks down the argument and invokes methods
 /// on the client that indicate how its pieces should be handled.  This
 /// handles things like returning structures via hidden parameters.
-void DefaultABI::HandleReturnType(tree type, tree fn, bool isBuiltin) {
+void DefaultABI::HandleReturnType(tree type, tree fn, bool isBuiltin,
+                                  std::vector<const Type*> &ScalarElts) {
   unsigned Offset = 0;
   const Type *Ty = ConvertType(type);
   if (Ty->isVectorTy()) {
@@ -52,7 +53,9 @@
 
     // FIXME: should return the hidden first argument for some targets
     // (e.g. ELF i386).
-    C.HandleAggregateShadowResult(Ty->getPointerTo(), false);
+    const PointerType *PTy = Ty->getPointerTo();
+    C.HandleAggregateShadowResult(PTy, false);
+    ScalarElts.push_back(PTy);
   }
 }
 
@@ -104,7 +107,6 @@
 						      C.getCallingConv(),
 						      Elts)) {
     if (!LLVM_AGGREGATE_PARTIALLY_PASSED_IN_REGS(Elts, ScalarElts,
-						 C.isShadowReturn(),
 						 C.getCallingConv()))
       PassInMixedRegisters(Ty, Elts, ScalarElts);
     else {

Modified: llvm-gcc-4.2/trunk/gcc/llvm-abi.h
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/gcc/llvm-abi.h?rev=113726&r1=113725&r2=113726&view=diff
==============================================================================
--- llvm-gcc-4.2/trunk/gcc/llvm-abi.h (original)
+++ llvm-gcc-4.2/trunk/gcc/llvm-abi.h Sun Sep 12 04:00:41 2010
@@ -302,7 +302,7 @@
 // the aggregate. Note, this routine should return false if none of the needed
 // registers are available.
 #ifndef LLVM_AGGREGATE_PARTIALLY_PASSED_IN_REGS
-#define LLVM_AGGREGATE_PARTIALLY_PASSED_IN_REGS(E, SE, ISR, CC) \
+#define LLVM_AGGREGATE_PARTIALLY_PASSED_IN_REGS(E, SE, CC) \
     false
 #endif
 
@@ -396,7 +396,8 @@
   /// return type. It potentially breaks down the argument and invokes methods
   /// on the client that indicate how its pieces should be handled.  This
   /// handles things like returning structures via hidden parameters.
-  void HandleReturnType(tree type, tree fn, bool isBuiltin);
+  void HandleReturnType(tree type, tree fn, bool isBuiltin,
+                        std::vector<const Type*> &ScalarElts);
 
   /// HandleArgument - This is invoked by the target-independent code for each
   /// argument type passed into the function.  It potentially breaks down the

Modified: llvm-gcc-4.2/trunk/gcc/llvm-convert.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/gcc/llvm-convert.cpp?rev=113726&r1=113725&r2=113726&view=diff
==============================================================================
--- llvm-gcc-4.2/trunk/gcc/llvm-convert.cpp (original)
+++ llvm-gcc-4.2/trunk/gcc/llvm-convert.cpp Sun Sep 12 04:00:41 2010
@@ -436,13 +436,13 @@
 // passed in memory byval.
 static bool isPassedByVal(tree type, const Type *Ty,
                           std::vector<const Type*> &ScalarArgs,
-                          bool isShadowRet, CallingConv::ID &CC) {
+                          CallingConv::ID &CC) {
   if (LLVM_SHOULD_PASS_AGGREGATE_USING_BYVAL_ATTR(type, Ty))
     return true;
 
   std::vector<const Type*> Args;
   if (LLVM_SHOULD_PASS_AGGREGATE_IN_MIXED_REGS(type, Ty, CC, Args) &&
-      LLVM_AGGREGATE_PARTIALLY_PASSED_IN_REGS(Args, ScalarArgs, isShadowRet,
+      LLVM_AGGREGATE_PARTIALLY_PASSED_IN_REGS(Args, ScalarArgs,
                                               CC))
     // We want to pass the whole aggregate in registers but only some of the
     // registers are available.
@@ -673,17 +673,19 @@
   FunctionPrologArgumentConversion Client(FnDecl, AI, Builder, CallingConv);
   DefaultABI ABIConverter(Client);
 
+  // Scalar arguments processed so far.
+  std::vector<const Type*> ScalarArgs;
+
   // Handle the DECL_RESULT.
   ABIConverter.HandleReturnType(TREE_TYPE(TREE_TYPE(FnDecl)), FnDecl,
-                                DECL_BUILT_IN(FnDecl));
+                                DECL_BUILT_IN(FnDecl),
+                                ScalarArgs);
   // Remember this for use by FinishFunctionBody.
   ReturnOffset = Client.Offset;
 
   // Prepend the static chain (if any) to the list of arguments.
   tree Args = static_chain ? static_chain : DECL_ARGUMENTS(FnDecl);
 
-  // Scalar arguments processed so far.
-  std::vector<const Type*> ScalarArgs;
   while (Args) {
     const char *Name = "unnamed_arg";
     if (DECL_NAME(Args)) Name = IDENTIFIER_POINTER(DECL_NAME(Args));
@@ -696,7 +698,7 @@
          !LLVM_BYVAL_ALIGNMENT_TOO_SMALL(TREE_TYPE(Args))) ||
         (!ArgTy->isSingleValueType() &&
          isPassedByVal(TREE_TYPE(Args), ArgTy, ScalarArgs,
-                       Client.isShadowReturn(), CallingConv) &&
+                       CallingConv) &&
          !LLVM_BYVAL_ALIGNMENT_TOO_SMALL(TREE_TYPE(Args)))) {
       // If the value is passed by 'invisible reference' or 'byval reference',
       // the l-value for the argument IS the argument itself.  But for byval
@@ -3012,16 +3014,17 @@
   DefaultABI ABIConverter(Client);
 
   // Handle the result, including struct returns.
+  std::vector<const Type*> ScalarArgs;
   ABIConverter.HandleReturnType(TREE_TYPE(exp),
                                 fndecl ? fndecl : exp,
-                                fndecl ? DECL_BUILT_IN(fndecl) : false);
+                                fndecl ? DECL_BUILT_IN(fndecl) : false,
+                                ScalarArgs);
 
   // Pass the static chain, if any, as the first parameter.
   if (TREE_OPERAND(exp, 2))
     CallOperands.push_back(Emit(TREE_OPERAND(exp, 2), 0));
 
   // Loop over the arguments, expanding them and adding them to the op list.
-  std::vector<const Type*> ScalarArgs;
   for (tree arg = TREE_OPERAND(exp, 1); arg; arg = TREE_CHAIN(arg)) {
     tree type = TREE_TYPE(TREE_VALUE(arg));
     const Type *ArgTy = ConvertType(type);

Modified: llvm-gcc-4.2/trunk/gcc/llvm-types.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/gcc/llvm-types.cpp?rev=113726&r1=113725&r2=113726&view=diff
==============================================================================
--- llvm-gcc-4.2/trunk/gcc/llvm-types.cpp (original)
+++ llvm-gcc-4.2/trunk/gcc/llvm-types.cpp Sun Sep 12 04:00:41 2010
@@ -1082,8 +1082,10 @@
   TARGET_ADJUST_LLVM_CC(CallingConv, type);
 #endif
   
+  std::vector<const Type*> ScalarArgs;
   // Builtins are always prototyped, so this isn't one.
-  ABIConverter.HandleReturnType(ReturnType, current_function_decl, false);
+  ABIConverter.HandleReturnType(ReturnType, current_function_decl, false,
+                                ScalarArgs);
 
   SmallVector<AttributeWithIndex, 8> Attrs;
 
@@ -1110,7 +1112,6 @@
     Attrs.push_back(AttributeWithIndex::get(ArgTys.size(),
                                     Attribute::StructRet));
 
-  std::vector<const Type*> ScalarArgs;
   if (static_chain) {
     // Pass the static chain as the first parameter.
     ABIConverter.HandleArgument(TREE_TYPE(static_chain), ScalarArgs);
@@ -1152,8 +1153,10 @@
   TARGET_ADJUST_LLVM_CC(CallingConv, type);
 #endif
 
+  std::vector<const Type*> ScalarArgs;
   ABIConverter.HandleReturnType(TREE_TYPE(type), current_function_decl,
-                                decl ? DECL_BUILT_IN(decl) : false);
+                                decl ? DECL_BUILT_IN(decl) : false,
+                                ScalarArgs);
   
   // Compute attributes for return type (and function attributes).
   SmallVector<AttributeWithIndex, 8> Attrs;
@@ -1218,7 +1221,6 @@
     Attrs.push_back(AttributeWithIndex::get(ArgTypes.size(),
                                     Attribute::StructRet | Attribute::NoAlias));
 
-  std::vector<const Type*> ScalarArgs;
   if (static_chain) {
     // Pass the static chain as the first parameter.
     ABIConverter.HandleArgument(TREE_TYPE(static_chain), ScalarArgs);





More information about the llvm-commits mailing list