[llvm-commits] [llvm-gcc-4.2] r48608 - in /llvm-gcc-4.2/trunk/gcc: config/i386/llvm-i386-target.h config/i386/llvm-i386.cpp config/rs6000/llvm-rs6000.cpp config/rs6000/rs6000.h llvm-abi.h llvm-convert.cpp
Duncan Sands
baldrick at free.fr
Mon Mar 31 09:08:50 PDT 2008
> Hi Dale, I've cleaned up the return value part
> in commit 48778. Can you please check that it
> works properly for you. I haven't yet decided
> the best way of handling the argument case.
This is what I'm testing for the call argument case.
It seems to work! I did some additional small cleanups
in the same code area while there. It does introduce
a slow-down in the common case: scalars are always
stored to a temporary and later loaded out (if not
passed in integer registers). It would be easy to
eliminate this, though it's not clear to me if it
really matters.
Duncan.
Index: gcc-4.2.llvm/gcc/llvm-convert.cpp
===================================================================
--- gcc-4.2.llvm.orig/gcc/llvm-convert.cpp 2008-03-29 00:15:38.000000000 +0100
+++ gcc-4.2.llvm/gcc/llvm-convert.cpp 2008-03-31 18:02:31.000000000 +0200
@@ -2282,44 +2282,26 @@
/// definition for this target to figure out how to pass arguments into the
/// stack/regs for a function call.
struct FunctionCallArgumentConversion : public DefaultABIClient {
- tree CallExpression;
SmallVector<Value*, 16> &CallOperands;
- CallingConv::ID &CallingConvention;
- LLVMBuilder &Builder;
+ SmallVector<Value*, 2> LocStack;
+ const FunctionType *FTy;
const MemRef *DestLoc;
+ bool useReturnSlot;
+ LLVMBuilder &Builder;
MemRef RetBuf;
- std::vector<Value*> LocStack;
bool isShadowRet;
- FunctionCallArgumentConversion(tree exp, SmallVector<Value*, 16> &ops,
- CallingConv::ID &cc,
- LLVMBuilder &b, const MemRef *destloc)
- : CallExpression(exp), CallOperands(ops), CallingConvention(cc),
- Builder(b), DestLoc(destloc), isShadowRet(false) {
- CallingConvention = CallingConv::C;
-#ifdef TARGET_ADJUST_LLVM_CC
- tree ftype;
- if (tree fdecl = get_callee_fndecl(exp)) {
- ftype = TREE_TYPE(fdecl);
- } else {
- ftype = TREE_TYPE(TREE_OPERAND(exp,0));
+ FunctionCallArgumentConversion(SmallVector<Value*, 16> &ops,
+ const FunctionType *FnTy,
+ const MemRef *destloc,
+ bool ReturnSlotOpt,
+ LLVMBuilder &b)
+ : CallOperands(ops), FTy(FnTy), DestLoc(destloc),
+ useReturnSlot(ReturnSlotOpt), Builder(b), isShadowRet(false) { }
- // If it's call to pointer, we look for the function type.
- if (TREE_CODE(ftype) == POINTER_TYPE)
- ftype = TREE_TYPE(ftype);
- }
-
- TARGET_ADJUST_LLVM_CC(CallingConvention, ftype);
-#endif
- }
-
void setLocation(Value *Loc) {
LocStack.push_back(Loc);
}
- void clear() {
- assert(LocStack.size() == 1 && "Imbalance!");
- LocStack.clear();
- }
bool isShadowReturn() { return isShadowRet; }
@@ -2349,7 +2331,7 @@
assert(DestLoc == 0 &&
"Call returns a scalar but caller expects aggregate!");
}
-
+
/// HandleAggregateResultAsScalar - This callback is invoked if the function
/// returns an aggregate value by bit converting it to the specified scalar
/// type and returning that.
@@ -2371,7 +2353,7 @@
// The result is unused, but still needs to be stored somewhere.
Value *Buf = TheTreeToLLVM->CreateTemporary(PtrArgTy->getElementType());
CallOperands.push_back(Buf);
- } else if (CALL_EXPR_RETURN_SLOT_OPT(CallExpression)) {
+ } else if (useReturnSlot) {
// Letting the call write directly to the final destination is safe and
// may be required. Do not use a buffer.
CallOperands.push_back(DestLoc->Ptr);
@@ -2387,6 +2369,10 @@
isShadowRet = true;
}
+ /// HandleScalarShadowArgument - This callback is invoked if the function
+ /// returns a scalar value by using a "shadow" first parameter, which is a
+ /// pointer to the scalar, of type PtrArgTy. If RetPtr is set to true,
+ /// the pointer argument itself is returned from the function.
void HandleScalarShadowArgument(const PointerType *PtrArgTy, bool RetPtr) {
assert(DestLoc == 0 &&
"Call returns a scalar but caller expects aggregate!");
@@ -2399,16 +2385,38 @@
isShadowRet = true;
}
+ /// HandleScalarArgument - This is the primary callback that specifies an
+ /// LLVM argument to pass. It is only used for first class types.
void HandleScalarArgument(const llvm::Type *LLVMTy, tree type) {
assert(!LocStack.empty());
Value *Loc = LocStack.back();
- if (cast<PointerType>(Loc->getType())->getElementType() != LLVMTy)
- // This always deals with pointer types so BitCast is appropriate
- Loc = Builder.CreateBitCast(Loc, PointerType::getUnqual(LLVMTy), "tmp");
-
- CallOperands.push_back(Builder.CreateLoad(Loc, "tmp"));
+ if (Loc->getType() != PointerType::getUnqual(LLVMTy))
+ Loc = Builder.CreateBitCast(Loc, PointerType::getUnqual(LLVMTy));
+
+ // Load the scalar value and perform any implicit type conversions.
+ Loc = Builder.CreateLoad(Loc, "tmp");
+ if (CallOperands.size() < FTy->getNumParams()) {
+ const Type *CalledTy = FTy->getParamType(CallOperands.size());
+ if (Loc->getType() != CalledTy) {
+ assert(type && "Inconsistent parameter types?");
+ bool isSigned = !TYPE_UNSIGNED(type);
+ Loc = TheTreeToLLVM->CastToAnyType(Loc, isSigned, CalledTy, false);
+ }
+ }
+
+ CallOperands.push_back(Loc);
}
-
+
+ /// HandleByInvisibleReferenceArgument - This callback is invoked if a pointer
+ /// (of type PtrTy) to the argument is passed rather than the argument itself.
+ void HandleByInvisibleReferenceArgument(const llvm::Type *PtrTy, tree type){
+ assert(!LocStack.empty());
+ Value *Loc = LocStack.back();
+ if (Loc->getType() != PtrTy)
+ Loc = Builder.CreateBitCast(Loc, PtrTy);
+ CallOperands.push_back(Loc);
+ }
+
/// HandleByValArgument - This callback is invoked if the aggregate function
/// argument is passed by value. It is lowered to a parameter passed by
/// reference with an additional parameter attribute "ByVal".
@@ -2419,16 +2427,17 @@
CallOperands.push_back(Loc);
}
+ /// EnterField - Called when we're about the enter the field of a struct
+ /// or union. FieldNo is the number of the element we are entering in the
+ /// LLVM Struct, StructTy is the LLVM type of the struct we are entering.
void EnterField(unsigned FieldNo, const llvm::Type *StructTy) {
Value *Loc = LocStack.back();
- if (cast<PointerType>(Loc->getType())->getElementType() != StructTy)
- // This always deals with pointer types so BitCast is appropriate
- Loc = Builder.CreateBitCast(Loc, PointerType::getUnqual(StructTy),
- "tmp");
-
- LocStack.push_back(Builder.CreateStructGEP(Loc, FieldNo, "tmp"));
+ if (Loc->getType() != PointerType::getUnqual(StructTy))
+ Loc = Builder.CreateBitCast(Loc, PointerType::getUnqual(StructTy));
+ LocStack.push_back(Builder.CreateStructGEP(Loc, FieldNo, "field"));
}
void ExitField() {
+ assert(!LocStack.empty());
LocStack.pop_back();
}
};
@@ -2445,6 +2454,7 @@
if (PAL.isEmpty() && isa<Function>(Callee))
PAL = cast<Function>(Callee)->getParamAttrs();
+ // Work out whether to use an invoke or an ordinary call.
if (!tree_could_throw_p(exp))
// This call does not throw - mark it 'nounwind'.
PAL = PAL.addAttr(0, ParamAttr::NoUnwind);
@@ -2474,15 +2484,26 @@
}
}
+ tree fndecl = get_callee_fndecl(exp);
+ tree fntype = fndecl ?
+ TREE_TYPE(fndecl) : TREE_TYPE (TREE_TYPE(TREE_OPERAND (exp, 0)));
+
+ // Determine the calling convention.
+ CallingConv::ID CallingConvention = CallingConv::C;
+#ifdef TARGET_ADJUST_LLVM_CC
+ TARGET_ADJUST_LLVM_CC(CallingConvention, fntype);
+#endif
+
SmallVector<Value*, 16> CallOperands;
- CallingConv::ID CallingConvention;
- FunctionCallArgumentConversion Client(exp, CallOperands, CallingConvention,
- Builder, DestLoc);
+ const PointerType *PFTy = cast<PointerType>(Callee->getType());
+ const FunctionType *FTy = cast<FunctionType>(PFTy->getElementType());
+ FunctionCallArgumentConversion Client(CallOperands, FTy, DestLoc,
+ CALL_EXPR_RETURN_SLOT_OPT(exp),
+ Builder);
TheLLVMABI<FunctionCallArgumentConversion> ABIConverter(Client);
// Handle the result, including struct returns.
- tree fndecl = get_callee_fndecl(exp);
- ABIConverter.HandleReturnType(TREE_TYPE(exp),
+ ABIConverter.HandleReturnType(TREE_TYPE(exp),
fndecl ? DECL_BUILT_IN(fndecl) : false);
// Pass the static chain, if any, as the first parameter.
@@ -2490,52 +2511,27 @@
CallOperands.push_back(Emit(TREE_OPERAND(exp, 2), 0));
// Loop over the arguments, expanding them and adding them to the op list.
- const PointerType *PFTy = cast<PointerType>(Callee->getType());
- const FunctionType *FTy = cast<FunctionType>(PFTy->getElementType());
for (tree arg = TREE_OPERAND(exp, 1); arg; arg = TREE_CHAIN(arg)) {
- const Type *ActualArgTy = ConvertType(TREE_TYPE(TREE_VALUE(arg)));
- const Type *ArgTy = ActualArgTy;
- if (CallOperands.size() < FTy->getNumParams())
- ArgTy = FTy->getParamType(CallOperands.size());
-
- // If we are implicitly passing the address of this argument instead of
- // passing it by value, handle this first.
- if (isPassedByInvisibleReference(TREE_TYPE(TREE_VALUE(arg)))) {
- // Get the address of the parameter passed in.
- LValue ArgVal = EmitLV(TREE_VALUE(arg));
- assert(!ArgVal.isBitfield() && "Bitfields shouldn't be invisible refs!");
- Value *Ptr = ArgVal.Ptr;
-
- if (CallOperands.size() >= FTy->getNumParams())
- ArgTy = PointerType::getUnqual(ArgTy);
- CallOperands.push_back(BitCastToType(Ptr, ArgTy));
- } else if (ActualArgTy->isFirstClassType()) {
+ const Type *ArgTy = ConvertType(TREE_TYPE(TREE_VALUE(arg)));
+
+ // Push the address of the argument.
+ if (ArgTy->isFirstClassType()) {
+ // Store to a temporary, and use the temporary's address.
Value *V = Emit(TREE_VALUE(arg), 0);
- if (TREE_CODE(TREE_TYPE(TREE_VALUE(arg)))==VECTOR_TYPE &&
- LLVM_SHOULD_PASS_VECTOR_IN_INTEGER_REGS(TREE_TYPE(TREE_VALUE(arg)))) {
- // Passed as integer registers. We need a stack object, not a value.
- MemRef NewLoc = CreateTempLoc(ConvertType(TREE_TYPE(TREE_VALUE(arg))));
- StoreInst *St = Builder.CreateStore(V, NewLoc.Ptr, false);
- Client.setLocation(NewLoc.Ptr);
- ParameterAttributes Attributes = ParamAttr::None;
- ABIConverter.HandleArgument(TREE_TYPE(TREE_VALUE(arg)), &Attributes);
- if (Attributes != ParamAttr::None)
- PAL = PAL.addAttr(CallOperands.size(), Attributes);
- } else {
- bool isSigned = !TYPE_UNSIGNED(TREE_TYPE(TREE_VALUE(arg)));
- CallOperands.push_back(CastToAnyType(V, isSigned, ArgTy, false));
- }
+ Value *Tmp = CreateTemporary(ArgTy);
+ Builder.CreateStore(V, Tmp);
+ Client.setLocation(Tmp);
} else {
- // If this is an aggregate value passed by-value, use the current ABI to
- // determine how the parameters are passed.
- LValue LV = EmitLV(TREE_VALUE(arg));
- assert(!LV.isBitfield() && "Bitfields are first-class types!");
- Client.setLocation(LV.Ptr);
- ParameterAttributes Attributes = ParamAttr::None;
- ABIConverter.HandleArgument(TREE_TYPE(TREE_VALUE(arg)), &Attributes);
- if (Attributes != ParamAttr::None)
- PAL = PAL.addAttr(CallOperands.size(), Attributes);
+ // An aggregate - get the address directly.
+ LValue ArgVal = EmitLV(TREE_VALUE(arg));
+ assert(!ArgVal.isBitfield() && "Bitfields are first-class types!");
+ Client.setLocation(ArgVal.Ptr);
}
+
+ ParameterAttributes Attributes = ParamAttr::None;
+ ABIConverter.HandleArgument(TREE_TYPE(TREE_VALUE(arg)), &Attributes);
+ if (Attributes != ParamAttr::None)
+ PAL = PAL.addAttr(CallOperands.size(), Attributes);
}
// Compile stuff like:
Index: gcc-4.2.llvm/gcc/llvm-abi.h
===================================================================
--- gcc-4.2.llvm.orig/gcc/llvm-abi.h 2008-03-29 00:15:38.000000000 +0100
+++ gcc-4.2.llvm/gcc/llvm-abi.h 2008-03-29 00:49:28.000000000 +0100
@@ -73,9 +73,13 @@
void HandleScalarShadowArgument(const PointerType *PtrArgTy, bool RetPtr) {}
- /// HandleScalarArgument - This is the primary callback that specifies an LLVM
- /// argument to pass.
- void HandleScalarArgument(const llvm::Type *LLVMTy, tree argTreeType) {}
+ /// HandleScalarArgument - This is the primary callback that specifies an
+ /// LLVM argument to pass. It is only used for first class types.
+ void HandleScalarArgument(const llvm::Type *LLVMTy, tree type) {}
+
+ /// HandleByInvisibleReferenceArgument - This callback is invoked if a pointer
+ /// (of type PtrTy) to the argument is passed rather than the argument itself.
+ void HandleByInvisibleReferenceArgument(const llvm::Type *PtrTy, tree type) {}
/// HandleByValArgument - This callback is invoked if the aggregate function
/// argument is passed by value.
@@ -330,7 +334,7 @@
// not include variable sized fields here.
std::vector<const Type*> Elts;
if (isPassedByInvisibleReference(type)) { // variable size -> by-ref.
- C.HandleScalarArgument(PointerType::getUnqual(Ty), type);
+ C.HandleByInvisibleReferenceArgument(PointerType::getUnqual(Ty), type);
} else if (Ty->getTypeID()==Type::VectorTyID) {
if (LLVM_SHOULD_PASS_VECTOR_IN_INTEGER_REGS(type)) {
PassInIntegerRegisters(type, Ty);
Index: gcc-4.2.llvm/gcc/llvm-types.cpp
===================================================================
--- gcc-4.2.llvm.orig/gcc/llvm-types.cpp 2008-03-30 17:32:45.000000000 +0200
+++ gcc-4.2.llvm/gcc/llvm-types.cpp 2008-03-30 17:34:32.000000000 +0200
@@ -995,6 +995,12 @@
ArgTypes.push_back(LLVMTy);
}
+ /// HandleByInvisibleReferenceArgument - This callback is invoked if a pointer
+ /// (of type PtrTy) to the argument is passed rather than the argument itself.
+ void HandleByInvisibleReferenceArgument(const llvm::Type *PtrTy, tree type) {
+ ArgTypes.push_back(PtrTy);
+ }
+
/// HandleByValArgument - This callback is invoked if the aggregate function
/// argument is passed by value. It is lowered to a parameter passed by
/// reference with an additional parameter attribute "ByVal".
More information about the llvm-commits
mailing list