[llvm-commits] [llvm-gcc-4.2] r49680 - in /llvm-gcc-4.2/trunk/gcc/config/i386: llvm-i386-target.h llvm-i386.cpp
Devang Patel
dpatel at apple.com
Mon Apr 14 13:16:36 PDT 2008
Author: dpatel
Date: Mon Apr 14 15:16:21 2008
New Revision: 49680
URL: http://llvm.org/viewvc/llvm-project?rev=49680&view=rev
Log:
Begin adding support for multiple value returns.
This work is not yet complete and it is disabled right now.
Modified:
llvm-gcc-4.2/trunk/gcc/config/i386/llvm-i386-target.h
llvm-gcc-4.2/trunk/gcc/config/i386/llvm-i386.cpp
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=49680&r1=49679&r2=49680&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 Mon Apr 14 15:16:21 2008
@@ -114,6 +114,24 @@
extern const Type *llvm_x86_aggr_type_for_struct_return(const Type *Ty);
+/* LLVM_BUILD_MULTIPLE_RETURN_VALUE - Build multiple return values
+ for the function FN and add them in RETVALS. */
+#define LLVM_BUILD_MULTIPLE_RETURN_VALUE(Fn,R,RetVals,B) \
+ llvm_x86_build_multiple_return_value((Fn),(R),(RetVals),(B))
+
+extern void llvm_x86_build_multiple_return_value(Function *, Value *,
+ SmallVectorImpl <Value *> &,
+ IRBuilder &);
+
+/* 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_x86_extract_multiple_return_value((Src),(Dest),(V),(B))
+
+extern void llvm_x86_extract_multiple_return_value(Value *Src, Value *Dest,
+ bool isVolatile,
+ IRBuilder &B);
+
/* Vectors which are not MMX nor SSE should be passed as integers. */
#define LLVM_SHOULD_PASS_VECTOR_IN_INTEGER_REGS(X) \
llvm_x86_should_pass_vector_in_integer_regs((X))
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=49680&r1=49679&r2=49680&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 Mon Apr 14 15:16:21 2008
@@ -895,8 +895,46 @@
return false;
}
-// Return LLVM Type if TY can be returned as a scalar, otherwise return NULL.
+// llvm_suitable_multiple_ret_value_type - Return TRUE if return value
+// of type TY should be returned using multiple value return instruction.
+static bool llvm_suitable_multiple_ret_value_type(const Type *Ty) {
+
+ //NOTE: Work in progress. Do not open the flood gate yet.
+ return false;
+
+ if (!TARGET_64BIT)
+ return false;
+
+ const StructType *STy = dyn_cast<StructType>(Ty);
+ if (!STy)
+ return false;
+
+ unsigned NumElements = STy->getNumElements();
+
+ bool useMultipleReturnVals = true;
+ for (unsigned i = 0; i < NumElements; ++i) {
+ const Type *T = STy->getElementType(i);
+
+ if (T->isFirstClassType())
+ continue;
+
+ if (const ArrayType *ATy = dyn_cast<ArrayType>(T)) {
+ // Allow { float f[4]; } but block { float f[10]; } or { char c[4]; }
+ // FIXME :Double check '5'.
+ if (ATy->getElementType()->isFloatingPoint()
+ && ATy->getNumElements() < 5)
+ continue;
+ }
+ return false;
+ }
+
+ return true;
+}
+
+// llvm_x86_scalar_type_for_struct_return - Return LLVM type if TY
+// can be returned as a scalar, otherwise return NULL.
const Type *llvm_x86_scalar_type_for_struct_return(const Type *Ty) {
+
unsigned Size = getTargetData().getABITypeSize(Ty);
if (Size == 0)
return Type::VoidTy;
@@ -906,7 +944,12 @@
return Type::Int16Ty;
else if (Size <= 4)
return Type::Int32Ty;
- else if (Size <= 8)
+
+ // Check if Ty should be returned using multiple value return instruction.
+ if (llvm_suitable_multiple_ret_value_type(Ty))
+ return NULL;
+
+ if (Size <= 8)
return Type::Int64Ty;
else if (Size <= 16)
return IntegerType::get(128);
@@ -918,8 +961,211 @@
// Return LLVM Type if TY can be returned as an aggregate, otherwise return NULL.
const Type *llvm_x86_aggr_type_for_struct_return(const Type *Ty) {
- return NULL;
+
+ if (!llvm_suitable_multiple_ret_value_type(Ty))
+ return NULL;
+
+ const StructType *STy = cast<StructType>(Ty);
+ unsigned NumElements = STy->getNumElements();
+
+ std::vector<const Type *> ElementTypes;
+ for (unsigned i = 0; i < NumElements; ++i) {
+ const Type *T = STy->getElementType(i);
+
+ if (T->isFirstClassType()) {
+ ElementTypes.push_back(T);
+ continue;
+ }
+
+ const ArrayType *ATy = dyn_cast<ArrayType>(T);
+ assert (ATy && "Unexpected struct element type!");
+ assert (ATy->getElementType()->isFirstClassType()
+ && "Unexpected ArrayType element type!");
+
+ unsigned size = ATy->getNumElements();
+ if (ATy->getElementType()->isFloatingPoint()) {
+ switch (size) {
+ case 2:
+ // use { <2 x float> } for struct { float[2]; }
+ ElementTypes.push_back(VectorType::get(ATy->getElementType(), 2));
+ break;
+ case 3:
+ // use { <2 x float>, float } for struct { float[3]; }
+ ElementTypes.push_back(VectorType::get(ATy->getElementType(), 2));
+ ElementTypes.push_back(ATy->getElementType());
+ break;
+ case 4:
+ // use { <4 x float> } for struct { float[4]; }
+ ElementTypes.push_back(VectorType::get(ATy->getElementType(), 4));
+ break;
+ default:
+ assert (0 && "Unexpected floating point array size!");
+ }
+ } else {
+ for (unsigned j = 0; j < size; ++j)
+ ElementTypes.push_back(ATy->getElementType());
+ }
+ }
+
+ return StructType::get(ElementTypes, STy->isPacked());
}
+// llvm_x86_build_mrv_array_element - This is a helper function used by
+// llvm_x6_build_multiple_return_value. This function builds a vector
+// from the array fields of RetVal.
+static Value *llvm_x86_build_mrv_array_element(const Type *STyFieldTy,
+ Value *RetVal,
+ unsigned FieldNo,
+ unsigned ArraySize,
+ IRBuilder &Builder) {
+ llvm::Value *Idxs[3];
+ Idxs[0] = ConstantInt::get(llvm::Type::Int32Ty, 0);
+ Idxs[1] = ConstantInt::get(llvm::Type::Int32Ty, FieldNo);
+
+ Value *R1 = UndefValue::get(STyFieldTy);
+
+ for (unsigned i = 0; i < ArraySize; ++i) {
+ Idxs[2] = ConstantInt::get(llvm::Type::Int32Ty, i);
+ Value *GEP = Builder.CreateGEP(RetVal, Idxs, Idxs+3, "mrv_gep");
+ Value *ElemVal = Builder.CreateLoad(GEP, "mrv");
+ R1 = Builder.CreateInsertElement(R1, ElemVal,
+ ConstantInt::get(llvm::Type::Int32Ty, i),
+ "mrv");
+ }
+ return R1;
+}
+
+// llvm_x86_build_multiple_return_value - Function FN returns multiple value
+// where RETVAL points to the aggregate being returned. Build a RETVALS vector
+// of individual values from RETVAL aggregate. RETVALS will be used by
+// the client to build multiple value return instruction.
+void llvm_x86_build_multiple_return_value(Function *Fn, Value *RetVal,
+ SmallVectorImpl <Value *> &RetVals,
+ IRBuilder &Builder) {
+ const StructType *STy = cast<StructType>(Fn->getReturnType());
+ const PointerType *PTy = cast<PointerType>(RetVal->getType());
+ const StructType *RetSTy = cast<StructType>(PTy->getElementType());
+
+ // Walk RetSTy elements and populate RetVals vector. Note, STy and RetSTy
+ // may not match. For example, when STy is { <2 x float> } the RetSTy is
+ // { float[2]; }
+ unsigned NumElements = RetSTy->getNumElements();
+ for (unsigned RNO = 0, SNO = 0; RNO < NumElements; ++RNO, ++SNO) {
+ const Type *ElemType = RetSTy->getElementType(RNO);
+ if (ElemType->isFirstClassType()) {
+ Value *GEP = Builder.CreateStructGEP(RetVal, RNO, "mrv_idx");
+ Value *ElemVal = Builder.CreateLoad(GEP, "mrv");
+ RetVals.push_back(ElemVal);
+ } else {
+ const ArrayType *ATy = cast<ArrayType>(ElemType);
+ unsigned ArraySize = ATy->getNumElements();
+ const VectorType *SElemTy = cast<VectorType>(STy->getElementType(SNO));
+ unsigned Size = SElemTy->getNumElements();
+ assert (ArraySize >= Size && "Invalid multiple return value type!");
+ Value *R = llvm_x86_build_mrv_array_element(SElemTy, RetVal, RNO,
+ Size, Builder);
+ RetVals.push_back(R);
+ if (ArraySize > Size) {
+ assert (ArraySize == Size + 1 && "Unable to build multiple return value!");
+ // Build remaining values.
+ const Type *NextTy = STy->getElementType(SNO + 1);
+ if (NextTy->getTypeID() == Type::FloatTyID) {
+ Value *Idxs[3];
+ Idxs[0] = ConstantInt::get(llvm::Type::Int32Ty, 0);
+ Idxs[1] = ConstantInt::get(llvm::Type::Int32Ty, RNO);
+ Idxs[2] = ConstantInt::get(llvm::Type::Int32Ty, Size + 1);
+ Value *GEP3 = Builder.CreateGEP(RetVal, Idxs, Idxs+3, "mrv_gep");
+ Value *ElemVal3 = Builder.CreateLoad(GEP3, "mrv");
+ RetVals.push_back(ElemVal3);
+ SNO++;
+ } else
+ assert ( 0 && "Unable to build multiple return value!");
+ }
+ }
+ }
+}
+
+// llvm_x86_extract_mrv_array_element - Helper function that help extract
+// an array element from multiple return value.
+//
+// Here, SRC is returning multiple values. DEST's DESTFIELNO field is an array.
+// Extract SRCFIELDNO's ELEMENO value and store it in DEST's FIELDNO field's
+// ELEMENTNO.
+//
+static void llvm_x86_extract_mrv_array_element(Value *Src, Value *Dest,
+ unsigned SrcFieldNo,
+ unsigned SrcElemNo,
+ unsigned DestFieldNo,
+ unsigned DestElemNo,
+ IRBuilder &Builder,
+ bool isVolatile) {
+ GetResultInst *GR = Builder.CreateGetResult(Src, SrcFieldNo, "mrv_gr");
+ const StructType *STy = cast<StructType>(Src->getType());
+ llvm::Value *Idxs[3];
+ Idxs[0] = ConstantInt::get(llvm::Type::Int32Ty, 0);
+ Idxs[1] = ConstantInt::get(llvm::Type::Int32Ty, DestFieldNo);
+ Idxs[2] = ConstantInt::get(llvm::Type::Int32Ty, DestElemNo);
+ Value *GEP = Builder.CreateGEP(Dest, Idxs, Idxs+3, "mrv_gep");
+ if (isa<VectorType>(STy->getElementType(SrcFieldNo))) {
+ Value *ElemIndex = ConstantInt::get(Type::Int32Ty, SrcElemNo);
+ Value *GRElem = Builder.CreateExtractElement(GR, ElemIndex, "mrv");
+ Builder.CreateStore(GRElem, GEP, isVolatile);
+ } else {
+ Builder.CreateStore(GR, GEP, isVolatile);
+ }
+}
+
+// llvm_x86_extract_multiple_return_value - Extract multiple values returned
+// by SRC and store them in DEST. It is expected thaty SRC and
+// DEST types are StructType, but they may not match.
+void llvm_x86_extract_multiple_return_value(Value *Src, Value *Dest,
+ bool isVolatile,
+ IRBuilder &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 using getresult.
+ if (DestElemType->isFirstClassType()) {
+ Value *GEP = Builder.CreateStructGEP(Dest, DNO, "mrv_gep");
+ GetResultInst *GR = Builder.CreateGetResult(Src, SNO, "mrv_gr");
+ Builder.CreateStore(GR, 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();
+ for (unsigned di = 0, si = 0; di < ArraySize; ++di, ++si) {
+ llvm_x86_extract_mrv_array_element(Src, Dest, SNO, si, DNO, di,
+ Builder, isVolatile);
+ if (const VectorType *SElemTy =
+ dyn_cast<VectorType>(STy->getElementType(SNO))) {
+ unsigned NumVElem = SElemTy->getNumElements();
+ if (NumVElem == si + 1) {
+ // If extracted all elments from current Src field then
+ // move to next field.
+ si = 0;
+ ++SNO;
+ }
+ } else {
+ // Copied content from current source field, so move to next field.
+ ++SNO;
+ }
+ }
+ // Process next DNO element.
+ ++DNO;
+ }
+}
/* LLVM LOCAL end (ENTIRE FILE!) */
More information about the llvm-commits
mailing list