diff options
24 files changed, 502 insertions, 838 deletions
diff --git a/include/llvm/CallingConv.h b/include/llvm/CallingConv.h index e6ffd28..4bacb1d 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 faa0e35..11c6ad6 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 c1e3a98..06f3a98 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 34bc3ad..49d6624 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 44ffa47..b24857e 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 e688868..96eedff 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 e688868..96eedff 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 03832e7..a5c4b67 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 03832e7..a5c4b67 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 5f5f0d3..84754ce 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 12c5d8e..c1d7000 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 594a48e..e2268d2 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 9faba6b..0c80813 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 097ca91..041ff36 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 5c28fac..ff85828 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 9f9fb72..0dce6fd 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 b120a14..a9df1f8 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 4af0085..50746d7 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 840533f..d83f3e0 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 a871c4d..3246cd9 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 24fbb69..97dc16c 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 ec7aee8..3733d2a 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 d159317..4f67889 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 882455f..766860f 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... |