diff options
Diffstat (limited to 'lib/Target/X86/X86ISelLowering.cpp')
-rw-r--r-- | lib/Target/X86/X86ISelLowering.cpp | 1096 |
1 files changed, 349 insertions, 747 deletions
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); |