summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/llvm/CallingConv.h8
-rw-r--r--include/llvm/CodeGen/SelectionDAGNodes.h23
-rw-r--r--include/llvm/DerivedTypes.h8
-rw-r--r--include/llvm/Target/TargetLowering.h2
-rw-r--r--include/llvm/Transforms/IPO.h3
-rw-r--r--lib/AsmParser/Lexer.l3
-rw-r--r--lib/AsmParser/Lexer.l.cvs3
-rw-r--r--lib/AsmParser/llvmAsmParser.y12
-rw-r--r--lib/AsmParser/llvmAsmParser.y.cvs12
-rw-r--r--lib/CodeGen/SelectionDAG/LegalizeDAG.cpp6
-rw-r--r--lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp40
-rw-r--r--lib/Target/ARM/ARMISelLowering.cpp1
-rw-r--r--lib/Target/CBackend/CBackend.cpp28
-rw-r--r--lib/Target/PowerPC/PPCISelLowering.cpp6
-rw-r--r--lib/Target/X86/X86AsmPrinter.cpp4
-rw-r--r--lib/Target/X86/X86ISelLowering.cpp1096
-rw-r--r--lib/Target/X86/X86ISelLowering.h22
-rw-r--r--lib/Target/X86/X86Subtarget.cpp1
-rw-r--r--lib/Transforms/IPO/DeadArgumentElimination.cpp7
-rw-r--r--lib/Transforms/IPO/ExtractFunction.cpp29
-rw-r--r--lib/VMCore/AsmWriter.cpp3
-rw-r--r--lib/VMCore/Type.cpp4
-rw-r--r--lib/VMCore/Verifier.cpp10
-rw-r--r--tools/llvm-extract/llvm-extract.cpp9
24 files changed, 502 insertions, 838 deletions
diff --git a/include/llvm/CallingConv.h b/include/llvm/CallingConv.h
index e6ffd281e6..4bacb1d954 100644
--- a/include/llvm/CallingConv.h
+++ b/include/llvm/CallingConv.h
@@ -30,14 +30,6 @@ namespace CallingConv {
/// certain amounts of prototype mismatch.
C = 0,
- /// CSRet - C Struct Return calling convention. This convention requires
- /// that the function return void and take a pointer as the first argument
- /// of the struct. This is used by targets which need to distinguish
- /// between C functions returning a structure, and C functions taking a
- /// structure pointer as the first argument to the function.
- CSRet = 1,
-
-
// Generic LLVM calling conventions. None of these calling conventions
// support varargs calls, and all assume that the caller and callee
// prototype exactly match.
diff --git a/include/llvm/CodeGen/SelectionDAGNodes.h b/include/llvm/CodeGen/SelectionDAGNodes.h
index faa0e35da0..11c6ad6c53 100644
--- a/include/llvm/CodeGen/SelectionDAGNodes.h
+++ b/include/llvm/CodeGen/SelectionDAGNodes.h
@@ -133,20 +133,25 @@ namespace ISD {
// UNDEF - An undefined node
UNDEF,
- /// FORMAL_ARGUMENTS(CHAIN, CC#, ISVARARG) - This node represents the formal
- /// arguments for a function. CC# is a Constant value indicating the
- /// calling convention of the function, and ISVARARG is a flag that
- /// indicates whether the function is varargs or not. This node has one
- /// result value for each incoming argument, plus one for the output chain.
- /// It must be custom legalized.
+ /// FORMAL_ARGUMENTS(CHAIN, CC#, ISVARARG, FLAG0, ..., FLAGn) - This node
+ /// represents the formal arguments for a function. CC# is a Constant value
+ /// indicating the calling convention of the function, and ISVARARG is a
+ /// flag that indicates whether the function is varargs or not. This node
+ /// has one result value for each incoming argument, plus one for the output
+ /// chain. It must be custom legalized. See description of CALL node for
+ /// FLAG argument contents explanation.
///
FORMAL_ARGUMENTS,
/// RV1, RV2...RVn, CHAIN = CALL(CHAIN, CC#, ISVARARG, ISTAILCALL, CALLEE,
- /// ARG0, SIGN0, ARG1, SIGN1, ... ARGn, SIGNn)
+ /// ARG0, FLAG0, ARG1, FLAG1, ... ARGn, FLAGn)
/// This node represents a fully general function call, before the legalizer
- /// runs. This has one result value for each argument / signness pair, plus
- /// a chain result. It must be custom legalized.
+ /// runs. This has one result value for each argument / flag pair, plus
+ /// a chain result. It must be custom legalized. Flag argument indicates
+ /// misc. argument attributes. Currently:
+ /// Bit 0 - signness
+ /// Bit 1 - 'inreg' attribute
+ /// Bit 2 - 'sret' attribute
CALL,
// EXTRACT_ELEMENT - This is used to get the first or second (determined by
diff --git a/include/llvm/DerivedTypes.h b/include/llvm/DerivedTypes.h
index c1e3a98a04..06f3a98807 100644
--- a/include/llvm/DerivedTypes.h
+++ b/include/llvm/DerivedTypes.h
@@ -134,7 +134,9 @@ public:
NoAttributeSet = 0, ///< No attribute value has been set
ZExtAttribute = 1, ///< zero extended before/after call
SExtAttribute = 1 << 1, ///< sign extended before/after call
- NoReturnAttribute = 1 << 2 ///< mark the function as not returning
+ NoReturnAttribute = 1 << 2, ///< mark the function as not returning
+ InRegAttribute = 1 << 3, ///< force argument to be passed in register
+ StructRetAttribute= 1 << 4 ///< hidden pointer to structure to return
};
typedef std::vector<ParameterAttributes> ParamAttrsList;
private:
@@ -176,6 +178,10 @@ public:
///
unsigned getNumParams() const { return unsigned(ContainedTys.size()-1); }
+ bool isStructReturn() const {
+ return (getNumParams() && paramHasAttr(1, StructRetAttribute));
+ }
+
/// The parameter attributes for the \p ith parameter are returned. The 0th
/// parameter refers to the return type of the function.
/// @returns The ParameterAttributes for the \p ith parameter.
diff --git a/include/llvm/Target/TargetLowering.h b/include/llvm/Target/TargetLowering.h
index 34bc3ad7ee..49d6624f8e 100644
--- a/include/llvm/Target/TargetLowering.h
+++ b/include/llvm/Target/TargetLowering.h
@@ -730,6 +730,8 @@ public:
SDOperand Node;
const Type* Ty;
bool isSigned;
+ bool isInReg;
+ bool isSRet;
};
typedef std::vector<ArgListEntry> ArgListTy;
virtual std::pair<SDOperand, SDOperand>
diff --git a/include/llvm/Transforms/IPO.h b/include/llvm/Transforms/IPO.h
index 44ffa473e4..b24857e967 100644
--- a/include/llvm/Transforms/IPO.h
+++ b/include/llvm/Transforms/IPO.h
@@ -82,7 +82,8 @@ ModulePass *createGlobalDCEPass();
/// the specified function. Otherwise, it deletes as much of the module as
/// possible, except for the function specified.
///
-ModulePass *createFunctionExtractionPass(Function *F, bool deleteFn = false);
+ModulePass *createFunctionExtractionPass(Function *F, bool deleteFn = false,
+ bool relinkCallees = false);
//===----------------------------------------------------------------------===//
diff --git a/lib/AsmParser/Lexer.l b/lib/AsmParser/Lexer.l
index e688868802..96eedff5d5 100644
--- a/lib/AsmParser/Lexer.l
+++ b/lib/AsmParser/Lexer.l
@@ -227,7 +227,6 @@ sideeffect { return SIDEEFFECT; }
cc { return CC_TOK; }
ccc { return CCC_TOK; }
-csretcc { return CSRETCC_TOK; }
fastcc { return FASTCC_TOK; }
coldcc { return COLDCC_TOK; }
x86_stdcallcc { return X86_STDCALLCC_TOK; }
@@ -287,6 +286,8 @@ call { RET_TOK(OtherOpVal, Call, CALL); }
trunc { RET_TOK(CastOpVal, Trunc, TRUNC); }
zext { RET_TOK(CastOpVal, ZExt, ZEXT); }
sext { RET_TOK(CastOpVal, SExt, SEXT); }
+inreg { return INREG; }
+sret { return SRET; }
fptrunc { RET_TOK(CastOpVal, FPTrunc, FPTRUNC); }
fpext { RET_TOK(CastOpVal, FPExt, FPEXT); }
uitofp { RET_TOK(CastOpVal, UIToFP, UITOFP); }
diff --git a/lib/AsmParser/Lexer.l.cvs b/lib/AsmParser/Lexer.l.cvs
index e688868802..96eedff5d5 100644
--- a/lib/AsmParser/Lexer.l.cvs
+++ b/lib/AsmParser/Lexer.l.cvs
@@ -227,7 +227,6 @@ sideeffect { return SIDEEFFECT; }
cc { return CC_TOK; }
ccc { return CCC_TOK; }
-csretcc { return CSRETCC_TOK; }
fastcc { return FASTCC_TOK; }
coldcc { return COLDCC_TOK; }
x86_stdcallcc { return X86_STDCALLCC_TOK; }
@@ -287,6 +286,8 @@ call { RET_TOK(OtherOpVal, Call, CALL); }
trunc { RET_TOK(CastOpVal, Trunc, TRUNC); }
zext { RET_TOK(CastOpVal, ZExt, ZEXT); }
sext { RET_TOK(CastOpVal, SExt, SEXT); }
+inreg { return INREG; }
+sret { return SRET; }
fptrunc { RET_TOK(CastOpVal, FPTrunc, FPTRUNC); }
fpext { RET_TOK(CastOpVal, FPExt, FPEXT); }
uitofp { RET_TOK(CastOpVal, UIToFP, UITOFP); }
diff --git a/lib/AsmParser/llvmAsmParser.y b/lib/AsmParser/llvmAsmParser.y
index 03832e7c9f..a5c4b67cb3 100644
--- a/lib/AsmParser/llvmAsmParser.y
+++ b/lib/AsmParser/llvmAsmParser.y
@@ -984,8 +984,7 @@ Module *llvm::RunVMAsmParser(const char * AsmString, Module * M) {
%token DLLIMPORT DLLEXPORT EXTERN_WEAK
%token OPAQUE EXTERNAL TARGET TRIPLE ALIGN
%token DEPLIBS CALL TAIL ASM_TOK MODULE SIDEEFFECT
-%token CC_TOK CCC_TOK CSRETCC_TOK FASTCC_TOK COLDCC_TOK
-%token X86_STDCALLCC_TOK X86_FASTCALLCC_TOK
+%token CC_TOK CCC_TOK FASTCC_TOK COLDCC_TOK X86_STDCALLCC_TOK X86_FASTCALLCC_TOK
%token DATALAYOUT
%type <UIntVal> OptCallingConv
%type <ParamAttrs> OptParamAttrs ParamAttr
@@ -1017,7 +1016,7 @@ Module *llvm::RunVMAsmParser(const char * AsmString, Module * M) {
%token <OtherOpVal> EXTRACTELEMENT INSERTELEMENT SHUFFLEVECTOR
// Function Attributes
-%token NORETURN
+%token NORETURN INREG SRET
// Visibility Styles
%token DEFAULT HIDDEN
@@ -1119,7 +1118,6 @@ FunctionDefineLinkage
OptCallingConv : /*empty*/ { $$ = CallingConv::C; } |
CCC_TOK { $$ = CallingConv::C; } |
- CSRETCC_TOK { $$ = CallingConv::CSRet; } |
FASTCC_TOK { $$ = CallingConv::Fast; } |
COLDCC_TOK { $$ = CallingConv::Cold; } |
X86_STDCALLCC_TOK { $$ = CallingConv::X86_StdCall; } |
@@ -1131,8 +1129,10 @@ OptCallingConv : /*empty*/ { $$ = CallingConv::C; } |
CHECK_FOR_ERROR
};
-ParamAttr : ZEXT { $$ = FunctionType::ZExtAttribute; }
- | SEXT { $$ = FunctionType::SExtAttribute; }
+ParamAttr : ZEXT { $$ = FunctionType::ZExtAttribute; }
+ | SEXT { $$ = FunctionType::SExtAttribute; }
+ | INREG { $$ = FunctionType::InRegAttribute; }
+ | SRET { $$ = FunctionType::StructRetAttribute; }
;
OptParamAttrs : /* empty */ { $$ = FunctionType::NoAttributeSet; }
diff --git a/lib/AsmParser/llvmAsmParser.y.cvs b/lib/AsmParser/llvmAsmParser.y.cvs
index 03832e7c9f..a5c4b67cb3 100644
--- a/lib/AsmParser/llvmAsmParser.y.cvs
+++ b/lib/AsmParser/llvmAsmParser.y.cvs
@@ -984,8 +984,7 @@ Module *llvm::RunVMAsmParser(const char * AsmString, Module * M) {
%token DLLIMPORT DLLEXPORT EXTERN_WEAK
%token OPAQUE EXTERNAL TARGET TRIPLE ALIGN
%token DEPLIBS CALL TAIL ASM_TOK MODULE SIDEEFFECT
-%token CC_TOK CCC_TOK CSRETCC_TOK FASTCC_TOK COLDCC_TOK
-%token X86_STDCALLCC_TOK X86_FASTCALLCC_TOK
+%token CC_TOK CCC_TOK FASTCC_TOK COLDCC_TOK X86_STDCALLCC_TOK X86_FASTCALLCC_TOK
%token DATALAYOUT
%type <UIntVal> OptCallingConv
%type <ParamAttrs> OptParamAttrs ParamAttr
@@ -1017,7 +1016,7 @@ Module *llvm::RunVMAsmParser(const char * AsmString, Module * M) {
%token <OtherOpVal> EXTRACTELEMENT INSERTELEMENT SHUFFLEVECTOR
// Function Attributes
-%token NORETURN
+%token NORETURN INREG SRET
// Visibility Styles
%token DEFAULT HIDDEN
@@ -1119,7 +1118,6 @@ FunctionDefineLinkage
OptCallingConv : /*empty*/ { $$ = CallingConv::C; } |
CCC_TOK { $$ = CallingConv::C; } |
- CSRETCC_TOK { $$ = CallingConv::CSRet; } |
FASTCC_TOK { $$ = CallingConv::Fast; } |
COLDCC_TOK { $$ = CallingConv::Cold; } |
X86_STDCALLCC_TOK { $$ = CallingConv::X86_StdCall; } |
@@ -1131,8 +1129,10 @@ OptCallingConv : /*empty*/ { $$ = CallingConv::C; } |
CHECK_FOR_ERROR
};
-ParamAttr : ZEXT { $$ = FunctionType::ZExtAttribute; }
- | SEXT { $$ = FunctionType::SExtAttribute; }
+ParamAttr : ZEXT { $$ = FunctionType::ZExtAttribute; }
+ | SEXT { $$ = FunctionType::SExtAttribute; }
+ | INREG { $$ = FunctionType::InRegAttribute; }
+ | SRET { $$ = FunctionType::StructRetAttribute; }
;
OptParamAttrs : /* empty */ { $$ = FunctionType::NoAttributeSet; }
diff --git a/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp b/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
index 5f5f0d360f..84754ce9af 100644
--- a/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
+++ b/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
@@ -2168,6 +2168,7 @@ SDOperand SelectionDAGLegalize::LegalizeOp(SDOperand Op) {
const char *FnName = 0;
if (Node->getOpcode() == ISD::MEMSET) {
Entry.Node = Tmp2; Entry.isSigned = false; Entry.Ty = IntPtrTy;
+ Entry.isInReg = false;
Args.push_back(Entry);
// Extend the (previously legalized) ubyte argument to be an int value
// for the call.
@@ -2176,6 +2177,7 @@ SDOperand SelectionDAGLegalize::LegalizeOp(SDOperand Op) {
else
Tmp3 = DAG.getNode(ISD::ZERO_EXTEND, MVT::i32, Tmp3);
Entry.Node = Tmp3; Entry.Ty = Type::Int32Ty; Entry.isSigned = true;
+ Entry.isInReg = false;
Args.push_back(Entry);
Entry.Node = Tmp4; Entry.Ty = IntPtrTy; Entry.isSigned = false;
Args.push_back(Entry);
@@ -2183,7 +2185,7 @@ SDOperand SelectionDAGLegalize::LegalizeOp(SDOperand Op) {
FnName = "memset";
} else if (Node->getOpcode() == ISD::MEMCPY ||
Node->getOpcode() == ISD::MEMMOVE) {
- Entry.Ty = IntPtrTy; Entry.isSigned = false;
+ Entry.Ty = IntPtrTy; Entry.isSigned = false; Entry.isInReg = false;
Entry.Node = Tmp2; Args.push_back(Entry);
Entry.Node = Tmp3; Args.push_back(Entry);
Entry.Node = Tmp4; Args.push_back(Entry);
@@ -4124,7 +4126,7 @@ SDOperand SelectionDAGLegalize::ExpandLibCall(const char *Name, SDNode *Node,
MVT::ValueType ArgVT = Node->getOperand(i).getValueType();
const Type *ArgTy = MVT::getTypeForValueType(ArgVT);
Entry.Node = Node->getOperand(i); Entry.Ty = ArgTy;
- Entry.isSigned = isSigned;
+ Entry.isSigned = isSigned; Entry.isInReg = false;
Args.push_back(Entry);
}
SDOperand Callee = DAG.getExternalSymbol(Name, TLI.getPointerTy());
diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
index 12c5d8e18d..c1d70006c1 100644
--- a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
+++ b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
@@ -2167,6 +2167,8 @@ void SelectionDAGLowering::visitCall(CallInst &I) {
SDOperand ArgNode = getValue(Arg);
Entry.Node = ArgNode; Entry.Ty = Arg->getType();
Entry.isSigned = FTy->paramHasAttr(i, FunctionType::SExtAttribute);
+ Entry.isInReg = FTy->paramHasAttr(i, FunctionType::InRegAttribute);
+ Entry.isSRet = FTy->paramHasAttr(i, FunctionType::StructRetAttribute);
Args.push_back(Entry);
}
@@ -2761,6 +2763,8 @@ void SelectionDAGLowering::visitMalloc(MallocInst &I) {
Entry.Node = Src;
Entry.Ty = TLI.getTargetData()->getIntPtrType();
Entry.isSigned = false;
+ Entry.isInReg = false;
+ Entry.isSRet = false;
Args.push_back(Entry);
std::pair<SDOperand,SDOperand> Result =
@@ -2777,6 +2781,8 @@ void SelectionDAGLowering::visitFree(FreeInst &I) {
Entry.Node = getValue(I.getOperand(0));
Entry.Ty = TLI.getTargetData()->getIntPtrType();
Entry.isSigned = false;
+ Entry.isInReg = false;
+ Entry.isSRet = false;
Args.push_back(Entry);
MVT::ValueType IntPtr = TLI.getPointerTy();
std::pair<SDOperand,SDOperand> Result =
@@ -2859,6 +2865,7 @@ static SDOperand ExpandScalarFormalArgs(MVT::ValueType VT, SDNode *Arg,
/// integrated into SDISel.
std::vector<SDOperand>
TargetLowering::LowerArguments(Function &F, SelectionDAG &DAG) {
+ const FunctionType *FTy = F.getFunctionType();
// Add CC# and isVararg as operands to the FORMAL_ARGUMENTS node.
std::vector<SDOperand> Ops;
Ops.push_back(DAG.getRoot());
@@ -2867,16 +2874,22 @@ TargetLowering::LowerArguments(Function &F, SelectionDAG &DAG) {
// Add one result value for each formal argument.
std::vector<MVT::ValueType> RetVals;
+ unsigned j = 0;
for (Function::arg_iterator I = F.arg_begin(), E = F.arg_end(); I != E; ++I) {
MVT::ValueType VT = getValueType(I->getType());
+ bool isInReg = FTy->paramHasAttr(++j, FunctionType::InRegAttribute);
+ bool isSRet = FTy->paramHasAttr(j, FunctionType::StructRetAttribute);
+ unsigned Flags = (isInReg << 1) | (isSRet << 2);
switch (getTypeAction(VT)) {
default: assert(0 && "Unknown type action!");
case Legal:
RetVals.push_back(VT);
+ Ops.push_back(DAG.getConstant(Flags, MVT::i32));
break;
case Promote:
RetVals.push_back(getTypeToTransformTo(VT));
+ Ops.push_back(DAG.getConstant(Flags, MVT::i32));
break;
case Expand:
if (VT != MVT::Vector) {
@@ -2885,8 +2898,10 @@ TargetLowering::LowerArguments(Function &F, SelectionDAG &DAG) {
// integers it turns into.
MVT::ValueType NVT = getTypeToExpandTo(VT);
unsigned NumVals = getNumElements(VT);
- for (unsigned i = 0; i != NumVals; ++i)
+ for (unsigned i = 0; i != NumVals; ++i) {
RetVals.push_back(NVT);
+ Ops.push_back(DAG.getConstant(Flags, MVT::i32));
+ }
} else {
// Otherwise, this is a vector type. We only support legal vectors
// right now.
@@ -2898,6 +2913,7 @@ TargetLowering::LowerArguments(Function &F, SelectionDAG &DAG) {
MVT::ValueType TVT = MVT::getVectorType(getValueType(EltTy), NumElems);
if (TVT != MVT::Other && isTypeLegal(TVT)) {
RetVals.push_back(TVT);
+ Ops.push_back(DAG.getConstant(Flags, MVT::i32));
} else {
assert(0 && "Don't support illegal by-val vector arguments yet!");
}
@@ -2917,7 +2933,6 @@ TargetLowering::LowerArguments(Function &F, SelectionDAG &DAG) {
// Set up the return result vector.
Ops.clear();
- const FunctionType *FTy = F.getFunctionType();
unsigned i = 0;
unsigned Idx = 1;
for (Function::arg_iterator I = F.arg_begin(), E = F.arg_end(); I != E;
@@ -2984,13 +2999,13 @@ TargetLowering::LowerArguments(Function &F, SelectionDAG &DAG) {
/// ExpandScalarCallArgs - Recursively expand call argument node by
/// bit_converting it or extract a pair of elements from the larger node.
static void ExpandScalarCallArgs(MVT::ValueType VT, SDOperand Arg,
- bool isSigned,
+ unsigned Flags,
SmallVector<SDOperand, 32> &Ops,
SelectionDAG &DAG,
TargetLowering &TLI) {
if (TLI.getTypeAction(VT) != TargetLowering::Expand) {
Ops.push_back(Arg);
- Ops.push_back(DAG.getConstant(isSigned, MVT::i32));
+ Ops.push_back(DAG.getConstant(Flags, MVT::i32));
return;
}
@@ -2998,7 +3013,7 @@ static void ExpandScalarCallArgs(MVT::ValueType VT, SDOperand Arg,
unsigned NumVals = MVT::getSizeInBits(VT) / MVT::getSizeInBits(EVT);
if (NumVals == 1) {
Arg = DAG.getNode(ISD::BIT_CONVERT, EVT, Arg);
- ExpandScalarCallArgs(EVT, Arg, isSigned, Ops, DAG, TLI);
+ ExpandScalarCallArgs(EVT, Arg, Flags, Ops, DAG, TLI);
} else if (NumVals == 2) {
SDOperand Lo = DAG.getNode(ISD::EXTRACT_ELEMENT, EVT, Arg,
DAG.getConstant(0, TLI.getPointerTy()));
@@ -3006,8 +3021,8 @@ static void ExpandScalarCallArgs(MVT::ValueType VT, SDOperand Arg,
DAG.getConstant(1, TLI.getPointerTy()));
if (!TLI.isLittleEndian())
std::swap(Lo, Hi);
- ExpandScalarCallArgs(EVT, Lo, isSigned, Ops, DAG, TLI);
- ExpandScalarCallArgs(EVT, Hi, isSigned, Ops, DAG, TLI);
+ ExpandScalarCallArgs(EVT, Lo, Flags, Ops, DAG, TLI);
+ ExpandScalarCallArgs(EVT, Hi, Flags, Ops, DAG, TLI);
} else {
// Value scalarized into many values. Unimp for now.
assert(0 && "Cannot expand i64 -> i16 yet!");
@@ -3036,11 +3051,14 @@ TargetLowering::LowerCallTo(SDOperand Chain, const Type *RetTy,
MVT::ValueType VT = getValueType(Args[i].Ty);
SDOperand Op = Args[i].Node;
bool isSigned = Args[i].isSigned;
+ bool isInReg = Args[i].isInReg;
+ bool isSRet = Args[i].isSRet;
+ unsigned Flags = (isSRet << 2) | (isInReg << 1) | isSigned;
switch (getTypeAction(VT)) {
default: assert(0 && "Unknown type action!");
case Legal:
Ops.push_back(Op);
- Ops.push_back(DAG.getConstant(isSigned, MVT::i32));
+ Ops.push_back(DAG.getConstant(Flags, MVT::i32));
break;
case Promote:
if (MVT::isInteger(VT)) {
@@ -3051,14 +3069,14 @@ TargetLowering::LowerCallTo(SDOperand Chain, const Type *RetTy,
Op = DAG.getNode(ISD::FP_EXTEND, getTypeToTransformTo(VT), Op);
}
Ops.push_back(Op);
- Ops.push_back(DAG.getConstant(isSigned, MVT::i32));
+ Ops.push_back(DAG.getConstant(Flags, MVT::i32));
break;
case Expand:
if (VT != MVT::Vector) {
// If this is a large integer, it needs to be broken down into small
// integers. Figure out what the source elt type is and how many small
// integers it is.
- ExpandScalarCallArgs(VT, Op, isSigned, Ops, DAG, *this);
+ ExpandScalarCallArgs(VT, Op, Flags, Ops, DAG, *this);
} else {
// Otherwise, this is a vector type. We only support legal vectors
// right now.
@@ -3073,7 +3091,7 @@ TargetLowering::LowerCallTo(SDOperand Chain, const Type *RetTy,
// Insert a VBIT_CONVERT of the MVT::Vector type to the packed type.
Op = DAG.getNode(ISD::VBIT_CONVERT, TVT, Op);
Ops.push_back(Op);
- Ops.push_back(DAG.getConstant(isSigned, MVT::i32));
+ Ops.push_back(DAG.getConstant(Flags, MVT::i32));
} else {
assert(0 && "Don't support illegal by-val vector call args yet!");
abort();
diff --git a/lib/Target/ARM/ARMISelLowering.cpp b/lib/Target/ARM/ARMISelLowering.cpp
index 594a48e788..e2268d212b 100644
--- a/lib/Target/ARM/ARMISelLowering.cpp
+++ b/lib/Target/ARM/ARMISelLowering.cpp
@@ -352,7 +352,6 @@ SDOperand ARMTargetLowering::LowerCALL(SDOperand Op, SelectionDAG &DAG) {
SDOperand Chain = Op.getOperand(0);
unsigned CallConv = cast<ConstantSDNode>(Op.getOperand(1))->getValue();
assert((CallConv == CallingConv::C ||
- CallConv == CallingConv::CSRet ||
CallConv == CallingConv::Fast) && "unknown calling convention");
SDOperand Callee = Op.getOperand(4);
unsigned NumOps = (Op.getNumOperands() - 5) / 2;
diff --git a/lib/Target/CBackend/CBackend.cpp b/lib/Target/CBackend/CBackend.cpp
index 9faba6bd81..0c808131b6 100644
--- a/lib/Target/CBackend/CBackend.cpp
+++ b/lib/Target/CBackend/CBackend.cpp
@@ -1748,8 +1748,8 @@ void CWriter::printContainedStructs(const Type *Ty,
}
void CWriter::printFunctionSignature(const Function *F, bool Prototype) {
- /// isCStructReturn - Should this function actually return a struct by-value?
- bool isCStructReturn = F->getCallingConv() == CallingConv::CSRet;
+ /// isStructReturn - Should this function actually return a struct by-value?
+ bool isStructReturn = F->getFunctionType()->isStructReturn();
if (F->hasInternalLinkage()) Out << "static ";
if (F->hasDLLImportLinkage()) Out << "__declspec(dllimport) ";
@@ -1778,7 +1778,7 @@ void CWriter::printFunctionSignature(const Function *F, bool Prototype) {
// If this is a struct-return function, don't print the hidden
// struct-return argument.
- if (isCStructReturn) {
+ if (isStructReturn) {
assert(I != E && "Invalid struct return function!");
++I;
}
@@ -1804,7 +1804,7 @@ void CWriter::printFunctionSignature(const Function *F, bool Prototype) {
// If this is a struct-return function, don't print the hidden
// struct-return argument.
- if (isCStructReturn) {
+ if (isStructReturn) {
assert(I != E && "Invalid struct return function!");
++I;
}
@@ -1832,7 +1832,7 @@ void CWriter::printFunctionSignature(const Function *F, bool Prototype) {
// Get the return tpe for the function.
const Type *RetTy;
- if (!isCStructReturn)
+ if (!isStructReturn)
RetTy = F->getReturnType();
else {
// If this is a struct-return function, print the struct-return type.
@@ -1855,11 +1855,14 @@ static inline bool isFPIntBitCast(const Instruction &I) {
}
void CWriter::printFunction(Function &F) {
+ /// isStructReturn - Should this function actually return a struct by-value?
+ bool isStructReturn = F.getFunctionType()->isStructReturn();
+
printFunctionSignature(&F, false);
Out << " {\n";
// If this is a struct return function, handle the result with magic.
- if (F.getCallingConv() == CallingConv::CSRet) {
+ if (isStructReturn) {
const Type *StructTy =
cast<PointerType>(F.arg_begin()->getType())->getElementType();
Out << " ";
@@ -1977,7 +1980,10 @@ void CWriter::printBasicBlock(BasicBlock *BB) {
//
void CWriter::visitReturnInst(ReturnInst &I) {
// If this is a struct return function, return the temporary struct.
- if (I.getParent()->getParent()->getCallingConv() == CallingConv::CSRet) {
+ bool isStructReturn = I.getParent()->getParent()->
+ getFunctionType()->isStructReturn();
+
+ if (isStructReturn) {
Out << " return StructReturn;\n";
return;
}
@@ -2468,9 +2474,12 @@ void CWriter::visitCallInst(CallInst &I) {
Value *Callee = I.getCalledValue();
+ const PointerType *PTy = cast<PointerType>(Callee->getType());
+ const FunctionType *FTy = cast<FunctionType>(PTy->getElementType());
+
// If this is a call to a struct-return function, assign to the first
// parameter instead of passing it to the call.
- bool isStructRet = I.getCallingConv() == CallingConv::CSRet;
+ bool isStructRet = FTy->isStructReturn();
if (isStructRet) {
Out << "*(";
writeOperand(I.getOperand(1));
@@ -2478,9 +2487,6 @@ void CWriter::visitCallInst(CallInst &I) {
}
if (I.isTailCall()) Out << " /*tail*/ ";
-
- const PointerType *PTy = cast<PointerType>(Callee->getType());
- const FunctionType *FTy = cast<FunctionType>(PTy->getElementType());
if (!WroteCallee) {
// If this is an indirect call to a struct return function, we need to cast
diff --git a/lib/Target/PowerPC/PPCISelLowering.cpp b/lib/Target/PowerPC/PPCISelLowering.cpp
index 097ca91a30..041ff36af3 100644
--- a/lib/Target/PowerPC/PPCISelLowering.cpp
+++ b/lib/Target/PowerPC/PPCISelLowering.cpp
@@ -1360,9 +1360,9 @@ static SDOperand LowerCALL(SDOperand Op, SelectionDAG &DAG) {
// On PPC64, promote integers to 64-bit values.
if (isPPC64 && Arg.getValueType() == MVT::i32) {
- unsigned ExtOp = ISD::ZERO_EXTEND;
- if (cast<ConstantSDNode>(Op.getOperand(5+2*i+1))->getValue())
- ExtOp = ISD::SIGN_EXTEND;
+ unsigned Flags = cast<ConstantSDNode>(Op.getOperand(5+2*i+1))->getValue();
+ unsigned ExtOp = (Flags & 1) ? ISD::SIGN_EXTEND : ISD::ZERO_EXTEND;
+
Arg = DAG.getNode(ExtOp, MVT::i64, Arg);
}
diff --git a/lib/Target/X86/X86AsmPrinter.cpp b/lib/Target/X86/X86AsmPrinter.cpp
index 5c28fac10c..ff85828c5a 100644
--- a/lib/Target/X86/X86AsmPrinter.cpp
+++ b/lib/Target/X86/X86AsmPrinter.cpp
@@ -71,6 +71,10 @@ void X86SharedAsmPrinter::decorateName(std::string &Name,
unsigned CC = F->getCallingConv();
if (CC != CallingConv::X86_StdCall && CC != CallingConv::X86_FastCall)
return;
+
+ // Decorate names only when we're targeting Cygwin/Mingw32 targets
+ if (!Subtarget->isTargetCygMing())
+ return;
FMFInfoMap::const_iterator info_item = FunctionInfoMap.find(F);
diff --git a/lib/Target/X86/X86ISelLowering.cpp b/lib/Target/X86/X86ISelLowering.cpp
index 9f9fb7248e..0dce6fd6ed 100644
--- a/lib/Target/X86/X86ISelLowering.cpp
+++ b/lib/Target/X86/X86ISelLowering.cpp
@@ -424,57 +424,104 @@ X86TargetLowering::X86TargetLowering(TargetMachine &TM)
}
//===----------------------------------------------------------------------===//
-// C Calling Convention implementation
+// C & StdCall Calling Convention implementation
//===----------------------------------------------------------------------===//
+// StdCall calling convention seems to be standard for many Windows' API
+// routines and around. It differs from C calling convention just a little:
+// callee should clean up the stack, not caller. Symbols should be also
+// decorated in some fancy way :) It doesn't support any vector arguments.
/// AddLiveIn - This helper function adds the specified physical register to the
/// MachineFunction as a live in value. It also creates a corresponding virtual
/// register for it.
static unsigned AddLiveIn(MachineFunction &MF, unsigned PReg,
- TargetRegisterClass *RC) {
+ const TargetRegisterClass *RC) {
assert(RC->contains(PReg) && "Not the correct regclass!");
unsigned VReg = MF.getSSARegMap()->createVirtualRegister(RC);
MF.addLiveIn(PReg, VReg);
return VReg;
}
-/// HowToPassCCCArgument - Returns how an formal argument of the specified type
+/// HowToPassArgument - Returns how an formal argument of the specified type
/// should be passed. If it is through stack, returns the size of the stack
-/// slot; if it is through XMM register, returns the number of XMM registers
-/// are needed.
+/// slot; if it is through integer or XMM register, returns the number of
+/// integer or XMM registers are needed.
static void
-HowToPassCCCArgument(MVT::ValueType ObjectVT, unsigned NumXMMRegs,
- unsigned &ObjSize, unsigned &ObjXMMRegs) {
+HowToPassCallArgument(MVT::ValueType ObjectVT,
+ bool ArgInReg,
+ unsigned NumIntRegs, unsigned NumXMMRegs,
+ unsigned MaxNumIntRegs,
+ unsigned &ObjSize, unsigned &ObjIntRegs,
+ unsigned &ObjXMMRegs,
+ bool AllowVectors = true) {
+ ObjSize = 0;
+ ObjIntRegs = 0;
ObjXMMRegs = 0;
+ if (MaxNumIntRegs>3) {
+ // We don't have too much registers on ia32! :)
+ MaxNumIntRegs = 3;
+ }
+
switch (ObjectVT) {
default: assert(0 && "Unhandled argument type!");
- case MVT::i8: ObjSize = 1; break;
- case MVT::i16: ObjSize = 2; break;
- case MVT::i32: ObjSize = 4; break;
- case MVT::i64: ObjSize = 8; break;
- case MVT::f32: ObjSize = 4; break;
- case MVT::f64: ObjSize = 8; break;
+ case MVT::i8:
+ if (ArgInReg && (NumIntRegs < MaxNumIntRegs))
+ ObjIntRegs = 1;
+ else
+ ObjSize = 1;
+ break;
+ case MVT::i16:
+ if (ArgInReg && (NumIntRegs < MaxNumIntRegs))
+ ObjIntRegs = 1;
+ else
+ ObjSize = 2;
+ break;
+ case MVT::i32:
+ if (ArgInReg && (NumIntRegs < MaxNumIntRegs))
+ ObjIntRegs = 1;
+ else
+ ObjSize = 4;
+ break;
+ case MVT::i64:
+ if (ArgInReg && (NumIntRegs+2 <= MaxNumIntRegs)) {
+ ObjIntRegs = 2;
+ } else if (ArgInReg && (NumIntRegs+1 <= MaxNumIntRegs)) {
+ ObjIntRegs = 1;
+ ObjSize = 4;
+ } else
+ ObjSize = 8;
+ case MVT::f32:
+ ObjSize = 4;
+ break;
+ case MVT::f64:
+ ObjSize = 8;
+ break;
case MVT::v16i8:
case MVT::v8i16:
case MVT::v4i32:
case MVT::v2i64:
case MVT::v4f32:
case MVT::v2f64:
- if (NumXMMRegs < 4)
- ObjXMMRegs = 1;
- else
- ObjSize = 16;
- break;
+ if (AllowVectors) {
+ if (NumXMMRegs < 4)
+ ObjXMMRegs = 1;
+ else
+ ObjSize = 16;
+ break;
+ } else
+ assert(0 && "Unhandled argument type [vector]!");
}
}
-SDOperand X86TargetLowering::LowerCCCArguments(SDOperand Op, SelectionDAG &DAG) {
+SDOperand X86TargetLowering::LowerCCCArguments(SDOperand Op, SelectionDAG &DAG,
+ bool isStdCall) {
unsigned NumArgs = Op.Val->getNumValues() - 1;
MachineFunction &MF = DAG.getMachineFunction();
MachineFrameInfo *MFI = MF.getFrameInfo();
SDOperand Root = Op.getOperand(0);
std::vector<SDOperand> ArgValues;
+ bool isVarArg = cast<ConstantSDNode>(Op.getOperand(2))->getValue() != 0;
// Add DAG nodes to load the arguments... On entry to a function on the X86,
// the stack frame looks like this:
@@ -484,57 +531,115 @@ SDOperand X86TargetLowering::LowerCCCArguments(SDOperand Op, SelectionDAG &DAG)
// [ESP + 8] -- second argument, if first argument is <= 4 bytes in size
// ...
//
- unsigned ArgOffset = 0; // Frame mechanisms handle retaddr slot
- unsigned NumXMMRegs = 0; // XMM regs used for parameter passing.
+ unsigned ArgOffset = 0; // Frame mechanisms handle retaddr slot
+ unsigned NumSRetBytes= 0; // How much bytes on stack used for struct return
+ unsigned NumXMMRegs = 0; // XMM regs used for parameter passing.
+ unsigned NumIntRegs = 0; // Integer regs used for parameter passing
+
static const unsigned XMMArgRegs[] = {
X86::XMM0, X86::XMM1, X86::XMM2, X86::XMM3
};
+ static const unsigned GPRArgRegs[][3] = {
+ { X86::AL, X86::DL, X86::CL },
+ { X86::AX, X86::DX, X86::CX },
+ { X86::EAX, X86::EDX, X86::ECX }
+ };
+ static const TargetRegisterClass* GPRClasses[3] = {
+ X86::GR8RegisterClass, X86::GR16RegisterClass, X86::GR32RegisterClass
+ };
+
+ // Handle regparm attribute
+ std::vector<bool> ArgInRegs(NumArgs, false);
+ std::vector<bool> SRetArgs(NumArgs, false);
+ if (!isVarArg) {
+ for (unsigned i = 0; i<NumArgs; ++i) {
+ unsigned Flags = cast<ConstantSDNode>(Op.getOperand(3+i))->getValue();
+ ArgInRegs[i] = (Flags >> 1) & 1;
+ SRetArgs[i] = (Flags >> 2) & 1;
+ }
+ }
+
for (unsigned i = 0; i < NumArgs; ++i) {
MVT::ValueType ObjectVT = Op.getValue(i).getValueType();
unsigned ArgIncrement = 4;
unsigned ObjSize = 0;
unsigned ObjXMMRegs = 0;
- HowToPassCCCArgument(ObjectVT, NumXMMRegs, ObjSize, ObjXMMRegs);
+ unsigned ObjIntRegs = 0;
+ unsigned Reg = 0;
+ SDOperand ArgValue;
+
+ HowToPassCallArgument(ObjectVT,
+ ArgInRegs[i],
+ NumIntRegs, NumXMMRegs, 3,
+ ObjSize, ObjIntRegs, ObjXMMRegs,
+ !isStdCall);
+
if (ObjSize > 4)
ArgIncrement = ObjSize;
- SDOperand ArgValue;
- if (ObjXMMRegs) {
- // Passed in a XMM register.
- unsigned Reg = AddLiveIn(MF, XMMArgRegs[NumXMMRegs],
- X86::VR128RegisterClass);
- ArgValue= DAG.getCopyFromReg(Root, Reg, ObjectVT);
- ArgValues.push_back(ArgValue);
+ if (ObjIntRegs || ObjXMMRegs) {
+ switch (ObjectVT) {
+ default: assert(0 && "Unhandled argument type!");
+ case MVT::i8:
+ case MVT::i16:
+ case MVT::i32: {
+ unsigned RegToUse = GPRArgRegs[ObjectVT-MVT::i8][NumIntRegs];
+ Reg = AddLiveIn(MF, RegToUse, GPRClasses[ObjectVT-MVT::i8]);
+ ArgValue = DAG.getCopyFromReg(Root, Reg, ObjectVT);
+ break;
+ }
+ case MVT::v16i8:
+ case MVT::v8i16:
+ case MVT::v4i32:
+ case MVT::v2i64:
+ case MVT::v4f32:
+ case MVT::v2f64:
+ assert(!isStdCall && "Unhandled argument type!");
+ Reg = AddLiveIn(MF, XMMArgRegs[NumXMMRegs], X86::VR128RegisterClass);
+ ArgValue = DAG.getCopyFromReg(Root, Reg, ObjectVT);
+ break;
+ }
+ NumIntRegs += ObjIntRegs;
NumXMMRegs += ObjXMMRegs;
- } else {
+ }
+ if (ObjSize) {
// XMM arguments have to be aligned on 16-byte boundary.
if (ObjSize == 16)
ArgOffset = ((ArgOffset + 15) / 16) * 16;
- // Create the frame index object for this incoming parameter...
+ // Create the SelectionDAG nodes corresponding to a load from this
+ // parameter.
int FI = MFI->CreateFixedObject(ObjSize, ArgOffset);
SDOperand FIN = DAG.getFrameIndex(FI, getPointerTy());
ArgValue = DAG.getLoad(Op.Val->getValueType(i), Root, FIN, NULL, 0);
- ArgValues.push_back(ArgValue);
- ArgOffset += ArgIncrement; // Move on to the next argument...
+
+ ArgOffset += ArgIncrement; // Move on to the next argument.
+ if (SRetArgs[i])
+ NumSRetBytes += ArgIncrement;
}
+
+ ArgValues.push_back(ArgValue);
}
ArgValues.push_back(Root);
// If the function takes variable number of arguments, make a frame index for
// the start of the first vararg value... for expansion of llvm.va_start.
- bool isVarArg = cast<ConstantSDNode>(Op.getOperand(2))->getValue() != 0;
if (isVarArg)
VarArgsFrameIndex = MFI->CreateFixedObject(1, ArgOffset);
+
+ if (isStdCall && !isVarArg) {
+ BytesToPopOnReturn = ArgOffset; // Callee pops everything..
+ BytesCallerReserves = 0;
+ } else {
+ BytesToPopOnReturn = NumSRetBytes; // Callee pops hidden struct pointer.
+ BytesCallerReserves = ArgOffset;
+ }
+
RegSaveFrameIndex = 0xAAAAAAA; // X86-64 only.
ReturnAddrIndex = 0; // No return address slot generated yet.
- BytesToPopOnReturn = 0; // Callee pops nothing.
- BytesCallerReserves = ArgOffset;
- // If this is a struct return on, the callee pops the hidden struct
- // pointer. This is common for Darwin/X86, Linux & Mingw32 targets.
- if (MF.getFunction()->getCallingConv() == CallingConv::CSRet)
- BytesToPopOnReturn = 4;
+
+ MF.getInfo<X86FunctionInfo>()->setBytesToPopOnReturn(BytesToPopOnReturn);
// Return the new list of results.
std::vector<MVT::ValueType> RetVTs(Op.Val->value_begin(),
@@ -542,52 +647,64 @@ SDOperand X86TargetLowering::LowerCCCArguments(SDOperand Op, SelectionDAG &DAG)
return DAG.getNode(ISD::MERGE_VALUES, RetVTs, &ArgValues[0],ArgValues.size());
}
-
-SDOperand X86TargetLowering::LowerCCCCallTo(SDOperand Op, SelectionDAG &DAG) {
+SDOperand X86TargetLowering::LowerCCCCallTo(SDOperand Op, SelectionDAG &DAG,
+ bool isStdCall) {
SDOperand Chain = Op.getOperand(0);
- unsigned CallingConv= cast<ConstantSDNode>(Op.getOperand(1))->getValue();
+ bool isVarArg = cast<ConstantSDNode>(Op.getOperand(2))->getValue() != 0;
bool isTailCall = cast<ConstantSDNode>(Op.getOperand(3))->getValue() != 0;
SDOperand Callee = Op.getOperand(4);
MVT::ValueType RetVT= Op.Val->getValueType(0);
unsigned NumOps = (Op.getNumOperands() - 5) / 2;
- // Keep track of the number of XMM regs passed so far.
- unsigned NumXMMRegs = 0;
static const unsigned XMMArgRegs[] = {
X86::XMM0, X86::XMM1, X86::XMM2, X86::XMM3
};
+ static const unsigned GPR32ArgRegs[] = {
+ X86::EAX, X86::EDX, X86::ECX
+ };
// Count how many bytes are to be pushed on the stack.
- unsigned NumBytes = 0;
+ unsigned NumBytes = 0;
+ // Keep track of the number of integer regs passed so far.
+ unsigned NumIntRegs = 0;
+ // Keep track of the number of XMM regs passed so far.
+ unsigned NumXMMRegs = 0;
+ // How much bytes on stack used for struct return
+ unsigned NumSRetBytes= 0;
+
+ // Handle regparm attribute
+ std::vector<bool> ArgInRegs(NumOps, false);
+ std::vector<bool> SRetArgs(NumOps, false);
+ for (unsigned i = 0; i<NumOps; ++i) {
+ unsigned Flags =
+ dyn_cast<ConstantSDNode>(Op.getOperand(5+2*i+1))->getValue();
+ ArgInRegs[i] = (Flags >> 1) & 1;
+ SRetArgs[i] = (Flags >> 2) & 1;
+ }
+
+ // Calculate stack frame size
for (unsigned i = 0; i != NumOps; ++i) {
SDOperand Arg = Op.getOperand(5+2*i);
+ unsigned ArgIncrement = 4;
+ unsigned ObjSize = 0;
+ unsigned ObjIntRegs = 0;
+ unsigned ObjXMMRegs = 0;
- switch (Arg.getValueType()) {
- default: assert(0 && "Unexpected ValueType for argument!");
- case MVT::i8:
- case MVT::i16:
- case MVT::i32:
- case MVT::f32:
- NumBytes += 4;
- break;
- case MVT::i64:
- case MVT::f64:
- NumBytes += 8;
- break;
- case MVT::v16i8:
- case MVT::v8i16:
- case MVT::v4i32:
- case MVT::v2i64:
- case MVT::v4f32:
- case MVT::v2f64:
- if (NumXMMRegs < 4)
- ++NumXMMRegs;
- else {
- // XMM arguments have to be aligned on 16-byte boundary.
+ HowToPassCallArgument(Arg.getValueType(),
+ ArgInRegs[i],
+ NumIntRegs, NumXMMRegs, 3,
+ ObjSize, ObjIntRegs, ObjXMMRegs,
+ !isStdCall);
+ if (ObjSize > 4)
+ ArgIncrement = ObjSize;
+
+ NumIntRegs += ObjIntRegs;
+ NumXMMRegs += ObjXMMRegs;
+ if (ObjSize) {
+ // XMM arguments have to be aligned on 16-byte boundary.
+ if (ObjSize == 16)
NumBytes = ((NumBytes + 15) / 16) * 16;
- NumBytes += 16;
- }
- break;
+ NumBytes += ArgIncrement;
}
}
@@ -596,58 +713,67 @@ SDOperand X86TargetLowering::LowerCCCCallTo(SDOperand Op, SelectionDAG &DAG) {
// Arguments go on the stack in reverse order, as specified by the ABI.
unsigned ArgOffset = 0;
NumXMMRegs = 0;
+ NumIntRegs = 0;
std::vector<std::pair<unsigned, SDOperand> > RegsToPass;
std::vector<SDOperand> MemOpChains;
SDOperand StackPtr = DAG.getRegister(X86StackPtr, getPointerTy());
for (unsigned i = 0; i != NumOps; ++i) {
SDOperand Arg = Op.getOperand(5+2*i);
+ unsigned ArgIncrement = 4;
+ unsigned ObjSize = 0;
+ unsigned ObjIntRegs = 0;
+ unsigned ObjXMMRegs = 0;
- switch (Arg.getValueType()) {
- default: assert(0 && "Unexpected ValueType for argument!");
- case MVT::i8:
- case MVT::i16: {
+ HowToPassCallArgument(Arg.getValueType(),
+ ArgInRegs[i],
+ NumIntRegs, NumXMMRegs, 3,
+ ObjSize, ObjIntRegs, ObjXMMRegs,
+ !isStdCall);
+
+ if (ObjSize > 4)
+ ArgIncrement = ObjSize;
+
+ if (Arg.getValueType() == MVT::i8 || Arg.getValueType() == MVT::i16) {
// Promote the integer to 32 bits. If the input type is signed use a
// sign extend, otherwise use a zero extend.
- unsigned ExtOp =
- dyn_cast<ConstantSDNode>(Op.getOperand(5+2*i+1))->getValue() ?
- ISD::SIGN_EXTEND : ISD::ZERO_EXTEND;
+ unsigned Flags = cast<ConstantSDNode>(Op.getOperand(5+2*i+1))->getValue();
+
+ unsigned ExtOp = (Flags & 1) ? ISD::SIGN_EXTEND : ISD::ZERO_EXTEND;
Arg = DAG.getNode(ExtOp, MVT::i32, Arg);
}
- // Fallthrough
- case MVT::i32:
- case MVT::f32: {
- SDOperand PtrOff = DAG.getConstant(ArgOffset, getPointerTy());
- PtrOff = DAG.getNode(ISD::ADD, getPointerTy(), StackPtr, PtrOff);
- MemOpChains.push_back(DAG.getStore(Chain, Arg, PtrOff, NULL, 0));
- ArgOffset += 4;
- break;
+ if (ObjIntRegs || ObjXMMRegs) {
+ switch (Arg.getValueType()) {
+ default: assert(0 && "Unhandled argument type!");
+ case MVT::i32:
+ RegsToPass.push_back(std::make_pair(GPR32ArgRegs[NumIntRegs], Arg));
+ break;
+ case MVT::v16i8:
+ case MVT::v8i16:
+ case MVT::v4i32:
+ case MVT::v2i64:
+ case MVT::v4f32:
+ case MVT::v2f64:
+ assert(!isStdCall && "Unhandled argument type!");
+ RegsToPass.push_back(std::make_pair(XMMArgRegs[NumXMMRegs], Arg));
+ break;
+ }
+
+ NumIntRegs += ObjIntRegs;
+ NumXMMRegs += ObjXMMRegs;
}
- case MVT::i64:
- case MVT::f64: {
+ if (ObjSize) {
+ // XMM arguments have to be aligned on 16-byte boundary.
+ if (ObjSize == 16)
+ ArgOffset = ((ArgOffset + 15) / 16) * 16;
+
SDOperand PtrOff = DAG.getConstant(ArgOffset, getPointerTy());
PtrOff = DAG.getNode(ISD::ADD, getPointerTy(), StackPtr, PtrOff);
MemOpChains.push_back(DAG.getStore(Chain, Arg, PtrOff, NULL, 0));
- ArgOffset += 8;
- break;
- }
- case MVT::v16i8:
- case MVT::v8i16:
- case MVT::v4i32:
- case MVT::v2i64:
- case MVT::v4f32:
- case MVT::v2f64:
- if (NumXMMRegs < 4) {
- RegsToPass.push_back(std::make_pair(XMMArgRegs[NumXMMRegs], Arg));
- NumXMMRegs++;
- } else {
- // XMM arguments have to be aligned on 16-byte boundary.
- ArgOffset = ((ArgOffset + 15) / 16) * 16;
- SDOperand PtrOff = DAG.getConstant(ArgOffset, getPointerTy());
- PtrOff = DAG.getNode(ISD::ADD, getPointerTy(), StackPtr, PtrOff);
- MemOpChains.push_back(DAG.getStore(Chain, Arg, PtrOff, NULL, 0));
- ArgOffset += 16;
- }
+
+ ArgOffset += ArgIncrement; // Move on to the next argument.
+ if (SRetArgs[i])
+ NumSRetBytes += ArgIncrement;
}
}
@@ -706,12 +832,19 @@ SDOperand X86TargetLowering::LowerCCCCallTo(SDOperand Op, SelectionDAG &DAG) {
// Create the CALLSEQ_END node.
unsigned NumBytesForCalleeToPush = 0;
- // If this is is a call to a struct-return function, the callee
- // pops the hidden struct pointer, so we have to push it back.
- // This is common for Darwin/X86, Linux & Mingw32 targets.
- if (CallingConv == CallingConv::CSRet)
- NumBytesForCalleeToPush = 4;
-
+ if (isStdCall) {
+ if (isVarArg) {
+ NumBytesForCalleeToPush = NumSRetBytes;
+ } else {
+ NumBytesForCalleeToPush = NumBytes;
+ }
+ } else {
+ // If this is is a call to a struct-return function, the callee
+ // pops the hidden struct pointer, so we have to push it back.
+ // This is common for Darwin/X86, Linux & Mingw32 targets.
+ NumBytesForCalleeToPush = NumSRetBytes;
+ }
+
NodeTys.clear();
NodeTys.push_back(MVT::Other); // Returns a chain
if (RetVT != MVT::Other)
@@ -760,6 +893,7 @@ SDOperand X86TargetLowering::LowerCCCCallTo(SDOperand Op, SelectionDAG &DAG) {
case MVT::v2i64:
case MVT::v4f32:
case MVT::v2f64:
+ assert(!isStdCall && "Unknown value type to return!");
Chain = DAG.getCopyFromReg(Chain, X86::XMM0, RetVT, InFlag).getValue(1);
ResultVals.push_back(Chain.getValue(0));
NodeTys.push_back(RetVT);
@@ -1319,7 +1453,7 @@ X86TargetLowering::LowerX86_64CCCCallTo(SDOperand Op, SelectionDAG &DAG) {
}
//===----------------------------------------------------------------------===//
-// Fast Calling Convention implementation
+// Fast & FastCall Calling Convention implementation
//===----------------------------------------------------------------------===//
//
// The X86 'fast' calling convention passes up to two integer arguments in
@@ -1334,78 +1468,20 @@ X86TargetLowering::LowerX86_64CCCCallTo(SDOperand Op, SelectionDAG &DAG) {
// Note that this can be enhanced in the future to pass fp vals in registers
// (when we have a global fp allocator) and do other tricks.
//
+//===----------------------------------------------------------------------===//
+// The X86 'fastcall' calling convention passes up to two integer arguments in
+// registers (an appropriate portion of ECX/EDX), passes arguments in C order,
+// and requires that the callee pop its arguments off the stack (allowing proper
+// tail calls), and has the same return value conventions as C calling convs.
+//
+// This calling convention always arranges for the callee pop value to be 8n+4
+// bytes, which is needed for tail recursion elimination and stack alignment
+// reasons.
-/// HowToPassFastCCArgument - Returns how an formal argument of the specified
-/// type should be passed. If it is through stack, returns the size of the stack
-/// slot; if it is through integer or XMM register, returns the number of
-/// integer or XMM registers are needed.
-static void
-HowToPassFastCCArgument(MVT::ValueType ObjectVT,
- unsigned NumIntRegs, unsigned NumXMMRegs,
- unsigned &ObjSize, unsigned &ObjIntRegs,
- unsigned &ObjXMMRegs) {
- ObjSize = 0;
- ObjIntRegs = 0;
- ObjXMMRegs = 0;
-
- switch (ObjectVT) {
- default: assert(0 && "Unhandled argument type!");
- case MVT::i8:
-#if FASTCC_NUM_INT_ARGS_INREGS > 0
- if (NumIntRegs < FASTCC_NUM_INT_ARGS_INREGS)
- ObjIntRegs = 1;
- else
-#endif
- ObjSize = 1;
- break;
- case MVT::i16:
-#if FASTCC_NUM_INT_ARGS_INREGS > 0
- if (NumIntRegs < FASTCC_NUM_INT_ARGS_INREGS)
- ObjIntRegs = 1;
- else
-#endif
- ObjSize = 2;
- break;
- case MVT::i32:
-#if FASTCC_NUM_INT_ARGS_INREGS > 0
- if (NumIntRegs < FASTCC_NUM_INT_ARGS_INREGS)
- ObjIntRegs = 1;
- else
-#endif
- ObjSize = 4;
- break;
- case MVT::i64:
-#if FASTCC_NUM_INT_ARGS_INREGS > 0
- if (NumIntRegs+2 <= FASTCC_NUM_INT_ARGS_INREGS) {
- ObjIntRegs = 2;
- } else if (NumIntRegs+1 <= FASTCC_NUM_INT_ARGS_INREGS) {
- ObjIntRegs = 1;
- ObjSize = 4;
- } else
-#endif
- ObjSize = 8;
- case MVT::f32:
- ObjSize = 4;
- break;
- case MVT::f64:
- ObjSize = 8;
- break;
- case MVT::v16i8:
- case MVT::v8i16:
- case MVT::v4i32:
- case MVT::v2i64:
- case MVT::v4f32:
- case MVT::v2f64:
- if (NumXMMRegs < 4)
- ObjXMMRegs = 1;
- else
- ObjSize = 16;
- break;
- }
-}
SDOperand
-X86TargetLowering::LowerFastCCArguments(SDOperand Op, SelectionDAG &DAG) {
+X86TargetLowering::LowerFastCCArguments(SDOperand Op, SelectionDAG &DAG,
+ bool isFastCall) {
unsigned NumArgs = Op.Val->getNumValues()-1;
MachineFunction &MF = DAG.getMachineFunction();
MachineFrameInfo *MFI = MF.getFrameInfo();
@@ -1422,8 +1498,8 @@ X86TargetLowering::LowerFastCCArguments(SDOperand Op, SelectionDAG &DAG) {
unsigned ArgOffset = 0; // Frame mechanisms handle retaddr slot
// Keep track of the number of integer regs passed so far. This can be either
- // 0 (neither EAX or EDX used), 1 (EAX is used) or 2 (EAX and EDX are both
- // used).
+ // 0 (neither EAX/ECX or EDX used), 1 (EAX/ECX is used) or 2 (EAX/ECX and EDX
+ // are both used).
unsigned NumIntRegs = 0;
unsigned NumXMMRegs = 0; // XMM regs used for parameter passing.
@@ -1431,62 +1507,61 @@ X86TargetLowering::LowerFastCCArguments(SDOperand Op, SelectionDAG &DAG) {
X86::XMM0, X86::XMM1, X86::XMM2, X86::XMM3
};
+ static const unsigned GPRArgRegs[][2][2] = {
+ {{ X86::AL, X86::DL }, { X86::CL, X86::DL }},
+ {{ X86::AX, X86::DX }, { X86::CX, X86::DX }},
+ {{ X86::EAX, X86::EDX }, { X86::ECX, X86::EDX }}
+ };
+
+ static const TargetRegisterClass* GPRClasses[3] = {
+ X86::GR8RegisterClass, X86::GR16RegisterClass, X86::GR32RegisterClass
+ };
+
+ unsigned GPRInd = (isFastCall ? 1 : 0);
for (unsigned i = 0; i < NumArgs; ++i) {
MVT::ValueType ObjectVT = Op.getValue(i).getValueType();
unsigned ArgIncrement = 4;
unsigned ObjSize = 0;
- unsigned ObjIntRegs = 0;
unsigned ObjXMMRegs = 0;
-
- HowToPassFastCCArgument(ObjectVT, NumIntRegs, NumXMMRegs,
- ObjSize, ObjIntRegs, ObjXMMRegs);
+ unsigned ObjIntRegs = 0;
+ unsigned Reg = 0;
+ SDOperand ArgValue;
+
+ HowToPassCallArgument(ObjectVT,
+ true, // Use as much registers as possible
+ NumIntRegs, NumXMMRegs,
+ (isFastCall ? 2 : FASTCC_NUM_INT_ARGS_INREGS),
+ ObjSize, ObjIntRegs, ObjXMMRegs,
+ !isFastCall);
+
if (ObjSize > 4)
ArgIncrement = ObjSize;
- unsigned Reg = 0;
- SDOperand ArgValue;
if (ObjIntRegs || ObjXMMRegs) {
switch (ObjectVT) {
default: assert(0 && "Unhandled argument type!");
case MVT::i8:
- Reg = AddLiveIn(MF, NumIntRegs ? X86::DL : X86::AL,
- X86::GR8RegisterClass);
- ArgValue = DAG.getCopyFromReg(Root, Reg, MVT::i8);
- break;
case MVT::i16:
- Reg = AddLiveIn(MF, NumIntRegs ? X86::DX : X86::AX,
- X86::GR16RegisterClass);
- ArgValue = DAG.getCopyFromReg(Root, Reg, MVT::i16);
- break;
case MVT::i32:
- Reg = AddLiveIn(MF, NumIntRegs ? X86::EDX : X86::EAX,
- X86::GR32RegisterClass);
- ArgValue = DAG.getCopyFromReg(Root, Reg, MVT::i32);
- break;
- case MVT::i64:
- Reg = AddLiveIn(MF, NumIntRegs ? X86::EDX : X86::EAX,
- X86::GR32RegisterClass);
- ArgValue = DAG.getCopyFromReg(Root, Reg, MVT::i32);
- if (ObjIntRegs == 2) {
- Reg = AddLiveIn(MF, X86::EDX, X86::GR32RegisterClass);
- SDOperand ArgValue2 = DAG.getCopyFromReg(Root, Reg, MVT::i32);
- ArgValue= DAG.getNode(ISD::BUILD_PAIR, MVT::i64, ArgValue, ArgValue2);
- }
- break;
+ unsigned RegToUse = GPRArgRegs[ObjectVT-MVT::i8][GPRInd][NumIntRegs];
+ Reg = AddLiveIn(MF, RegToUse, GPRClasses[ObjectVT-MVT::i8]);
+ ArgValue = DAG.getCopyFromReg(Root, Reg, ObjectVT);
+ break;
case MVT::v16i8:
case MVT::v8i16:
case MVT::v4i32:
case MVT::v2i64:
case MVT::v4f32:
- case MVT::v2f64:
+ case MVT::v2f64: {
+ assert(!isFastCall && "Unhandled argument type!");
Reg = AddLiveIn(MF, XMMArgRegs[NumXMMRegs], X86::VR128RegisterClass);
ArgValue = DAG.getCopyFromReg(Root, Reg, ObjectVT);
break;
}
+ }
NumIntRegs += ObjIntRegs;
NumXMMRegs += ObjXMMRegs;
}
-
if (ObjSize) {
// XMM arguments have to be aligned on 16-byte boundary.
if (ObjSize == 16)
@@ -1495,12 +1570,8 @@ X86TargetLowering::LowerFastCCArguments(SDOperand Op, SelectionDAG &DAG) {
// parameter.
int FI = MFI->CreateFixedObject(ObjSize, ArgOffset);
SDOperand FIN = DAG.getFrameIndex(FI, getPointerTy());
- if (ObjectVT == MVT::i64 && ObjIntRegs) {
- SDOperand ArgValue2 = DAG.getLoad(Op.Val->getValueType(i), Root, FIN,
- NULL, 0);
- ArgValue = DAG.getNode(ISD::BUILD_PAIR, MVT::i64, ArgValue, ArgValue2);
- } else
- ArgValue = DAG.getLoad(Op.Val->getValueType(i), Root, FIN, NULL, 0);
+ ArgValue = DAG.getLoad(Op.Val->getValueType(i), Root, FIN, NULL, 0);
+
ArgOffset += ArgIncrement; // Move on to the next argument.
}
@@ -1520,6 +1591,8 @@ X86TargetLowering::LowerFastCCArguments(SDOperand Op, SelectionDAG &DAG) {
BytesToPopOnReturn = ArgOffset; // Callee pops all stack arguments.
BytesCallerReserves = 0;
+ MF.getInfo<X86FunctionInfo>()->setBytesToPopOnReturn(BytesToPopOnReturn);
+
// Finally, inform the code generator which regs we return values in.
switch (getValueType(MF.getFunction()->getReturnType())) {
default: assert(0 && "Unknown type!");
@@ -1544,6 +1617,7 @@ X86TargetLowering::LowerFastCCArguments(SDOperand Op, SelectionDAG &DAG) {
case MVT::v2i64:
case MVT::v4f32:
case MVT::v2f64:
+ assert(!isFastCall && "Unknown result type");
MF.addLiveOut(X86::XMM0);
break;
}
@@ -1566,27 +1640,21 @@ SDOperand X86TargetLowering::LowerFastCCCallTo(SDOperand Op, SelectionDAG &DAG,
unsigned NumBytes = 0;
// Keep track of the number of integer regs passed so far. This can be either
- // 0 (neither EAX or EDX used), 1 (EAX is used) or 2 (EAX and EDX are both
- // used).
+ // 0 (neither EAX/ECX or EDX used), 1 (EAX/ECX is used) or 2 (EAX/ECX and EDX
+ // are both used).
unsigned NumIntRegs = 0;
unsigned NumXMMRegs = 0; // XMM regs used for parameter passing.
- static const unsigned GPRArgRegs[][2] = {
- { X86::AL, X86::DL },
- { X86::AX, X86::DX },
- { X86::EAX, X86::EDX }
- };
-#if 0
- static const unsigned FastCallGPRArgRegs[][2] = {
- { X86::CL, X86::DL },
- { X86::CX, X86::DX },
- { X86::ECX, X86::EDX }
+ static const unsigned GPRArgRegs[][2][2] = {
+ {{ X86::AL, X86::DL }, { X86::CL, X86::DL }},
+ {{ X86::AX, X86::DX }, { X86::CX, X86::DX }},
+ {{ X86::EAX, X86::EDX }, { X86::ECX, X86::EDX }}
};
-#endif
static const unsigned XMMArgRegs[] = {
X86::XMM0, X86::XMM1, X86::XMM2, X86::XMM3
};
+ unsigned GPRInd = (isFastCall ? 1 : 0);
for (unsigned i = 0; i != NumOps; ++i) {
SDOperand Arg = Op.getOperand(5+2*i);
@@ -1613,18 +1681,15 @@ SDOperand X86TargetLowering::LowerFastCCCallTo(SDOperand Op, SelectionDAG &DAG,
case MVT::v2i64:
case MVT::v4f32:
case MVT::v2f64:
- if (isFastCall) {
- assert(0 && "Unknown value type!");
- } else {
- if (NumXMMRegs < 4)
- NumXMMRegs++;
- else {
- // XMM arguments have to be aligned on 16-byte boundary.
- NumBytes = ((NumBytes + 15) / 16) * 16;
- NumBytes += 16;
- }
- }
- break;
+ assert(!isFastCall && "Unknown value type!");
+ if (NumXMMRegs < 4)
+ NumXMMRegs++;
+ else {
+ // XMM arguments have to be aligned on 16-byte boundary.
+ NumBytes = ((NumBytes + 15) / 16) * 16;
+ NumBytes += 16;
+ }
+ break;
}
}
@@ -1651,13 +1716,13 @@ SDOperand X86TargetLowering::LowerFastCCCallTo(SDOperand Op, SelectionDAG &DAG,
case MVT::i32: {
unsigned MaxNumIntRegs = (isFastCall ? 2 : FASTCC_NUM_INT_ARGS_INREGS);
if (NumIntRegs < MaxNumIntRegs) {
- RegsToPass.push_back(
- std::make_pair(GPRArgRegs[Arg.getValueType()-MVT::i8][NumIntRegs],
- Arg));
+ unsigned RegToUse =
+ GPRArgRegs[Arg.getValueType()-MVT::i8][GPRInd][NumIntRegs];
+ RegsToPass.push_back(std::make_pair(RegToUse, Arg));
++NumIntRegs;
break;
}
- } // Fall through
+ } // Fall through
case MVT::f32: {
SDOperand PtrOff = DAG.getConstant(ArgOffset, getPointerTy());
PtrOff = DAG.getNode(ISD::ADD, getPointerTy(), StackPtr, PtrOff);
@@ -1678,22 +1743,19 @@ SDOperand X86TargetLowering::LowerFastCCCallTo(SDOperand Op, SelectionDAG &DAG,
case MVT::v2i64:
case MVT::v4f32:
case MVT::v2f64:
- if (isFastCall) {
- assert(0 && "Unexpected ValueType for argument!");
- } else {
- if (NumXMMRegs < 4) {
- RegsToPass.push_back(std::make_pair(XMMArgRegs[NumXMMRegs], Arg));
- NumXMMRegs++;
- } else {
- // XMM arguments have to be aligned on 16-byte boundary.
- ArgOffset = ((ArgOffset + 15) / 16) * 16;
- SDOperand PtrOff = DAG.getConstant(ArgOffset, getPointerTy());
- PtrOff = DAG.getNode(ISD::ADD, getPointerTy(), StackPtr, PtrOff);
- MemOpChains.push_back(DAG.getStore(Chain, Arg, PtrOff, NULL, 0));
- ArgOffset += 16;
- }
- }
- break;
+ assert(!isFastCall && "Unexpected ValueType for argument!");
+ if (NumXMMRegs < 4) {
+ RegsToPass.push_back(std::make_pair(XMMArgRegs[NumXMMRegs], Arg));
+ NumXMMRegs++;
+ } else {
+ // XMM arguments have to be aligned on 16-byte boundary.
+ ArgOffset = ((ArgOffset + 15) / 16) * 16;
+ SDOperand PtrOff = DAG.getConstant(ArgOffset, getPointerTy());
+ PtrOff = DAG.getNode(ISD::ADD, getPointerTy(), StackPtr, PtrOff);
+ MemOpChains.push_back(DAG.getStore(Chain, Arg, PtrOff, NULL, 0));
+ ArgOffset += 16;
+ }
+ break;
}
}
@@ -1721,6 +1783,14 @@ SDOperand X86TargetLowering::LowerFastCCCallTo(SDOperand Op, SelectionDAG &DAG,
} else if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(Callee))
Callee = DAG.getTargetExternalSymbol(S->getSymbol(), getPointerTy());
+ if (getTargetMachine().getRelocationModel() == Reloc::PIC_ &&
+ Subtarget->isPICStyleGOT()) {
+ Chain = DAG.getCopyToReg(Chain, X86::EBX,
+ DAG.getNode(X86ISD::GlobalBaseReg, getPointerTy()),
+ InFlag);
+ InFlag = Chain.getValue(1);
+ }
+
std::vector<MVT::ValueType> NodeTys;
NodeTys.push_back(MVT::Other); // Returns a chain
NodeTys.push_back(MVT::Flag); // Returns a flag for retval copy to use.
@@ -1854,479 +1924,6 @@ SDOperand X86TargetLowering::LowerFastCCCallTo(SDOperand Op, SelectionDAG &DAG,
return Res.getValue(Op.ResNo);
}
-//===----------------------------------------------------------------------===//
-// StdCall Calling Convention implementation
-//===----------------------------------------------------------------------===//
-// StdCall calling convention seems to be standard for many Windows' API
-// routines and around. It differs from C calling convention just a little:
-// callee should clean up the stack, not caller. Symbols should be also
-// decorated in some fancy way :) It doesn't support any vector arguments.
-
-/// HowToPassStdCallCCArgument - Returns how an formal argument of the specified
-/// type should be passed. Returns the size of the stack slot
-static void
-HowToPassStdCallCCArgument(MVT::ValueType ObjectVT, unsigned &ObjSize) {
- switch (ObjectVT) {
- default: assert(0 && "Unhandled argument type!");
- case MVT::i8: ObjSize = 1; break;
- case MVT::i16: ObjSize = 2; break;
- case MVT::i32: ObjSize = 4; break;
- case MVT::i64: ObjSize = 8; break;
- case MVT::f32: ObjSize = 4; break;
- case MVT::f64: ObjSize = 8; break;
- }
-}
-
-SDOperand X86TargetLowering::LowerStdCallCCArguments(SDOperand Op,
- SelectionDAG &DAG) {
- unsigned NumArgs = Op.Val->getNumValues() - 1;
- MachineFunction &MF = DAG.getMachineFunction();
- MachineFrameInfo *MFI = MF.getFrameInfo();
- SDOperand Root = Op.getOperand(0);
- std::vector<SDOperand> ArgValues;
-
- // Add DAG nodes to load the arguments... On entry to a function on the X86,
- // the stack frame looks like this:
- //
- // [ESP] -- return address
- // [ESP + 4] -- first argument (leftmost lexically)
- // [ESP + 8] -- second argument, if first argument is <= 4 bytes in size
- // ...
- //
- unsigned ArgOffset = 0; // Frame mechanisms handle retaddr slot
- for (unsigned i = 0; i < NumArgs; ++i) {
- MVT::ValueType ObjectVT = Op.getValue(i).getValueType();
- unsigned ArgIncrement = 4;
- unsigned ObjSize = 0;
- HowToPassStdCallCCArgument(ObjectVT, ObjSize);
- if (ObjSize > 4)
- ArgIncrement = ObjSize;
-
- SDOperand ArgValue;
- // Create the frame index object for this incoming parameter...
- int FI = MFI->CreateFixedObject(ObjSize, ArgOffset);
- SDOperand FIN = DAG.getFrameIndex(FI, getPointerTy());
- ArgValue = DAG.getLoad(Op.Val->getValueType(i), Root, FIN, NULL, 0);
- ArgValues.push_back(ArgValue);
- ArgOffset += ArgIncrement; // Move on to the next argument...
- }
-
- ArgValues.push_back(Root);
-
- // If the function takes variable number of arguments, make a frame index for
- // the start of the first vararg value... for expansion of llvm.va_start.
- bool isVarArg = cast<ConstantSDNode>(Op.getOperand(2))->getValue() != 0;
- if (isVarArg) {
- BytesToPopOnReturn = 0; // Callee pops nothing.
- BytesCallerReserves = ArgOffset;
- VarArgsFrameIndex = MFI->CreateFixedObject(1, ArgOffset);
- } else {
- BytesToPopOnReturn = ArgOffset; // Callee pops everything..
- BytesCallerReserves = 0;
- }
- RegSaveFrameIndex = 0xAAAAAAA; // X86-64 only.
- ReturnAddrIndex = 0; // No return address slot generated yet.
-
- MF.getInfo<X86FunctionInfo>()->setBytesToPopOnReturn(BytesToPopOnReturn);
-
- // Return the new list of results.
- std::vector<MVT::ValueType> RetVTs(Op.Val->value_begin(),
- Op.Val->value_end());
- return DAG.getNode(ISD::MERGE_VALUES, RetVTs, &ArgValues[0],ArgValues.size());
-}
-
-
-SDOperand X86TargetLowering::LowerStdCallCCCallTo(SDOperand Op,
- SelectionDAG &DAG) {
- SDOperand Chain = Op.getOperand(0);
- bool isVarArg = cast<ConstantSDNode>(Op.getOperand(2))->getValue() != 0;
- bool isTailCall = cast<ConstantSDNode>(Op.getOperand(3))->getValue() != 0;
- SDOperand Callee = Op.getOperand(4);
- MVT::ValueType RetVT= Op.Val->getValueType(0);
- unsigned NumOps = (Op.getNumOperands() - 5) / 2;
-
- // Count how many bytes are to be pushed on the stack.
- unsigned NumBytes = 0;
- for (unsigned i = 0; i != NumOps; ++i) {
- SDOperand Arg = Op.getOperand(5+2*i);
-
- switch (Arg.getValueType()) {
- default: assert(0 && "Unexpected ValueType for argument!");
- case MVT::i8:
- case MVT::i16:
- case MVT::i32:
- case MVT::f32:
- NumBytes += 4;
- break;
- case MVT::i64:
- case MVT::f64:
- NumBytes += 8;
- break;
- }
- }
-
- Chain = DAG.getCALLSEQ_START(Chain,DAG.getConstant(NumBytes, getPointerTy()));
-
- // Arguments go on the stack in reverse order, as specified by the ABI.
- unsigned ArgOffset = 0;
- std::vector<SDOperand> MemOpChains;
- SDOperand StackPtr = DAG.getRegister(X86StackPtr, getPointerTy());
- for (unsigned i = 0; i != NumOps; ++i) {
- SDOperand Arg = Op.getOperand(5+2*i);
-
- switch (Arg.getValueType()) {
- default: assert(0 && "Unexpected ValueType for argument!");
- case MVT::i8:
- case MVT::i16: {
- // Promote the integer to 32 bits. If the input type is signed use a
- // sign extend, otherwise use a zero extend.
- unsigned ExtOp =
- dyn_cast<ConstantSDNode>(Op.getOperand(5+2*i+1))->getValue() ?
- ISD::SIGN_EXTEND : ISD::ZERO_EXTEND;
- Arg = DAG.getNode(ExtOp, MVT::i32, Arg);
- }
- // Fallthrough
-
- case MVT::i32:
- case MVT::f32: {
- SDOperand PtrOff = DAG.getConstant(ArgOffset, getPointerTy());
- PtrOff = DAG.getNode(ISD::ADD, getPointerTy(), StackPtr, PtrOff);
- MemOpChains.push_back(DAG.getStore(Chain, Arg, PtrOff, NULL, 0));
- ArgOffset += 4;
- break;
- }
- case MVT::i64:
- case MVT::f64: {
- SDOperand PtrOff = DAG.getConstant(ArgOffset, getPointerTy());
- PtrOff = DAG.getNode(ISD::ADD, getPointerTy(), StackPtr, PtrOff);
- MemOpChains.push_back(DAG.getStore(Chain, Arg, PtrOff, NULL, 0));
- ArgOffset += 8;
- break;
- }
- }
- }
-
- if (!MemOpChains.empty())
- Chain = DAG.getNode(ISD::TokenFactor, MVT::Other,
- &MemOpChains[0], MemOpChains.size());
-
- // If the callee is a GlobalAddress node (quite common, every direct call is)
- // turn it into a TargetGlobalAddress node so that legalize doesn't hack it.
- if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) {
- // We should use extra load for direct calls to dllimported functions in
- // non-JIT mode.
- if (!Subtarget->GVRequiresExtraLoad(G->getGlobal(),
- getTargetMachine(), true))
- Callee = DAG.getTargetGlobalAddress(G->getGlobal(), getPointerTy());
- } else if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(Callee))
- Callee = DAG.getTargetExternalSymbol(S->getSymbol(), getPointerTy());
-
- std::vector<MVT::ValueType> NodeTys;
- NodeTys.push_back(MVT::Other); // Returns a chain
- NodeTys.push_back(MVT::Flag); // Returns a flag for retval copy to use.
- std::vector<SDOperand> Ops;
- Ops.push_back(Chain);
- Ops.push_back(Callee);
-
- Chain = DAG.getNode(isTailCall ? X86ISD::TAILCALL : X86ISD::CALL,
- NodeTys, &Ops[0], Ops.size());
- SDOperand InFlag = Chain.getValue(1);
-
- // Create the CALLSEQ_END node.
- unsigned NumBytesForCalleeToPush;
-
- if (isVarArg) {
- NumBytesForCalleeToPush = 0;
- } else {
- NumBytesForCalleeToPush = NumBytes;
- }
-
- NodeTys.clear();
- NodeTys.push_back(MVT::Other); // Returns a chain
- if (RetVT != MVT::Other)
- NodeTys.push_back(MVT::Flag); // Returns a flag for retval copy to use.
- Ops.clear();
- Ops.push_back(Chain);
- Ops.push_back(DAG.getConstant(NumBytes, getPointerTy()));
- Ops.push_back(DAG.getConstant(NumBytesForCalleeToPush, getPointerTy()));
- Ops.push_back(InFlag);
- Chain = DAG.getNode(ISD::CALLSEQ_END, NodeTys, &Ops[0], Ops.size());
- if (RetVT != MVT::Other)
- InFlag = Chain.getValue(1);
-
- std::vector<SDOperand> ResultVals;
- NodeTys.clear();
- switch (RetVT) {
- default: assert(0 && "Unknown value type to return!");
- case MVT::Other: break;
- case MVT::i8:
- Chain = DAG.getCopyFromReg(Chain, X86::AL, MVT::i8, InFlag).getValue(1);
- ResultVals.push_back(Chain.getValue(0));
- NodeTys.push_back(MVT::i8);
- break;
- case MVT::i16:
- Chain = DAG.getCopyFromReg(Chain, X86::AX, MVT::i16, InFlag).getValue(1);
- ResultVals.push_back(Chain.getValue(0));
- NodeTys.push_back(MVT::i16);
- break;
- case MVT::i32:
- if (Op.Val->getValueType(1) == MVT::i32) {
- Chain = DAG.getCopyFromReg(Chain, X86::EAX, MVT::i32, InFlag).getValue(1);
- ResultVals.push_back(Chain.getValue(0));
- Chain = DAG.getCopyFromReg(Chain, X86::EDX, MVT::i32,
- Chain.getValue(2)).getValue(1);
- ResultVals.push_back(Chain.getValue(0));
- NodeTys.push_back(MVT::i32);
- } else {
- Chain = DAG.getCopyFromReg(Chain, X86::EAX, MVT::i32, InFlag).getValue(1);
- ResultVals.push_back(Chain.getValue(0));
- }
- NodeTys.push_back(MVT::i32);
- break;
- case MVT::f32:
- case MVT::f64: {
- std::vector<MVT::ValueType> Tys;
- Tys.push_back(MVT::f64);
- Tys.push_back(MVT::Other);
- Tys.push_back(MVT::Flag);
- std::vector<SDOperand> Ops;
- Ops.push_back(Chain);
- Ops.push_back(InFlag);
- SDOperand RetVal = DAG.getNode(X86ISD::FP_GET_RESULT, Tys,
- &Ops[0], Ops.size());
- Chain = RetVal.getValue(1);
- InFlag = RetVal.getValue(2);
- if (X86ScalarSSE) {
- // FIXME: Currently the FST is flagged to the FP_GET_RESULT. This
- // shouldn't be necessary except that RFP cannot be live across
- // multiple blocks. When stackifier is fixed, they can be uncoupled.
- MachineFunction &MF = DAG.getMachineFunction();
- int SSFI = MF.getFrameInfo()->CreateStackObject(8, 8);
- SDOperand StackSlot = DAG.getFrameIndex(SSFI, getPointerTy());
- Tys.clear();
- Tys.push_back(MVT::Other);
- Ops.clear();
- Ops.push_back(Chain);
- Ops.push_back(RetVal);
- Ops.push_back(StackSlot);
- Ops.push_back(DAG.getValueType(RetVT));
- Ops.push_back(InFlag);
- Chain = DAG.getNode(X86ISD::FST, Tys, &Ops[0], Ops.size());
- RetVal = DAG.getLoad(RetVT, Chain, StackSlot, NULL, 0);
- Chain = RetVal.getValue(1);
- }
-
- if (RetVT == MVT::f32 && !X86ScalarSSE)
- // FIXME: we would really like to remember that this FP_ROUND
- // operation is okay to eliminate if we allow excess FP precision.
- RetVal = DAG.getNode(ISD::FP_ROUND, MVT::f32, RetVal);
- ResultVals.push_back(RetVal);
- NodeTys.push_back(RetVT);
- break;
- }
- }
-
- // If the function returns void, just return the chain.
- if (ResultVals.empty())
- return Chain;
-
- // Otherwise, merge everything together with a MERGE_VALUES node.
- NodeTys.push_back(MVT::Other);
- ResultVals.push_back(Chain);
- SDOperand Res = DAG.getNode(ISD::MERGE_VALUES, NodeTys,
- &ResultVals[0], ResultVals.size());
- return Res.getValue(Op.ResNo);
-}
-
-//===----------------------------------------------------------------------===//
-// FastCall Calling Convention implementation
-//===----------------------------------------------------------------------===//
-//
-// The X86 'fastcall' calling convention passes up to two integer arguments in
-// registers (an appropriate portion of ECX/EDX), passes arguments in C order,
-// and requires that the callee pop its arguments off the stack (allowing proper
-// tail calls), and has the same return value conventions as C calling convs.
-//
-// This calling convention always arranges for the callee pop value to be 8n+4
-// bytes, which is needed for tail recursion elimination and stack alignment
-// reasons.
-//
-
-/// HowToPassFastCallCCArgument - Returns how an formal argument of the
-/// specified type should be passed. If it is through stack, returns the size of
-/// the stack slot; if it is through integer register, returns the number of
-/// integer registers are needed.
-static void
-HowToPassFastCallCCArgument(MVT::ValueType ObjectVT,
- unsigned NumIntRegs,
- unsigned &ObjSize,
- unsigned &ObjIntRegs)
-{
- ObjSize = 0;
- ObjIntRegs = 0;
-
- switch (ObjectVT) {
- default: assert(0 && "Unhandled argument type!");
- case MVT::i8:
- if (NumIntRegs < 2)
- ObjIntRegs = 1;
- else
- ObjSize = 1;
- break;
- case MVT::i16:
- if (NumIntRegs < 2)
- ObjIntRegs = 1;
- else
- ObjSize = 2;
- break;
- case MVT::i32:
- if (NumIntRegs < 2)
- ObjIntRegs = 1;
- else
- ObjSize = 4;
- break;
- case MVT::i64:
- if (NumIntRegs+2 <= 2) {
- ObjIntRegs = 2;
- } else if (NumIntRegs+1 <= 2) {
- ObjIntRegs = 1;
- ObjSize = 4;
- } else
- ObjSize = 8;
- case MVT::f32:
- ObjSize = 4;
- break;
- case MVT::f64:
- ObjSize = 8;
- break;
- }
-}
-
-SDOperand
-X86TargetLowering::LowerFastCallCCArguments(SDOperand Op, SelectionDAG &DAG) {
- unsigned NumArgs = Op.Val->getNumValues()-1;
- MachineFunction &MF = DAG.getMachineFunction();
- MachineFrameInfo *MFI = MF.getFrameInfo();
- SDOperand Root = Op.getOperand(0);
- std::vector<SDOperand> ArgValues;
-
- // Add DAG nodes to load the arguments... On entry to a function the stack
- // frame looks like this:
- //
- // [ESP] -- return address
- // [ESP + 4] -- first nonreg argument (leftmost lexically)
- // [ESP + 8] -- second nonreg argument, if 1st argument is <= 4 bytes in size
- // ...
- unsigned ArgOffset = 0; // Frame mechanisms handle retaddr slot
-
- // Keep track of the number of integer regs passed so far. This can be either
- // 0 (neither ECX or EDX used), 1 (ECX is used) or 2 (ECX and EDX are both
- // used).
- unsigned NumIntRegs = 0;
-
- for (unsigned i = 0; i < NumArgs; ++i) {
- MVT::ValueType ObjectVT = Op.getValue(i).getValueType();
- unsigned ArgIncrement = 4;
- unsigned ObjSize = 0;
- unsigned ObjIntRegs = 0;
-
- HowToPassFastCallCCArgument(ObjectVT, NumIntRegs, ObjSize, ObjIntRegs);
- if (ObjSize > 4)
- ArgIncrement = ObjSize;
-
- unsigned Reg = 0;
- SDOperand ArgValue;
- if (ObjIntRegs) {
- switch (ObjectVT) {
- default: assert(0 && "Unhandled argument type!");
- case MVT::i8:
- Reg = AddLiveIn(MF, NumIntRegs ? X86::DL : X86::CL,
- X86::GR8RegisterClass);
- ArgValue = DAG.getCopyFromReg(Root, Reg, MVT::i8);
- break;
- case MVT::i16:
- Reg = AddLiveIn(MF, NumIntRegs ? X86::DX : X86::CX,
- X86::GR16RegisterClass);
- ArgValue = DAG.getCopyFromReg(Root, Reg, MVT::i16);
- break;
- case MVT::i32:
- Reg = AddLiveIn(MF, NumIntRegs ? X86::EDX : X86::ECX,
- X86::GR32RegisterClass);
- ArgValue = DAG.getCopyFromReg(Root, Reg, MVT::i32);
- break;
- case MVT::i64:
- Reg = AddLiveIn(MF, NumIntRegs ? X86::EDX : X86::ECX,
- X86::GR32RegisterClass);
- ArgValue = DAG.getCopyFromReg(Root, Reg, MVT::i32);
- if (ObjIntRegs == 2) {
- Reg = AddLiveIn(MF, X86::EDX, X86::GR32RegisterClass);
- SDOperand ArgValue2 = DAG.getCopyFromReg(Root, Reg, MVT::i32);
- ArgValue= DAG.getNode(ISD::BUILD_PAIR, MVT::i64, ArgValue, ArgValue2);
- }
- break;
- }
-
- NumIntRegs += ObjIntRegs;
- }
-
- if (ObjSize) {
- // Create the SelectionDAG nodes corresponding to a load from this
- // parameter.
- int FI = MFI->CreateFixedObject(ObjSize, ArgOffset);
- SDOperand FIN = DAG.getFrameIndex(FI, getPointerTy());
- if (ObjectVT == MVT::i64 && ObjIntRegs) {
- SDOperand ArgValue2 = DAG.getLoad(Op.Val->getValueType(i), Root, FIN,
- NULL, 0);
- ArgValue = DAG.getNode(ISD::BUILD_PAIR, MVT::i64, ArgValue, ArgValue2);
- } else
- ArgValue = DAG.getLoad(Op.Val->getValueType(i), Root, FIN, NULL, 0);
- ArgOffset += ArgIncrement; // Move on to the next argument.
- }
-
- ArgValues.push_back(ArgValue);
- }
-
- ArgValues.push_back(Root);
-
- // Make sure the instruction takes 8n+4 bytes to make sure the start of the
- // arguments and the arguments after the retaddr has been pushed are aligned.
- if ((ArgOffset & 7) == 0)
- ArgOffset += 4;
-
- VarArgsFrameIndex = 0xAAAAAAA; // fastcc functions can't have varargs.
- RegSaveFrameIndex = 0xAAAAAAA; // X86-64 only.
- ReturnAddrIndex = 0; // No return address slot generated yet.
- BytesToPopOnReturn = ArgOffset; // Callee pops all stack arguments.
- BytesCallerReserves = 0;
-
- MF.getInfo<X86FunctionInfo>()->setBytesToPopOnReturn(BytesToPopOnReturn);
-
- // Finally, inform the code generator which regs we return values in.
- switch (getValueType(MF.getFunction()->getReturnType())) {
- default: assert(0 && "Unknown type!");
- case MVT::isVoid: break;
- case MVT::i1:
- case MVT::i8:
- case MVT::i16:
- case MVT::i32:
- MF.addLiveOut(X86::ECX);
- break;
- case MVT::i64:
- MF.addLiveOut(X86::ECX);
- MF.addLiveOut(X86::EDX);
- break;
- case MVT::f32:
- case MVT::f64:
- MF.addLiveOut(X86::ST0);
- break;
- }
-
- // Return the new list of results.
- std::vector<MVT::ValueType> RetVTs(Op.Val->value_begin(),
- Op.Val->value_end());
- return DAG.getNode(ISD::MERGE_VALUES, RetVTs, &ArgValues[0],ArgValues.size());
-}
-
SDOperand X86TargetLowering::getReturnAddressFrameIndex(SelectionDAG &DAG) {
if (ReturnAddrIndex == 0) {
// Set up a frame object for the return address.
@@ -4367,14 +3964,13 @@ SDOperand X86TargetLowering::LowerCALL(SDOperand Op, SelectionDAG &DAG) {
assert(0 && "Unsupported calling convention");
case CallingConv::Fast:
if (EnableFastCC) {
- return LowerFastCCCallTo(Op, DAG, false);
+ return LowerFastCCCallTo(Op, DAG);
}
// Falls through
case CallingConv::C:
- case CallingConv::CSRet:
return LowerCCCCallTo(Op, DAG);
case CallingConv::X86_StdCall:
- return LowerStdCallCCCallTo(Op, DAG);
+ return LowerCCCCallTo(Op, DAG, true);
case CallingConv::X86_FastCall:
return LowerFastCCCallTo(Op, DAG, true);
}
@@ -4505,14 +4101,13 @@ X86TargetLowering::LowerFORMAL_ARGUMENTS(SDOperand Op, SelectionDAG &DAG) {
}
// Falls through
case CallingConv::C:
- case CallingConv::CSRet:
return LowerCCCArguments(Op, DAG);
case CallingConv::X86_StdCall:
MF.getInfo<X86FunctionInfo>()->setDecorationStyle(StdCall);
- return LowerStdCallCCArguments(Op, DAG);
+ return LowerCCCArguments(Op, DAG, true);
case CallingConv::X86_FastCall:
MF.getInfo<X86FunctionInfo>()->setDecorationStyle(FastCall);
- return LowerFastCallCCArguments(Op, DAG);
+ return LowerFastCCArguments(Op, DAG, true);
}
}
@@ -4535,11 +4130,15 @@ SDOperand X86TargetLowering::LowerMEMSET(SDOperand Op, SelectionDAG &DAG) {
Entry.Node = Op.getOperand(1);
Entry.Ty = IntPtrTy;
Entry.isSigned = false;
+ Entry.isInReg = false;
+ Entry.isSRet = false;
Args.push_back(Entry);
// Extend the unsigned i8 argument to be an int value for the call.
Entry.Node = DAG.getNode(ISD::ZERO_EXTEND, MVT::i32, Op.getOperand(2));
Entry.Ty = IntPtrTy;
Entry.isSigned = false;
+ Entry.isInReg = false;
+ Entry.isSRet = false;
Args.push_back(Entry);
Entry.Node = Op.getOperand(3);
Args.push_back(Entry);
@@ -4693,7 +4292,10 @@ SDOperand X86TargetLowering::LowerMEMCPY(SDOperand Op, SelectionDAG &DAG) {
MVT::ValueType IntPtr = getPointerTy();
TargetLowering::ArgListTy Args;
TargetLowering::ArgListEntry Entry;
- Entry.Ty = getTargetData()->getIntPtrType(); Entry.isSigned = false;
+ Entry.Ty = getTargetData()->getIntPtrType();
+ Entry.isSigned = false;
+ Entry.isInReg = false;
+ Entry.isSRet = false;
Entry.Node = Op.getOperand(1); Args.push_back(Entry);
Entry.Node = Op.getOperand(2); Args.push_back(Entry);
Entry.Node = Op.getOperand(3); Args.push_back(Entry);
diff --git a/lib/Target/X86/X86ISelLowering.h b/lib/Target/X86/X86ISelLowering.h
index b120a1432b..a9df1f8a66 100644
--- a/lib/Target/X86/X86ISelLowering.h
+++ b/lib/Target/X86/X86ISelLowering.h
@@ -364,25 +364,21 @@ namespace llvm {
/// X86ScalarSSE - Select between SSE2 or x87 floating point ops.
bool X86ScalarSSE;
- // C Calling Convention implementation.
- SDOperand LowerCCCArguments(SDOperand Op, SelectionDAG &DAG);
- SDOperand LowerCCCCallTo(SDOperand Op, SelectionDAG &DAG);
+ // C and StdCall Calling Convention implementation.
+ SDOperand LowerCCCArguments(SDOperand Op, SelectionDAG &DAG,
+ bool isStdCall = false);
+ SDOperand LowerCCCCallTo(SDOperand Op, SelectionDAG &DAG,
+ bool isStdCall = false);
// X86-64 C Calling Convention implementation.
SDOperand LowerX86_64CCCArguments(SDOperand Op, SelectionDAG &DAG);
SDOperand LowerX86_64CCCCallTo(SDOperand Op, SelectionDAG &DAG);
- // Fast Calling Convention implementation.
- SDOperand LowerFastCCArguments(SDOperand Op, SelectionDAG &DAG);
+ // Fast and FastCall Calling Convention implementation.
+ SDOperand LowerFastCCArguments(SDOperand Op, SelectionDAG &DAG,
+ bool isFastCall = false);
SDOperand LowerFastCCCallTo(SDOperand Op, SelectionDAG &DAG,
- bool isFastCall);
-
- // StdCall Calling Convention implementation.
- SDOperand LowerStdCallCCArguments(SDOperand Op, SelectionDAG &DAG);
- SDOperand LowerStdCallCCCallTo(SDOperand Op, SelectionDAG &DAG);
-
- // FastCall Calling Convention implementation.
- SDOperand LowerFastCallCCArguments(SDOperand Op, SelectionDAG &DAG);
+ bool isFastCall = false);
SDOperand LowerBUILD_VECTOR(SDOperand Op, SelectionDAG &DAG);
SDOperand LowerVECTOR_SHUFFLE(SDOperand Op, SelectionDAG &DAG);
diff --git a/lib/Target/X86/X86Subtarget.cpp b/lib/Target/X86/X86Subtarget.cpp
index 4af00859e3..50746d7e1c 100644
--- a/lib/Target/X86/X86Subtarget.cpp
+++ b/lib/Target/X86/X86Subtarget.cpp
@@ -35,6 +35,7 @@ bool X86Subtarget::GVRequiresExtraLoad(const GlobalValue* GV,
const TargetMachine& TM,
bool isDirectCall) const
{
+ // FIXME: PIC
if (TM.getRelocationModel() != Reloc::Static)
if (isTargetDarwin()) {
return (!isDirectCall &&
diff --git a/lib/Transforms/IPO/DeadArgumentElimination.cpp b/lib/Transforms/IPO/DeadArgumentElimination.cpp
index 840533f968..d83f3e027d 100644
--- a/lib/Transforms/IPO/DeadArgumentElimination.cpp
+++ b/lib/Transforms/IPO/DeadArgumentElimination.cpp
@@ -230,9 +230,10 @@ static inline bool CallPassesValueThoughVararg(Instruction *Call,
// (used in a computation), MaybeLive (only passed as an argument to a call), or
// Dead (not used).
DAE::Liveness DAE::getArgumentLiveness(const Argument &A) {
- // If this is the return value of a csret function, it's not really dead.
- if (A.getParent()->getCallingConv() == CallingConv::CSRet &&
- &*A.getParent()->arg_begin() == &A)
+ const FunctionType *FTy = A.getParent()->getFunctionType();
+
+ // If this is the return value of a struct function, it's not really dead.
+ if (FTy->isStructReturn() && &*A.getParent()->arg_begin() == &A)
return Live;
if (A.use_empty()) // First check, directly dead?
diff --git a/lib/Transforms/IPO/ExtractFunction.cpp b/lib/Transforms/IPO/ExtractFunction.cpp
index a871c4d7f2..3246cd96bb 100644
--- a/lib/Transforms/IPO/ExtractFunction.cpp
+++ b/lib/Transforms/IPO/ExtractFunction.cpp
@@ -11,6 +11,7 @@
//
//===----------------------------------------------------------------------===//
+#include "llvm/Instructions.h"
#include "llvm/Module.h"
#include "llvm/Pass.h"
#include "llvm/Transforms/IPO.h"
@@ -20,13 +21,15 @@ namespace {
class FunctionExtractorPass : public ModulePass {
Function *Named;
bool deleteFunc;
+ bool reLink;
public:
/// FunctionExtractorPass - If deleteFn is true, this pass deletes as the
/// specified function. Otherwise, it deletes as much of the module as
/// possible, except for the function specified.
///
- FunctionExtractorPass(Function *F = 0, bool deleteFn = true)
- : Named(F), deleteFunc(deleteFn) {}
+ FunctionExtractorPass(Function *F = 0, bool deleteFn = true,
+ bool relinkCallees = false)
+ : Named(F), deleteFunc(deleteFn), reLink(relinkCallees) {}
bool runOnModule(Module &M) {
if (Named == 0) {
@@ -41,6 +44,23 @@ namespace {
}
bool deleteFunction() {
+ // If we're in relinking mode, set linkage of all internal callees to
+ // external. This will allow us extract function, and then - link
+ // everything together
+ if (reLink) {
+ for (Function::iterator B = Named->begin(), BE = Named->end();
+ B != BE; ++B) {
+ for (BasicBlock::iterator I = B->begin(), E = B->end();
+ I != E; ++I) {
+ if (CallInst* callInst = dyn_cast<CallInst>(&*I)) {
+ Function* Callee = callInst->getCalledFunction();
+ if (Callee && Callee->hasInternalLinkage())
+ Callee->setLinkage(GlobalValue::ExternalLinkage);
+ }
+ }
+ }
+ }
+
Named->setLinkage(GlobalValue::ExternalLinkage);
Named->deleteBody();
assert(Named->isExternal() && "This didn't make the function external!");
@@ -113,6 +133,7 @@ namespace {
RegisterPass<FunctionExtractorPass> X("extract", "Function Extractor");
}
-ModulePass *llvm::createFunctionExtractionPass(Function *F, bool deleteFn) {
- return new FunctionExtractorPass(F, deleteFn);
+ModulePass *llvm::createFunctionExtractionPass(Function *F, bool deleteFn,
+ bool relinkCallees) {
+ return new FunctionExtractorPass(F, deleteFn, relinkCallees);
}
diff --git a/lib/VMCore/AsmWriter.cpp b/lib/VMCore/AsmWriter.cpp
index 24fbb698db..97dc16cdf2 100644
--- a/lib/VMCore/AsmWriter.cpp
+++ b/lib/VMCore/AsmWriter.cpp
@@ -956,7 +956,6 @@ void AssemblyWriter::printFunction(const Function *F) {
// Print the calling convention.
switch (F->getCallingConv()) {
case CallingConv::C: break; // default
- case CallingConv::CSRet: Out << "csretcc "; break;
case CallingConv::Fast: Out << "fastcc "; break;
case CallingConv::Cold: Out << "coldcc "; break;
case CallingConv::X86_StdCall: Out << "x86_stdcallcc "; break;
@@ -1166,7 +1165,6 @@ void AssemblyWriter::printInstruction(const Instruction &I) {
// Print the calling convention being used.
switch (CI->getCallingConv()) {
case CallingConv::C: break; // default
- case CallingConv::CSRet: Out << " csretcc"; break;
case CallingConv::Fast: Out << " fastcc"; break;
case CallingConv::Cold: Out << " coldcc"; break;
case CallingConv::X86_StdCall: Out << "x86_stdcallcc "; break;
@@ -1209,7 +1207,6 @@ void AssemblyWriter::printInstruction(const Instruction &I) {
// Print the calling convention being used.
switch (II->getCallingConv()) {
case CallingConv::C: break; // default
- case CallingConv::CSRet: Out << " csretcc"; break;
case CallingConv::Fast: Out << " fastcc"; break;
case CallingConv::Cold: Out << " coldcc"; break;
case CallingConv::X86_StdCall: Out << "x86_stdcallcc "; break;
diff --git a/lib/VMCore/Type.cpp b/lib/VMCore/Type.cpp
index ec7aee8031..3733d2a7ba 100644
--- a/lib/VMCore/Type.cpp
+++ b/lib/VMCore/Type.cpp
@@ -1089,6 +1089,10 @@ std::string FunctionType::getParamAttrsText(ParameterAttributes Attr) {
Result += "sext ";
if (Attr & NoReturnAttribute)
Result += "noreturn ";
+ if (Attr & InRegAttribute)
+ Result += "inreg ";
+ if (Attr & StructRetAttribute)
+ Result += "sret ";
return Result;
}
diff --git a/lib/VMCore/Verifier.cpp b/lib/VMCore/Verifier.cpp
index d1593173f3..4f67889e9d 100644
--- a/lib/VMCore/Verifier.cpp
+++ b/lib/VMCore/Verifier.cpp
@@ -338,17 +338,17 @@ void Verifier::visitFunction(Function &F) {
F.getReturnType() == Type::VoidTy,
"Functions cannot return aggregate values!", &F);
+ Assert1(!FT->isStructReturn() ||
+ (FT->getReturnType() == Type::VoidTy &&
+ FT->getNumParams() > 0 && isa<PointerType>(FT->getParamType(0))),
+ "Invalid struct-return function!", &F);
+
// Check that this function meets the restrictions on this calling convention.
switch (F.getCallingConv()) {
default:
break;
case CallingConv::C:
break;
- case CallingConv::CSRet:
- Assert1(FT->getReturnType() == Type::VoidTy &&
- FT->getNumParams() > 0 && isa<PointerType>(FT->getParamType(0)),
- "Invalid struct-return function!", &F);
- break;
case CallingConv::Fast:
case CallingConv::Cold:
case CallingConv::X86_FastCall:
diff --git a/tools/llvm-extract/llvm-extract.cpp b/tools/llvm-extract/llvm-extract.cpp
index 882455fc27..766860fd4f 100644
--- a/tools/llvm-extract/llvm-extract.cpp
+++ b/tools/llvm-extract/llvm-extract.cpp
@@ -42,6 +42,10 @@ Force("f", cl::desc("Overwrite output files"));
static cl::opt<bool>
DeleteFn("delete", cl::desc("Delete specified function from Module"));
+static cl::opt<bool>
+Relink("relink",
+ cl::desc("Turn external linkage for callees of function to delete"));
+
// ExtractFunc - The function to extract from the module... defaults to main.
static cl::opt<std::string>
ExtractFunc("func", cl::desc("Specify function to extract"), cl::init("main"),
@@ -72,8 +76,9 @@ int main(int argc, char **argv) {
PassManager Passes;
Passes.add(new TargetData(M.get())); // Use correct TargetData
// Either isolate the function or delete it from the Module
- Passes.add(createFunctionExtractionPass(F, DeleteFn));
- Passes.add(createGlobalDCEPass()); // Delete unreachable globals
+ Passes.add(createFunctionExtractionPass(F, DeleteFn, Relink));
+ if (!DeleteFn)
+ Passes.add(createGlobalDCEPass()); // Delete unreachable globals
Passes.add(createFunctionResolvingPass()); // Delete prototypes
Passes.add(createDeadTypeEliminationPass()); // Remove dead types...