[llvm-commits] CVS: llvm/lib/Target/X86/X86ISelPattern.cpp
Chris Lattner
lattner at cs.uiuc.edu
Thu May 12 16:06:45 PDT 2005
Changes in directory llvm/lib/Target/X86:
X86ISelPattern.cpp updated: 1.122 -> 1.123
---
Log message:
Add a new -enable-x86-fastcc option that enables passing the first
two integer values in registers for the fastcc calling conv.
---
Diffs of the changes: (+424 -11)
X86ISelPattern.cpp | 435 +++++++++++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 424 insertions(+), 11 deletions(-)
Index: llvm/lib/Target/X86/X86ISelPattern.cpp
diff -u llvm/lib/Target/X86/X86ISelPattern.cpp:1.122 llvm/lib/Target/X86/X86ISelPattern.cpp:1.123
--- llvm/lib/Target/X86/X86ISelPattern.cpp:1.122 Thu May 12 14:56:45 2005
+++ llvm/lib/Target/X86/X86ISelPattern.cpp Thu May 12 18:06:28 2005
@@ -14,6 +14,7 @@
#include "X86.h"
#include "X86InstrBuilder.h"
#include "X86RegisterInfo.h"
+#include "llvm/CallingConv.h"
#include "llvm/Constants.h"
#include "llvm/Instructions.h"
#include "llvm/Function.h"
@@ -33,6 +34,11 @@
#include <algorithm>
using namespace llvm;
+// FIXME: temporary.
+#include "llvm/Support/CommandLine.h"
+static cl::opt<bool> EnableFastCC("enable-x86-fastcc", cl::Hidden,
+ cl::desc("Enable fastcc on X86"));
+
//===----------------------------------------------------------------------===//
// X86TargetLowering - X86 Implementation of the TargetLowering interface
namespace {
@@ -123,11 +129,46 @@
virtual std::pair<SDOperand, SDOperand>
LowerFrameReturnAddress(bool isFrameAddr, SDOperand Chain, unsigned Depth,
SelectionDAG &DAG);
+ private:
+ // C Calling Convention implementation.
+ std::vector<SDOperand> LowerCCCArguments(Function &F, SelectionDAG &DAG);
+ std::pair<SDOperand, SDOperand>
+ LowerCCCCallTo(SDOperand Chain, const Type *RetTy, bool isVarArg,
+ SDOperand Callee, ArgListTy &Args, SelectionDAG &DAG);
+
+ // Fast Calling Convention implementation.
+ std::vector<SDOperand> LowerFastCCArguments(Function &F, SelectionDAG &DAG);
+ std::pair<SDOperand, SDOperand>
+ LowerFastCCCallTo(SDOperand Chain, const Type *RetTy,
+ SDOperand Callee, ArgListTy &Args, SelectionDAG &DAG);
};
}
std::vector<SDOperand>
X86TargetLowering::LowerArguments(Function &F, SelectionDAG &DAG) {
+ if (F.getCallingConv() == CallingConv::Fast && EnableFastCC)
+ return LowerFastCCArguments(F, DAG);
+ return LowerCCCArguments(F, DAG);
+}
+
+std::pair<SDOperand, SDOperand>
+X86TargetLowering::LowerCallTo(SDOperand Chain, const Type *RetTy,
+ bool isVarArg, unsigned CallingConv,
+ SDOperand Callee, ArgListTy &Args,
+ SelectionDAG &DAG) {
+ assert((!isVarArg || CallingConv == CallingConv::C) &&
+ "Only C takes varargs!");
+ if (CallingConv == CallingConv::Fast && EnableFastCC)
+ return LowerFastCCCallTo(Chain, RetTy, Callee, Args, DAG);
+ return LowerCCCCallTo(Chain, RetTy, isVarArg, Callee, Args, DAG);
+}
+
+//===----------------------------------------------------------------------===//
+// C Calling Convention implementation
+//===----------------------------------------------------------------------===//
+
+std::vector<SDOperand>
+X86TargetLowering::LowerCCCArguments(Function &F, SelectionDAG &DAG) {
std::vector<SDOperand> ArgValues;
MachineFunction &MF = DAG.getMachineFunction();
@@ -208,9 +249,9 @@
}
std::pair<SDOperand, SDOperand>
-X86TargetLowering::LowerCallTo(SDOperand Chain, const Type *RetTy,
- bool isVarArg, unsigned CallingConv,
- SDOperand Callee, ArgListTy &Args, SelectionDAG &DAG) {
+X86TargetLowering::LowerCCCCallTo(SDOperand Chain, const Type *RetTy,
+ bool isVarArg, SDOperand Callee,
+ ArgListTy &Args, SelectionDAG &DAG) {
// Count how many bytes are to be pushed on the stack.
unsigned NumBytes = 0;
@@ -322,6 +363,305 @@
return std::make_pair(Result, Chain);
}
+//===----------------------------------------------------------------------===//
+// Fast Calling Convention implementation
+//===----------------------------------------------------------------------===//
+//
+// The X86 'fast' calling convention passes up to two integer arguments in
+// registers (an appropriate portion of EAX/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.
+//
+// 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.
+//
+std::vector<SDOperand>
+X86TargetLowering::LowerFastCCArguments(Function &F, SelectionDAG &DAG) {
+ std::vector<SDOperand> ArgValues;
+
+ MachineFunction &MF = DAG.getMachineFunction();
+ MachineFrameInfo *MFI = MF.getFrameInfo();
+
+ // 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 first 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 EAX or EDX used), 1 (EAX is used) or 2 (EAX and EDX are both
+ // used).
+ unsigned NumIntRegs = 0;
+
+ for (Function::arg_iterator I = F.arg_begin(), E = F.arg_end(); I != E; ++I) {
+ MVT::ValueType ObjectVT = getValueType(I->getType());
+ unsigned ArgIncrement = 4;
+ unsigned ObjSize = 0;
+ SDOperand ArgValue;
+
+ switch (ObjectVT) {
+ default: assert(0 && "Unhandled argument type!");
+ case MVT::i1:
+ case MVT::i8:
+ if (NumIntRegs < 2) {
+ if (!I->use_empty()) {
+ MF.addLiveIn(NumIntRegs ? X86::DL : X86::AL);
+ ArgValue = DAG.getCopyFromReg(NumIntRegs ? X86::DL : X86::AL, MVT::i8,
+ DAG.getRoot());
+ DAG.setRoot(ArgValue.getValue(1));
+ }
+ ++NumIntRegs;
+ break;
+ }
+
+ ObjSize = 1;
+ break;
+ case MVT::i16:
+ if (NumIntRegs < 2) {
+ if (!I->use_empty()) {
+ MF.addLiveIn(NumIntRegs ? X86::DX : X86::AX);
+ ArgValue = DAG.getCopyFromReg(NumIntRegs ? X86::DX : X86::AX,
+ MVT::i16, DAG.getRoot());
+ DAG.setRoot(ArgValue.getValue(1));
+ }
+ ++NumIntRegs;
+ break;
+ }
+ ObjSize = 2;
+ break;
+ case MVT::i32:
+ if (NumIntRegs < 2) {
+ if (!I->use_empty()) {
+ MF.addLiveIn(NumIntRegs ? X86::EDX : X86::EAX);
+ ArgValue = DAG.getCopyFromReg(NumIntRegs ? X86::EDX : X86::EAX,
+ MVT::i32, DAG.getRoot());
+ DAG.setRoot(ArgValue.getValue(1));
+ }
+ ++NumIntRegs;
+ break;
+ }
+ ObjSize = 4;
+ break;
+ case MVT::i64:
+ if (NumIntRegs == 0) {
+ if (!I->use_empty()) {
+ MF.addLiveIn(X86::EDX);
+ MF.addLiveIn(X86::EAX);
+
+ SDOperand Low=DAG.getCopyFromReg(X86::EAX, MVT::i32, DAG.getRoot());
+ SDOperand Hi =DAG.getCopyFromReg(X86::EDX, MVT::i32, Low.getValue(1));
+ DAG.setRoot(Hi.getValue(1));
+
+ ArgValue = DAG.getNode(ISD::BUILD_PAIR, MVT::i64, Low, Hi);
+ }
+ NumIntRegs = 2;
+ break;
+ } else if (NumIntRegs == 1) {
+ if (!I->use_empty()) {
+ MF.addLiveIn(X86::EDX);
+ SDOperand Low = DAG.getCopyFromReg(X86::EDX, MVT::i32, DAG.getRoot());
+ DAG.setRoot(Low.getValue(1));
+
+ // Load the high part from memory.
+ // Create the frame index object for this incoming parameter...
+ int FI = MFI->CreateFixedObject(4, ArgOffset);
+ SDOperand FIN = DAG.getFrameIndex(FI, MVT::i32);
+ SDOperand Hi = DAG.getLoad(MVT::i32, DAG.getEntryNode(), FIN,
+ DAG.getSrcValue(NULL));
+ ArgValue = DAG.getNode(ISD::BUILD_PAIR, MVT::i64, Low, Hi);
+ }
+ ArgOffset += 4;
+ NumIntRegs = 2;
+ break;
+ }
+ ObjSize = ArgIncrement = 8;
+ break;
+ case MVT::f32: ObjSize = 4; break;
+ case MVT::f64: ObjSize = ArgIncrement = 8; break;
+ }
+
+ // Don't codegen dead arguments. FIXME: remove this check when we can nuke
+ // dead loads.
+ if (ObjSize && !I->use_empty()) {
+ // Create the frame index object for this incoming parameter...
+ int FI = MFI->CreateFixedObject(ObjSize, ArgOffset);
+
+ // Create the SelectionDAG nodes corresponding to a load from this
+ // parameter.
+ SDOperand FIN = DAG.getFrameIndex(FI, MVT::i32);
+
+ ArgValue = DAG.getLoad(ObjectVT, DAG.getEntryNode(), FIN,
+ DAG.getSrcValue(NULL));
+ } else if (ArgValue.Val == 0) {
+ if (MVT::isInteger(ObjectVT))
+ ArgValue = DAG.getConstant(0, ObjectVT);
+ else
+ ArgValue = DAG.getConstantFP(0, ObjectVT);
+ }
+ ArgValues.push_back(ArgValue);
+
+ if (ObjSize)
+ ArgOffset += ArgIncrement; // Move on to the next argument.
+ }
+
+ // 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.
+ if (F.isVarArg())
+ VarArgsFrameIndex = MFI->CreateFixedObject(1, ArgOffset);
+ ReturnAddrIndex = 0; // No return address slot generated yet.
+
+ // Finally, inform the code generator which regs we return values in.
+ switch (getValueType(F.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::EAX);
+ break;
+ case MVT::i64:
+ MF.addLiveOut(X86::EAX);
+ MF.addLiveOut(X86::EDX);
+ break;
+ case MVT::f32:
+ case MVT::f64:
+ MF.addLiveOut(X86::ST0);
+ break;
+ }
+ return ArgValues;
+}
+
+std::pair<SDOperand, SDOperand>
+X86TargetLowering::LowerFastCCCallTo(SDOperand Chain, const Type *RetTy,
+ SDOperand Callee,
+ ArgListTy &Args, SelectionDAG &DAG) {
+ // Count how many bytes are to be pushed on the stack.
+ 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).
+ unsigned NumIntRegs = 0;
+
+ for (unsigned i = 0, e = Args.size(); i != e; ++i)
+ switch (getValueType(Args[i].second)) {
+ default: assert(0 && "Unknown value type!");
+ case MVT::i1:
+ case MVT::i8:
+ case MVT::i16:
+ case MVT::i32:
+ if (NumIntRegs < 2) {
+ ++NumIntRegs;
+ break;
+ }
+ // fall through
+ case MVT::f32:
+ NumBytes += 4;
+ break;
+ case MVT::i64:
+ if (NumIntRegs == 0) {
+ NumIntRegs = 2;
+ break;
+ } else if (NumIntRegs == 1) {
+ NumIntRegs = 2;
+ NumBytes += 4;
+ break;
+ }
+
+ // fall through
+ case MVT::f64:
+ NumBytes += 8;
+ break;
+ }
+
+ Chain = DAG.getNode(ISD::ADJCALLSTACKDOWN, MVT::Other, Chain,
+ DAG.getConstant(NumBytes, getPointerTy()));
+
+ // Arguments go on the stack in reverse order, as specified by the ABI.
+ unsigned ArgOffset = 0;
+ SDOperand StackPtr = DAG.getCopyFromReg(X86::ESP, MVT::i32,
+ DAG.getEntryNode());
+ NumIntRegs = 0;
+ std::vector<SDOperand> Stores;
+ std::vector<SDOperand> RegValuesToPass;
+ for (unsigned i = 0, e = Args.size(); i != e; ++i) {
+ switch (getValueType(Args[i].second)) {
+ default: assert(0 && "Unexpected ValueType for argument!");
+ case MVT::i1:
+ case MVT::i8:
+ case MVT::i16:
+ case MVT::i32:
+ if (NumIntRegs < 2) {
+ RegValuesToPass.push_back(Args[i].first);
+ ++NumIntRegs;
+ break;
+ }
+ // Fall through
+ case MVT::f32: {
+ SDOperand PtrOff = DAG.getConstant(ArgOffset, getPointerTy());
+ PtrOff = DAG.getNode(ISD::ADD, MVT::i32, StackPtr, PtrOff);
+ Stores.push_back(DAG.getNode(ISD::STORE, MVT::Other, Chain,
+ Args[i].first, PtrOff,
+ DAG.getSrcValue(NULL)));
+ ArgOffset += 4;
+ break;
+ }
+ case MVT::i64:
+ if (NumIntRegs < 2) { // Can pass part of it in regs?
+ SDOperand Hi = DAG.getNode(ISD::EXTRACT_ELEMENT, MVT::i32,
+ Args[i].first, DAG.getConstant(1, MVT::i32));
+ SDOperand Lo = DAG.getNode(ISD::EXTRACT_ELEMENT, MVT::i32,
+ Args[i].first, DAG.getConstant(0, MVT::i32));
+ RegValuesToPass.push_back(Lo);
+ ++NumIntRegs;
+ if (NumIntRegs < 2) { // Pass both parts in regs?
+ RegValuesToPass.push_back(Hi);
+ ++NumIntRegs;
+ } else {
+ // Pass the high part in memory.
+ SDOperand PtrOff = DAG.getConstant(ArgOffset, getPointerTy());
+ PtrOff = DAG.getNode(ISD::ADD, MVT::i32, StackPtr, PtrOff);
+ Stores.push_back(DAG.getNode(ISD::STORE, MVT::Other, Chain,
+ Args[i].first, PtrOff,
+ DAG.getSrcValue(NULL)));
+ ArgOffset += 4;
+ }
+ break;
+ }
+ // Fall through
+ case MVT::f64:
+ SDOperand PtrOff = DAG.getConstant(ArgOffset, getPointerTy());
+ PtrOff = DAG.getNode(ISD::ADD, MVT::i32, StackPtr, PtrOff);
+ Stores.push_back(DAG.getNode(ISD::STORE, MVT::Other, Chain,
+ Args[i].first, PtrOff,
+ DAG.getSrcValue(NULL)));
+ ArgOffset += 8;
+ break;
+ }
+ }
+ if (!Stores.empty())
+ Chain = DAG.getNode(ISD::TokenFactor, MVT::Other, Stores);
+
+ 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), 0);
+ Chain = TheCall.getValue(RetTyVT != MVT::isVoid);
+ Chain = DAG.getNode(ISD::ADJCALLSTACKUP, MVT::Other, Chain,
+ DAG.getConstant(NumBytes, getPointerTy()));
+ return std::make_pair(TheCall, Chain);
+}
+
+
+
std::pair<SDOperand, SDOperand> X86TargetLowering::
LowerFrameReturnAddress(bool isFrameAddress, SDOperand Chain, unsigned Depth,
@@ -340,7 +680,8 @@
if (!isFrameAddress)
// Just load the return address
- Result = DAG.getLoad(MVT::i32, DAG.getEntryNode(), RetAddrFI, DAG.getSrcValue(NULL));
+ Result = DAG.getLoad(MVT::i32, DAG.getEntryNode(), RetAddrFI,
+ DAG.getSrcValue(NULL));
else
Result = DAG.getNode(ISD::SUB, MVT::i32, RetAddrFI,
DAG.getConstant(4, MVT::i32));
@@ -1397,10 +1738,11 @@
SDOperand Op0, Op1;
if (Node->getOpcode() == ISD::CopyFromReg) {
- // FIXME: Handle copy from physregs!
-
- // Just use the specified register as our input.
- return dyn_cast<RegSDNode>(Node)->getReg();
+ if (MRegisterInfo::isVirtualRegister(cast<RegSDNode>(Node)->getReg()) ||
+ cast<RegSDNode>(Node)->getReg() == X86::ESP) {
+ // Just use the specified register as our input.
+ return cast<RegSDNode>(Node)->getReg();
+ }
}
unsigned &Reg = ExprMap[N];
@@ -1440,6 +1782,29 @@
default:
Node->dump();
assert(0 && "Node not handled!\n");
+ case ISD::CopyFromReg:
+ Select(N.getOperand(0));
+ if (Result == 1) {
+ Reg = Result = ExprMap[N.getValue(0)] =
+ MakeReg(N.getValue(0).getValueType());
+ }
+ switch (Node->getValueType(0)) {
+ default: assert(0 && "Cannot CopyFromReg this!");
+ case MVT::i1:
+ case MVT::i8:
+ BuildMI(BB, X86::MOV8rr, 1,
+ Result).addReg(cast<RegSDNode>(Node)->getReg());
+ return Result;
+ case MVT::i16:
+ BuildMI(BB, X86::MOV16rr, 1,
+ Result).addReg(cast<RegSDNode>(Node)->getReg());
+ return Result;
+ case MVT::i32:
+ BuildMI(BB, X86::MOV32rr, 1,
+ Result).addReg(cast<RegSDNode>(Node)->getReg());
+ return Result;
+ }
+
case ISD::FrameIndex:
Tmp1 = cast<FrameIndexSDNode>(N)->getIndex();
addFrameReference(BuildMI(BB, X86::LEA32r, 4, Result), (int)Tmp1);
@@ -2643,17 +3008,60 @@
BuildMI(BB, X86::MOV32rr, 1, Result).addReg(X86::ESP);
return Result;
- case ISD::CALL:
+ case ISD::CALL: {
// The chain for this call is now lowered.
ExprMap.insert(std::make_pair(N.getValue(Node->getNumValues()-1), 1));
+ bool isDirect = isa<GlobalAddressSDNode>(N.getOperand(1)) ||
+ isa<ExternalSymbolSDNode>(N.getOperand(1));
+ unsigned Callee = 0;
+ if (isDirect) {
+ Select(N.getOperand(0));
+ } else {
+ if (getRegPressure(N.getOperand(0)) > getRegPressure(N.getOperand(1))) {
+ Select(N.getOperand(0));
+ Callee = SelectExpr(N.getOperand(1));
+ } else {
+ Callee = SelectExpr(N.getOperand(1));
+ Select(N.getOperand(0));
+ }
+ }
+
+ // If this call has values to pass in registers, do so now.
+ if (Node->getNumOperands() > 2) {
+ // The first value is passed in (a part of) EAX, the second in EDX.
+ unsigned RegOp1 = SelectExpr(N.getOperand(2));
+ unsigned RegOp2 =
+ Node->getNumOperands() > 3 ? SelectExpr(N.getOperand(3)) : 0;
+
+ switch (N.getOperand(2).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;
+ case MVT::i16: BuildMI(BB, X86::MOV16rr, 1,X86::AX).addReg(RegOp1); break;
+ case MVT::i32: BuildMI(BB, X86::MOV32rr, 1,X86::EAX).addReg(RegOp1);break;
+ }
+ if (RegOp2)
+ switch (N.getOperand(3).getValueType()) {
+ default: assert(0 && "Bad thing to pass in regs");
+ case MVT::i1:
+ case MVT::i8:
+ BuildMI(BB, X86::MOV8rr , 1, X86::DL).addReg(RegOp2);
+ break;
+ case MVT::i16:
+ BuildMI(BB, X86::MOV16rr, 1, X86::DX).addReg(RegOp2);
+ break;
+ case MVT::i32:
+ BuildMI(BB, X86::MOV32rr, 1, X86::EDX).addReg(RegOp2);
+ break;
+ }
+ }
+
if (GlobalAddressSDNode *GASD =
dyn_cast<GlobalAddressSDNode>(N.getOperand(1))) {
- Select(N.getOperand(0));
BuildMI(BB, X86::CALLpcrel32, 1).addGlobalAddress(GASD->getGlobal(),true);
} else if (ExternalSymbolSDNode *ESSDN =
dyn_cast<ExternalSymbolSDNode>(N.getOperand(1))) {
- Select(N.getOperand(0));
BuildMI(BB, X86::CALLpcrel32,
1).addExternalSymbol(ESSDN->getSymbol(), true);
} else {
@@ -2688,6 +3096,7 @@
break;
}
return Result+N.ResNo;
+ }
case ISD::READPORT:
// First, determine that the size of the operand falls within the acceptable
// range for this architecture.
@@ -3125,6 +3534,10 @@
ExprMap.erase(N);
SelectExpr(N);
return;
+ case ISD::CopyFromReg:
+ ExprMap.erase(N);
+ SelectExpr(N.getValue(0));
+ return;
case ISD::TRUNCSTORE: { // truncstore chain, val, ptr :storety
// On X86, we can represent all types except for Bool and Float natively.
More information about the llvm-commits
mailing list