summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorChris Lattner <sabre@nondot.org>2005-05-14 08:48:15 +0000
committerChris Lattner <sabre@nondot.org>2005-05-14 08:48:15 +0000
commit239738a1620815b83097a4ac1bba9609c9eb2af8 (patch)
treede8403cb841c0d339a54a57680de8804e34e7f02 /lib
parent2789bde57f4245f4418a2d8d54e7f372b71f0a7d (diff)
downloadllvm-239738a1620815b83097a4ac1bba9609c9eb2af8.tar.gz
llvm-239738a1620815b83097a4ac1bba9609c9eb2af8.tar.bz2
llvm-239738a1620815b83097a4ac1bba9609c9eb2af8.tar.xz
Use target-specific nodes for calls. This allows the fastcc code to not have
to do ugly hackery to avoid emitting code like this: call foo mov vreg, EAX adjcallstackup ... If foo is a fastcc call and if vreg gets spilled, we might end up with this: call foo mov [ESP+offset], EAX ;; Offset doesn't consider the 12! sub ESP, 12 Which is bad. The previous hacky code to deal with this was A) gross B) not good enough. In particular, it could miss cases and emit the bad code above. Now we always emit this: call foo adjcallstackup ... mov vreg, EAX directly. This makes fastcc with callees poping the stack work much better. Next stop (finally!) really is tail calls. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@22021 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r--lib/Target/X86/X86ISelPattern.cpp287
1 files changed, 182 insertions, 105 deletions
diff --git a/lib/Target/X86/X86ISelPattern.cpp b/lib/Target/X86/X86ISelPattern.cpp
index efdb24419a..66bbe6f5aa 100644
--- a/lib/Target/X86/X86ISelPattern.cpp
+++ b/lib/Target/X86/X86ISelPattern.cpp
@@ -51,6 +51,29 @@ namespace {
/// the X86::FILD64m instruction. It has two inputs (token chain and
/// address) and two outputs (FP value and token chain).
FILD64m,
+
+ /// CALL/TAILCALL - These operations represent an abstract X86 call
+ /// instruction, which includes a bunch of information. In particular the
+ /// operands of these node are:
+ ///
+ /// #0 - The incoming token chain
+ /// #1 - The callee
+ /// #2 - The number of arg bytes the caller pushes on the stack.
+ /// #3 - The number of arg bytes the callee pops off the stack.
+ /// #4 - The value to pass in AL/AX/EAX (optional)
+ /// #5 - The value to pass in DL/DX/EDX (optional)
+ ///
+ /// The result values of these nodes are:
+ ///
+ /// #0 - The outgoing token chain
+ /// #1 - The first register result value (optional)
+ /// #2 - The second register result value (optional)
+ ///
+ /// The CALL vs TAILCALL distinction boils down to whether the callee is
+ /// known not to modify the caller's stack frame, as is standard with
+ /// LLVM.
+ CALL,
+ TAILCALL,
};
}
}
@@ -355,17 +378,59 @@ X86TargetLowering::LowerCCCCallTo(SDOperand Chain, const Type *RetTy,
std::vector<MVT::ValueType> RetVals;
MVT::ValueType RetTyVT = getValueType(RetTy);
- if (RetTyVT != MVT::isVoid)
- RetVals.push_back(RetTyVT);
RetVals.push_back(MVT::Other);
- SDOperand TheCall = SDOperand(DAG.getCall(RetVals, Chain, Callee,
- isTailCall), 0);
- Chain = TheCall.getValue(RetTyVT != MVT::isVoid);
- Chain = DAG.getNode(ISD::CALLSEQ_END, MVT::Other, Chain,
- DAG.getConstant(NumBytes, getPointerTy()),
- DAG.getConstant(0, getPointerTy()));
- return std::make_pair(TheCall, Chain);
+ // The result values produced have to be legal. Promote the result.
+ switch (RetTyVT) {
+ case MVT::isVoid: break;
+ default:
+ RetVals.push_back(RetTyVT);
+ break;
+ case MVT::i1:
+ case MVT::i8:
+ case MVT::i16:
+ RetVals.push_back(MVT::i32);
+ break;
+ case MVT::f32:
+ RetVals.push_back(MVT::f64);
+ break;
+ case MVT::i64:
+ RetVals.push_back(MVT::i32);
+ RetVals.push_back(MVT::i32);
+ break;
+ }
+ std::vector<SDOperand> Ops;
+ Ops.push_back(Chain);
+ Ops.push_back(Callee);
+ Ops.push_back(DAG.getConstant(NumBytes, getPointerTy()));
+ Ops.push_back(DAG.getConstant(0, getPointerTy()));
+ SDOperand TheCall = DAG.getNode(isTailCall ? X86ISD::TAILCALL : X86ISD::CALL,
+ RetVals, Ops);
+ Chain = DAG.getNode(ISD::CALLSEQ_END, MVT::Other, TheCall);
+
+ SDOperand ResultVal;
+ switch (RetTyVT) {
+ case MVT::isVoid: break;
+ default:
+ ResultVal = TheCall.getValue(1);
+ break;
+ case MVT::i1:
+ case MVT::i8:
+ case MVT::i16:
+ ResultVal = DAG.getNode(ISD::TRUNCATE, RetTyVT, TheCall.getValue(1));
+ break;
+ case MVT::f32:
+ // FIXME: we would really like to remember that this FP_ROUND operation is
+ // okay to eliminate if we allow excess FP precision.
+ ResultVal = DAG.getNode(ISD::FP_ROUND, MVT::f32, TheCall.getValue(1));
+ break;
+ case MVT::i64:
+ ResultVal = DAG.getNode(ISD::BUILD_PAIR, MVT::i64, TheCall.getValue(1),
+ TheCall.getValue(2));
+ break;
+ }
+
+ return std::make_pair(ResultVal, Chain);
}
std::pair<SDOperand, SDOperand>
@@ -705,26 +770,73 @@ X86TargetLowering::LowerFastCCCallTo(SDOperand Chain, const Type *RetTy,
if (!Stores.empty())
Chain = DAG.getNode(ISD::TokenFactor, MVT::Other, Stores);
+ // 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;
+
std::vector<MVT::ValueType> RetVals;
MVT::ValueType RetTyVT = getValueType(RetTy);
- if (RetTyVT != MVT::isVoid)
- RetVals.push_back(RetTyVT);
+
RetVals.push_back(MVT::Other);
- SDOperand TheCall = SDOperand(DAG.getCall(RetVals, Chain, Callee,
- RegValuesToPass, isTailCall), 0);
- Chain = TheCall.getValue(RetTyVT != MVT::isVoid);
+ // The result values produced have to be legal. Promote the result.
+ switch (RetTyVT) {
+ case MVT::isVoid: break;
+ default:
+ RetVals.push_back(RetTyVT);
+ break;
+ case MVT::i1:
+ case MVT::i8:
+ case MVT::i16:
+ RetVals.push_back(MVT::i32);
+ break;
+ case MVT::f32:
+ RetVals.push_back(MVT::f64);
+ break;
+ case MVT::i64:
+ RetVals.push_back(MVT::i32);
+ RetVals.push_back(MVT::i32);
+ break;
+ }
+
+ std::vector<SDOperand> Ops;
+ Ops.push_back(Chain);
+ Ops.push_back(Callee);
+ Ops.push_back(DAG.getConstant(ArgOffset, getPointerTy()));
+ // Callee pops all arg values on the stack.
+ Ops.push_back(DAG.getConstant(ArgOffset, getPointerTy()));
- // 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;
+ // Pass register arguments as needed.
+ Ops.insert(Ops.end(), RegValuesToPass.begin(), RegValuesToPass.end());
- Chain = DAG.getNode(ISD::CALLSEQ_END, MVT::Other, Chain,
- DAG.getConstant(ArgOffset, getPointerTy()),
- // The callee pops the arguments off the stack.
- DAG.getConstant(ArgOffset, getPointerTy()));
- return std::make_pair(TheCall, Chain);
+ SDOperand TheCall = DAG.getNode(isTailCall ? X86ISD::TAILCALL : X86ISD::CALL,
+ RetVals, Ops);
+ Chain = DAG.getNode(ISD::CALLSEQ_END, MVT::Other, TheCall);
+
+ SDOperand ResultVal;
+ switch (RetTyVT) {
+ case MVT::isVoid: break;
+ default:
+ ResultVal = TheCall.getValue(1);
+ break;
+ case MVT::i1:
+ case MVT::i8:
+ case MVT::i16:
+ ResultVal = DAG.getNode(ISD::TRUNCATE, RetTyVT, TheCall.getValue(1));
+ break;
+ case MVT::f32:
+ // FIXME: we would really like to remember that this FP_ROUND operation is
+ // okay to eliminate if we allow excess FP precision.
+ ResultVal = DAG.getNode(ISD::FP_ROUND, MVT::f32, TheCall.getValue(1));
+ break;
+ case MVT::i64:
+ ResultVal = DAG.getNode(ISD::BUILD_PAIR, MVT::i64, TheCall.getValue(1),
+ TheCall.getValue(2));
+ break;
+ }
+
+ return std::make_pair(ResultVal, Chain);
}
@@ -1876,18 +1988,18 @@ unsigned ISel::SelectExpr(SDOperand N) {
Reg = Result = (N.getValueType() != MVT::Other) ?
MakeReg(N.getValueType()) : 1;
break;
- case ISD::TAILCALL:
- case ISD::CALL:
+ case X86ISD::TAILCALL:
+ case X86ISD::CALL:
// If this is a call instruction, make sure to prepare ALL of the result
// values as well as the chain.
- if (Node->getNumValues() == 1)
- Reg = Result = 1; // Void call, just a chain.
- else {
- Result = MakeReg(Node->getValueType(0));
- ExprMap[N.getValue(0)] = Result;
- for (unsigned i = 1, e = N.Val->getNumValues()-1; i != e; ++i)
+ ExprMap[N.getValue(0)] = 1;
+ if (Node->getNumValues() > 1) {
+ Result = MakeReg(Node->getValueType(1));
+ ExprMap[N.getValue(1)] = Result;
+ for (unsigned i = 2, e = Node->getNumValues(); i != e; ++i)
ExprMap[N.getValue(i)] = MakeReg(Node->getValueType(i));
- ExprMap[SDOperand(Node, Node->getNumValues()-1)] = 1;
+ } else {
+ Result = 1;
}
break;
case ISD::ADD_PARTS:
@@ -3160,10 +3272,10 @@ unsigned ISel::SelectExpr(SDOperand N) {
BuildMI(BB, X86::MOV32rr, 1, Result).addReg(X86::ESP);
return Result;
- case ISD::TAILCALL:
- case ISD::CALL: {
+ case X86ISD::TAILCALL:
+ case X86ISD::CALL: {
// The chain for this call is now lowered.
- ExprMap.insert(std::make_pair(N.getValue(Node->getNumValues()-1), 1));
+ ExprMap.insert(std::make_pair(N.getValue(0), 1));
bool isDirect = isa<GlobalAddressSDNode>(N.getOperand(1)) ||
isa<ExternalSymbolSDNode>(N.getOperand(1));
@@ -3181,13 +3293,13 @@ unsigned ISel::SelectExpr(SDOperand N) {
}
// If this call has values to pass in registers, do so now.
- if (Node->getNumOperands() > 2) {
+ if (Node->getNumOperands() > 4) {
// The first value is passed in (a part of) EAX, the second in EDX.
- unsigned RegOp1 = SelectExpr(N.getOperand(2));
+ unsigned RegOp1 = SelectExpr(N.getOperand(4));
unsigned RegOp2 =
- Node->getNumOperands() > 3 ? SelectExpr(N.getOperand(3)) : 0;
+ Node->getNumOperands() > 5 ? SelectExpr(N.getOperand(5)) : 0;
- switch (N.getOperand(2).getValueType()) {
+ switch (N.getOperand(4).getValueType()) {
default: assert(0 && "Bad thing to pass in regs");
case MVT::i1:
case MVT::i8: BuildMI(BB, X86::MOV8rr , 1,X86::AL).addReg(RegOp1); break;
@@ -3195,7 +3307,7 @@ unsigned ISel::SelectExpr(SDOperand N) {
case MVT::i32: BuildMI(BB, X86::MOV32rr, 1,X86::EAX).addReg(RegOp1);break;
}
if (RegOp2)
- switch (N.getOperand(3).getValueType()) {
+ switch (N.getOperand(5).getValueType()) {
default: assert(0 && "Bad thing to pass in regs");
case MVT::i1:
case MVT::i8:
@@ -3228,27 +3340,34 @@ unsigned ISel::SelectExpr(SDOperand N) {
BuildMI(BB, X86::CALL32r, 1).addReg(Tmp1);
}
- switch (Node->getValueType(0)) {
- default: assert(0 && "Unknown value type for call result!");
- case MVT::Other: return 1;
- case MVT::i1:
- case MVT::i8:
- BuildMI(BB, X86::MOV8rr, 1, Result).addReg(X86::AL);
- break;
- case MVT::i16:
- BuildMI(BB, X86::MOV16rr, 1, Result).addReg(X86::AX);
- break;
- case MVT::i32:
- BuildMI(BB, X86::MOV32rr, 1, Result).addReg(X86::EAX);
- if (Node->getValueType(1) == MVT::i32)
- BuildMI(BB, X86::MOV32rr, 1, Result+1).addReg(X86::EDX);
- break;
- case MVT::f64: // Floating-point return values live in %ST(0)
- ContainsFPCode = true;
- BuildMI(BB, X86::FpGETRESULT, 1, Result);
- break;
- }
- return Result+N.ResNo;
+
+ // Get caller stack amount and amount the callee added to the stack pointer.
+ Tmp1 = cast<ConstantSDNode>(N.getOperand(2))->getValue();
+ Tmp2 = cast<ConstantSDNode>(N.getOperand(3))->getValue();
+ BuildMI(BB, X86::ADJCALLSTACKUP, 2).addImm(Tmp1).addImm(Tmp2);
+
+ if (Node->getNumValues() != 1)
+ switch (Node->getValueType(1)) {
+ default: assert(0 && "Unknown value type for call result!");
+ case MVT::Other: return 1;
+ case MVT::i1:
+ case MVT::i8:
+ BuildMI(BB, X86::MOV8rr, 1, Result).addReg(X86::AL);
+ break;
+ case MVT::i16:
+ BuildMI(BB, X86::MOV16rr, 1, Result).addReg(X86::AX);
+ break;
+ case MVT::i32:
+ BuildMI(BB, X86::MOV32rr, 1, Result).addReg(X86::EAX);
+ if (Node->getNumValues() == 3 && Node->getValueType(2) == MVT::i32)
+ BuildMI(BB, X86::MOV32rr, 1, Result+1).addReg(X86::EDX);
+ break;
+ case MVT::f64: // Floating-point return values live in %ST(0)
+ ContainsFPCode = true;
+ BuildMI(BB, X86::FpGETRESULT, 1, Result);
+ break;
+ }
+ return Result+N.ResNo-1;
}
case ISD::READPORT:
// First, determine that the size of the operand falls within the acceptable
@@ -3685,9 +3804,9 @@ void ISel::Select(SDOperand N) {
case ISD::EXTLOAD:
case ISD::SEXTLOAD:
case ISD::ZEXTLOAD:
- case ISD::TAILCALL:
- case ISD::CALL:
case ISD::DYNAMIC_STACKALLOC:
+ case X86ISD::TAILCALL:
+ case X86ISD::CALL:
ExprMap.erase(N);
SelectExpr(N);
return;
@@ -3835,48 +3954,6 @@ void ISel::Select(SDOperand N) {
return;
case ISD::CALLSEQ_END:
Select(N.getOperand(0));
- // Stack amount
- Tmp1 = cast<ConstantSDNode>(N.getOperand(1))->getValue();
-
- // Amount the callee added to the stack pointer.
- Tmp2 = cast<ConstantSDNode>(N.getOperand(2))->getValue();
-
- // This hackery is due to the fact that we don't want to emit this code:
- // call foo
- // mov vreg, EAX
- // adjcallstackup
- //
- // Because if foo is a fastcc call and if vreg gets spilled, we might end up
- // with this:
- // call foo
- // mov [ESP+offset], EAX ;; Offset doesn't consider the 12!
- // sub ESP, 12
- //
- // To avoid this, we force the adjcallstackup instruction before the 0, 1 or
- // 2 moves that occur after the call. The correct way to fix this is to use
- // target-specific DAG nodes in the call sequence. FIXME!
- //
- if (EnableFastCC) {
- // This code should be safe. Be defensive for LLVM 1.5 release though.
- assert(!BB->empty());
- MachineBasicBlock::iterator PrevI = --BB->end();
- if (PrevI->getOpcode() == X86::CALLpcrel32 ||
- PrevI->getOpcode() == X86::CALL32r)
- ++PrevI;
- else if (PrevI != BB->begin() &&
- ((--PrevI)->getOpcode() == X86::CALLpcrel32 ||
- PrevI->getOpcode() == X86::CALL32r))
- ++PrevI;
- else if (PrevI != BB->begin() &&
- ((--PrevI)->getOpcode() == X86::CALLpcrel32 ||
- PrevI->getOpcode() == X86::CALL32r))
- ++PrevI;
- else
- PrevI = BB->end();
- BuildMI(*BB, PrevI, X86::ADJCALLSTACKUP, 2).addImm(Tmp1).addImm(Tmp2);
- } else {
- BuildMI(BB, X86::ADJCALLSTACKUP, 2).addImm(Tmp1).addImm(Tmp2);
- }
return;
case ISD::MEMSET: {
Select(N.getOperand(0)); // Select the chain.