[llvm-commits] [llvm-gcc-4.2] r85539 - in /llvm-gcc-4.2/trunk/gcc: config/arm/llvm-arm-target.h config/arm/llvm-arm.cpp config/i386/llvm-i386-target.h llvm-abi.h llvm-types.cpp
Bob Wilson
bob.wilson at apple.com
Thu Oct 29 16:35:11 PDT 2009
Author: bwilson
Date: Thu Oct 29 18:35:11 2009
New Revision: 85539
URL: http://llvm.org/viewvc/llvm-project?rev=85539&view=rev
Log:
Fix ARM AAPCS-VFP return of homogeneous aggregates. Patch by Sandeep Patel.
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/llvm-abi.h
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=85539&r1=85538&r2=85539&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 Thu Oct 29 18:35:11 2009
@@ -25,17 +25,17 @@
specification says that varargs functions must use the base standard
instead of the VFP hard float variant. We check for that with
(isVoid || hasArgList). */
-#define TARGET_ADJUST_LLVM_CC(CC, type) \
- { \
- if (TARGET_AAPCS_BASED) \
- CC = ((TARGET_VFP && TARGET_HARD_FLOAT_ABI && \
- ((TYPE_ARG_TYPES(type) == 0) || \
- (TREE_VALUE(tree_last(TYPE_ARG_TYPES(type))) == \
- void_type_node))) ? \
- CallingConv::ARM_AAPCS_VFP : \
- CallingConv::ARM_AAPCS); \
- else \
- CC = CallingConv::ARM_APCS; \
+#define TARGET_ADJUST_LLVM_CC(CC, type) \
+ { \
+ if (TARGET_AAPCS_BASED) \
+ CC = ((TARGET_VFP && TARGET_HARD_FLOAT_ABI && \
+ ((TYPE_ARG_TYPES(type) == 0) || \
+ (TREE_VALUE(tree_last(TYPE_ARG_TYPES(type))) == \
+ void_type_node))) ? \
+ CallingConv::ARM_AAPCS_VFP : \
+ CallingConv::ARM_AAPCS); \
+ else \
+ CC = CallingConv::ARM_APCS; \
}
#ifdef LLVM_ABI_H
@@ -45,7 +45,7 @@
CallingConv::ID&,
std::vector<const Type*>&);
-#define LLVM_SHOULD_PASS_AGGREGATE_IN_MIXED_REGS(T, TY, CC, E) \
+#define LLVM_SHOULD_PASS_AGGREGATE_IN_MIXED_REGS(T, TY, CC, E) \
llvm_arm_should_pass_aggregate_in_mixed_regs((T), (TY), (CC), (E))
extern
@@ -53,9 +53,35 @@
std::vector<const Type*>&,
bool, CallingConv::ID&);
-#define LLVM_AGGREGATE_PARTIALLY_PASSED_IN_REGS(E, SE, ISR, CC) \
+#define LLVM_AGGREGATE_PARTIALLY_PASSED_IN_REGS(E, SE, ISR, CC) \
llvm_arm_aggregate_partially_passed_in_regs((E), (SE), (ISR), (CC))
+extern const Type *llvm_arm_aggr_type_for_struct_return(tree type,
+ CallingConv::ID &CC);
+
+/* LLVM_AGGR_TYPE_FOR_STRUCT_RETURN - Return LLVM Type if X can be
+ returned as an aggregate, otherwise return NULL. */
+#define LLVM_AGGR_TYPE_FOR_STRUCT_RETURN(X, CC) \
+ llvm_arm_aggr_type_for_struct_return((X), (CC))
+
+extern void llvm_arm_extract_multiple_return_value(Value *Src, Value *Dest,
+ bool isVolatile,
+ LLVMBuilder &B);
+
+/* LLVM_EXTRACT_MULTIPLE_RETURN_VALUE - Extract multiple return value from
+ SRC and assign it to DEST. */
+#define LLVM_EXTRACT_MULTIPLE_RETURN_VALUE(Src,Dest,V,B) \
+ llvm_arm_extract_multiple_return_value((Src),(Dest),(V),(B))
+
+extern
+bool llvm_arm_should_pass_or_return_aggregate_in_regs(tree TreeType,
+ CallingConv::ID &CC);
+
+/* LLVM_SHOULD_NOT_USE_SHADOW_RETURN = Return true is the given type should
+ not be returned via a shadow parameter with the given calling conventions. */
+#define LLVM_SHOULD_NOT_USE_SHADOW_RETURN(X, CC) \
+ llvm_arm_should_pass_or_return_aggregate_in_regs((X), (CC))
+
#endif /* LLVM_ABI_H */
#endif /* ENABLE_LLVM */
/* LLVM LOCAL end (ENTIRE FILE!) */
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=85539&r1=85538&r2=85539&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 Thu Oct 29 18:35:11 2009
@@ -2524,24 +2524,14 @@
llvm_arm_should_pass_aggregate_in_mixed_regs(tree TreeType, const Type *Ty,
CallingConv::ID &CC,
std::vector<const Type*> &Elts) {
- // Homogeneous aggregates are an AAPCS-VFP feature.
- if ((CC != CallingConv::ARM_AAPCS_VFP) ||
- !(TARGET_AAPCS_BASED && TARGET_VFP && TARGET_HARD_FLOAT_ABI))
+ if (!llvm_arm_should_pass_or_return_aggregate_in_regs(TreeType, CC))
return false;
- // Alas, we can't use LLVM Types to figure this out because we need to
- // examine unions closely. We'll have to walk the GCC TreeType.
- int fdt_counts[ARM_FDT_MAX] = { 0 };
- bool result = false;
- result = vfp_arg_homogeneous_aggregate_p(TYPE_MODE(TreeType), TreeType,
- fdt_counts);
-
// Walk Ty and push LLVM types corresponding to register types onto
// Elts.
- if (result)
- push_elts(Ty, Elts);
+ push_elts(Ty, Elts);
- return result;
+ return true;
}
static bool alloc_next_spr(bool *SPRs)
@@ -2645,4 +2635,124 @@
return false; // it all fit in registers!
}
+// Return LLVM Type if TYPE can be returned as an aggregate,
+// otherwise return NULL.
+const Type *llvm_arm_aggr_type_for_struct_return(tree TreeType,
+ CallingConv::ID &CC) {
+ if (!llvm_arm_should_pass_or_return_aggregate_in_regs(TreeType, CC))
+ return NULL;
+
+ // Walk Ty and push LLVM types corresponding to register types onto
+ // Elts.
+ std::vector<const Type*> Elts;
+ const Type *Ty = ConvertType(TreeType);
+ push_elts(Ty, Elts);
+
+ return StructType::get(Context, Elts, false);
+}
+
+// llvm_arm_extract_mrv_array_element - Helper function that helps extract
+// an array element from multiple return value.
+//
+// Here, SRC is returning multiple values. DEST's DESTFIELDNO field is an array.
+// Extract SRCFIELDNO's ELEMENO value and store it in DEST's FIELDNO field's
+// ELEMENTNO.
+//
+static void llvm_arm_extract_mrv_array_element(Value *Src, Value *Dest,
+ unsigned SrcFieldNo,
+ unsigned SrcElemNo,
+ unsigned DestFieldNo,
+ unsigned DestElemNo,
+ LLVMBuilder &Builder,
+ bool isVolatile) {
+ Value *EVI = Builder.CreateExtractValue(Src, SrcFieldNo, "mrv_gr");
+ const StructType *STy = cast<StructType>(Src->getType());
+ llvm::Value *Idxs[3];
+ Idxs[0] = ConstantInt::get(llvm::Type::getInt32Ty(Context), 0);
+ Idxs[1] = ConstantInt::get(llvm::Type::getInt32Ty(Context), DestFieldNo);
+ Idxs[2] = ConstantInt::get(llvm::Type::getInt32Ty(Context), DestElemNo);
+ Value *GEP = Builder.CreateGEP(Dest, Idxs, Idxs+3, "mrv_gep");
+ if (isa<VectorType>(STy->getElementType(SrcFieldNo))) {
+ Value *ElemIndex = ConstantInt::get(Type::getInt32Ty(Context), SrcElemNo);
+ Value *EVIElem = Builder.CreateExtractElement(EVI, ElemIndex, "mrv");
+ Builder.CreateStore(EVIElem, GEP, isVolatile);
+ } else {
+ Builder.CreateStore(EVI, GEP, isVolatile);
+ }
+}
+
+// llvm_arm_extract_multiple_return_value - Extract multiple values returned
+// by SRC and store them in DEST. It is expected that SRC and
+// DEST types are StructType, but they may not match.
+void llvm_arm_extract_multiple_return_value(Value *Src, Value *Dest,
+ bool isVolatile,
+ LLVMBuilder &Builder) {
+
+ const StructType *STy = cast<StructType>(Src->getType());
+ unsigned NumElements = STy->getNumElements();
+
+ const PointerType *PTy = cast<PointerType>(Dest->getType());
+ const StructType *DestTy = cast<StructType>(PTy->getElementType());
+
+ unsigned SNO = 0;
+ unsigned DNO = 0;
+
+ while (SNO < NumElements) {
+
+ const Type *DestElemType = DestTy->getElementType(DNO);
+
+ // Directly access first class values.
+ if (DestElemType->isSingleValueType()) {
+ Value *GEP = Builder.CreateStructGEP(Dest, DNO, "mrv_gep");
+ Value *EVI = Builder.CreateExtractValue(Src, SNO, "mrv_gr");
+ Builder.CreateStore(EVI, GEP, isVolatile);
+ ++DNO; ++SNO;
+ continue;
+ }
+
+ // Access array elements individually. Note, Src and Dest type may
+ // not match. For example { <2 x float>, float } and { float[3]; }
+ const ArrayType *ATy = cast<ArrayType>(DestElemType);
+ unsigned ArraySize = ATy->getNumElements();
+ unsigned DElemNo = 0; // DestTy's DNO field's element number
+ while (DElemNo < ArraySize) {
+ unsigned i = 0;
+ unsigned Size = 1;
+
+ if (const VectorType *SElemTy =
+ dyn_cast<VectorType>(STy->getElementType(SNO))) {
+ Size = SElemTy->getNumElements();
+ }
+ while (i < Size) {
+ llvm_arm_extract_mrv_array_element(Src, Dest, SNO, i++,
+ DNO, DElemNo++,
+ Builder, isVolatile);
+ }
+ // Consumed this src field. Try next one.
+ ++SNO;
+ }
+ // Finished building current dest field.
+ ++DNO;
+ }
+}
+
+// Target hook for llvm-abi.h for LLVM_SHOULD_NOT_USE_SHADOW_RETURN and is
+// also a utility function used for other target hooks in this file. Returns
+// true if the aggregate should be passed or returned in registers.
+bool llvm_arm_should_pass_or_return_aggregate_in_regs(tree TreeType,
+ CallingConv::ID &CC) {
+ // Homogeneous aggregates are an AAPCS-VFP feature.
+ if ((CC != CallingConv::ARM_AAPCS_VFP) ||
+ !(TARGET_AAPCS_BASED && TARGET_VFP && TARGET_HARD_FLOAT_ABI))
+ return false;
+
+ // Alas, we can't use LLVM Types to figure this out because we need to
+ // examine unions closely. We'll have to walk the GCC TreeType.
+ int fdt_counts[ARM_FDT_MAX] = { 0 };
+ bool result = false;
+ result = vfp_arg_homogeneous_aggregate_p(TYPE_MODE(TreeType), TreeType,
+ fdt_counts);
+ return result;
+}
+
/* LLVM LOCAL end (ENTIRE FILE!) */
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=85539&r1=85538&r2=85539&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 Thu Oct 29 18:35:11 2009
@@ -139,7 +139,7 @@
/* LLVM_AGGR_TYPE_FOR_STRUCT_RETURN - Return LLVM Type if X can be
returned as an aggregate, otherwise return NULL. */
-#define LLVM_AGGR_TYPE_FOR_STRUCT_RETURN(X) \
+#define LLVM_AGGR_TYPE_FOR_STRUCT_RETURN(X, CC) \
llvm_x86_aggr_type_for_struct_return(X)
extern void llvm_x86_extract_multiple_return_value(Value *Src, Value *Dest,
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=85539&r1=85538&r2=85539&view=diff
==============================================================================
--- llvm-gcc-4.2/trunk/gcc/llvm-abi.h (original)
+++ llvm-gcc-4.2/trunk/gcc/llvm-abi.h Thu Oct 29 18:35:11 2009
@@ -126,15 +126,24 @@
false
#endif
+// LLVM_SHOULD_NOT_USE_SHADOW_RETURN - A hook to allow aggregates to be
+// returned in registers.
+#ifndef LLVM_SHOULD_NOT_USE_SHADOW_RETURN
+#define LLVM_SHOULD_NOT_USE_SHADOW_RETURN(X, CC) \
+ false
+#endif
+
// doNotUseShadowReturn - Return true if the specified GCC type
// should not be returned using a pointer to struct parameter.
-static inline bool doNotUseShadowReturn(tree type, tree fndecl) {
+static inline bool doNotUseShadowReturn(tree type, tree fndecl,
+ CallingConv::ID CC) {
if (!TYPE_SIZE(type))
return false;
if (TREE_CODE(TYPE_SIZE(type)) != INTEGER_CST)
return false;
// LLVM says do not use shadow argument.
- if (LLVM_SHOULD_NOT_RETURN_COMPLEX_IN_MEMORY(type))
+ if (LLVM_SHOULD_NOT_RETURN_COMPLEX_IN_MEMORY(type) ||
+ LLVM_SHOULD_NOT_USE_SHADOW_RETURN(type, CC))
return true;
// GCC says use shadow argument.
if (aggregate_value_p(type, fndecl))
@@ -396,7 +405,7 @@
} else if (Ty->isSingleValueType() || Ty->isVoidTy()) {
// Return scalar values normally.
C.HandleScalarResult(Ty);
- } else if (doNotUseShadowReturn(type, fn)) {
+ } else if (doNotUseShadowReturn(type, fn, C.getCallingConv())) {
tree SingleElt = LLVM_SHOULD_RETURN_SELT_STRUCT_AS_SCALAR(type);
if (SingleElt && TYPE_SIZE(SingleElt) &&
TREE_CODE(TYPE_SIZE(SingleElt)) == INTEGER_CST &&
@@ -406,7 +415,8 @@
} else {
// Otherwise return as an integer value large enough to hold the entire
// aggregate.
- if (const Type *AggrTy = LLVM_AGGR_TYPE_FOR_STRUCT_RETURN(type))
+ if (const Type *AggrTy = LLVM_AGGR_TYPE_FOR_STRUCT_RETURN(type,
+ C.getCallingConv()))
C.HandleAggregateResultAsAggregate(AggrTy);
else if (const Type* ScalarTy =
LLVM_SCALAR_TYPE_FOR_STRUCT_RETURN(type, &Offset))
@@ -752,7 +762,7 @@
} else if (Ty->isSingleValueType() || Ty->isVoidTy()) {
// Return scalar values normally.
C.HandleScalarResult(Ty);
- } else if (doNotUseShadowReturn(type, fn)) {
+ } else if (doNotUseShadowReturn(type, fn, C.getCallingConv())) {
tree SingleElt = LLVM_SHOULD_RETURN_SELT_STRUCT_AS_SCALAR(type);
if (SingleElt && TYPE_SIZE(SingleElt) &&
TREE_CODE(TYPE_SIZE(SingleElt)) == INTEGER_CST &&
@@ -762,7 +772,8 @@
} else {
// Otherwise return as an integer value large enough to hold the entire
// aggregate.
- if (const Type *AggrTy = LLVM_AGGR_TYPE_FOR_STRUCT_RETURN(type))
+ if (const Type *AggrTy = LLVM_AGGR_TYPE_FOR_STRUCT_RETURN(type,
+ C.getCallingConv()))
C.HandleAggregateResultAsAggregate(AggrTy);
else if (const Type* ScalarTy =
LLVM_SCALAR_TYPE_FOR_STRUCT_RETURN(type, &Offset))
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=85539&r1=85538&r2=85539&view=diff
==============================================================================
--- llvm-gcc-4.2/trunk/gcc/llvm-types.cpp (original)
+++ llvm-gcc-4.2/trunk/gcc/llvm-types.cpp Thu Oct 29 18:35:11 2009
@@ -1052,16 +1052,16 @@
tree ReturnType = TREE_TYPE(type);
std::vector<PATypeHolder> ArgTys;
PATypeHolder RetTy(Type::getVoidTy(Context));
-
+
FunctionTypeConversion Client(RetTy, ArgTys, CallingConv, true /*K&R*/);
TheLLVMABI<FunctionTypeConversion> ABIConverter(Client);
-
- // Builtins are always prototyped, so this isn't one.
- ABIConverter.HandleReturnType(ReturnType, current_function_decl, false);
#ifdef TARGET_ADJUST_LLVM_CC
- TARGET_ADJUST_LLVM_CC(CallingConv, type);
+ TARGET_ADJUST_LLVM_CC(CallingConv, type);
#endif
+
+ // Builtins are always prototyped, so this isn't one.
+ ABIConverter.HandleReturnType(ReturnType, current_function_decl, false);
SmallVector<AttributeWithIndex, 8> Attrs;
@@ -1118,15 +1118,15 @@
bool isVarArg = false;
FunctionTypeConversion Client(RetTy, ArgTypes, CallingConv, false/*not K&R*/);
TheLLVMABI<FunctionTypeConversion> ABIConverter(Client);
-
- ABIConverter.HandleReturnType(TREE_TYPE(type), current_function_decl,
- decl ? DECL_BUILT_IN(decl) : false);
-
+
// Allow the target to set the CC for things like fastcall etc.
#ifdef TARGET_ADJUST_LLVM_CC
TARGET_ADJUST_LLVM_CC(CallingConv, type);
#endif
+ ABIConverter.HandleReturnType(TREE_TYPE(type), current_function_decl,
+ decl ? DECL_BUILT_IN(decl) : false);
+
// Compute attributes for return type (and function attributes).
SmallVector<AttributeWithIndex, 8> Attrs;
Attributes FnAttributes = Attribute::None;
More information about the llvm-commits
mailing list