mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-08-19 19:29:31 +00:00
Implement Calls for V8. This would be completely autogenerated except for
a small bug in tblgen. When that is fixed, we can remove the ISD::Call case in Select. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@24830 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
dc464de9b0
commit
2db3ff66f1
@ -50,6 +50,7 @@ namespace V8ISD {
|
||||
|
||||
namespace {
|
||||
class SparcV8TargetLowering : public TargetLowering {
|
||||
int VarArgsFrameOffset; // Frame offset to start of varargs area.
|
||||
public:
|
||||
SparcV8TargetLowering(TargetMachine &TM);
|
||||
virtual SDOperand LowerOperation(SDOperand Op, SelectionDAG &DAG);
|
||||
@ -154,7 +155,6 @@ SparcV8TargetLowering::LowerArguments(Function &F, SelectionDAG &DAG) {
|
||||
|
||||
switch (ObjectVT) {
|
||||
default: assert(0 && "Unhandled argument type!");
|
||||
// TODO: FP
|
||||
case MVT::i1:
|
||||
case MVT::i8:
|
||||
case MVT::i16:
|
||||
@ -278,6 +278,9 @@ SparcV8TargetLowering::LowerArguments(Function &F, SelectionDAG &DAG) {
|
||||
|
||||
// Store remaining ArgRegs to the stack if this is a varargs function.
|
||||
if (F.getFunctionType()->isVarArg()) {
|
||||
// Remember the vararg offset for the va_start implementation.
|
||||
VarArgsFrameOffset = ArgOffset;
|
||||
|
||||
for (; CurArgReg != ArgRegEnd; ++CurArgReg) {
|
||||
unsigned VReg = RegMap->createVirtualRegister(&V8::IntRegsRegClass);
|
||||
MF.addLiveIn(*CurArgReg, VReg);
|
||||
@ -325,8 +328,208 @@ SparcV8TargetLowering::LowerCallTo(SDOperand Chain, const Type *RetTy,
|
||||
bool isVarArg, unsigned CC,
|
||||
bool isTailCall, SDOperand Callee,
|
||||
ArgListTy &Args, SelectionDAG &DAG) {
|
||||
assert(0 && "Unimp");
|
||||
abort();
|
||||
MachineFunction &MF = DAG.getMachineFunction();
|
||||
// Count the size of the outgoing arguments.
|
||||
unsigned ArgsSize = 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:
|
||||
case MVT::f32:
|
||||
ArgsSize += 4;
|
||||
break;
|
||||
case MVT::i64:
|
||||
case MVT::f64:
|
||||
ArgsSize += 8;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ArgsSize > 4*6)
|
||||
ArgsSize -= 4*6; // Space for first 6 arguments is prereserved.
|
||||
else
|
||||
ArgsSize = 0;
|
||||
|
||||
Chain = DAG.getNode(ISD::CALLSEQ_START, MVT::Other, Chain,
|
||||
DAG.getConstant(ArgsSize, getPointerTy()));
|
||||
|
||||
SDOperand StackPtr, NullSV;
|
||||
std::vector<SDOperand> Stores;
|
||||
std::vector<SDOperand> RegValuesToPass;
|
||||
unsigned ArgOffset = 68;
|
||||
for (unsigned i = 0, e = Args.size(); i != e; ++i) {
|
||||
SDOperand Val = Args[i].first;
|
||||
MVT::ValueType ObjectVT = Val.getValueType();
|
||||
SDOperand ValToStore;
|
||||
unsigned ObjSize;
|
||||
switch (ObjectVT) {
|
||||
default: assert(0 && "Unhandled argument type!");
|
||||
case MVT::i1:
|
||||
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.
|
||||
if (Args[i].second->isSigned())
|
||||
Val = DAG.getNode(ISD::SIGN_EXTEND, MVT::i32, Val);
|
||||
else
|
||||
Val = DAG.getNode(ISD::ZERO_EXTEND, MVT::i32, Val);
|
||||
// FALL THROUGH
|
||||
case MVT::i32:
|
||||
ObjSize = 4;
|
||||
|
||||
if (RegValuesToPass.size() >= 6) {
|
||||
ValToStore = Val;
|
||||
} else {
|
||||
RegValuesToPass.push_back(Val);
|
||||
}
|
||||
break;
|
||||
case MVT::f32:
|
||||
ObjSize = 4;
|
||||
if (RegValuesToPass.size() >= 6) {
|
||||
ValToStore = Val;
|
||||
} else {
|
||||
// Convert this to a FP value in an int reg.
|
||||
int FrameIdx = MF.getFrameInfo()->CreateStackObject(4, 4);
|
||||
SDOperand FIPtr = DAG.getFrameIndex(FrameIdx, MVT::i32);
|
||||
SDOperand SV = DAG.getSrcValue(0);
|
||||
SDOperand Store = DAG.getNode(ISD::STORE, MVT::Other, Chain,
|
||||
Val, FIPtr, SV);
|
||||
Val = DAG.getLoad(MVT::i32, Store, FIPtr, SV);
|
||||
RegValuesToPass.push_back(Val);
|
||||
}
|
||||
break;
|
||||
case MVT::f64: {
|
||||
ObjSize = 8;
|
||||
// If we can store this directly into the outgoing slot, do so. We can
|
||||
// do this when all ArgRegs are used and if the outgoing slot is aligned.
|
||||
if (RegValuesToPass.size() >= 6 && ((ArgOffset-68) & 7) == 0) {
|
||||
ValToStore = Val;
|
||||
break;
|
||||
}
|
||||
|
||||
// Otherwise, convert this to a FP value in int regs.
|
||||
int FrameIdx = MF.getFrameInfo()->CreateStackObject(8, 8);
|
||||
SDOperand FIPtr = DAG.getFrameIndex(FrameIdx, MVT::i32);
|
||||
SDOperand SV = DAG.getSrcValue(0);
|
||||
SDOperand Store = DAG.getNode(ISD::STORE, MVT::Other, Chain,
|
||||
Val, FIPtr, SV);
|
||||
Val = DAG.getLoad(MVT::i64, Store, FIPtr, SV);
|
||||
}
|
||||
// FALL THROUGH
|
||||
case MVT::i64:
|
||||
ObjSize = 8;
|
||||
if (RegValuesToPass.size() >= 6) {
|
||||
ValToStore = Val; // Whole thing is passed in memory.
|
||||
break;
|
||||
}
|
||||
|
||||
// Split the value into top and bottom part. Top part goes in a reg.
|
||||
SDOperand Hi = DAG.getNode(ISD::EXTRACT_ELEMENT, MVT::i32, Val,
|
||||
DAG.getConstant(1, MVT::i32));
|
||||
SDOperand Lo = DAG.getNode(ISD::EXTRACT_ELEMENT, MVT::i32, Val,
|
||||
DAG.getConstant(0, MVT::i32));
|
||||
RegValuesToPass.push_back(Hi);
|
||||
|
||||
if (RegValuesToPass.size() >= 6) {
|
||||
ValToStore = Lo;
|
||||
} else {
|
||||
RegValuesToPass.push_back(Lo);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (ValToStore.Val) {
|
||||
if (!StackPtr.Val) {
|
||||
StackPtr = DAG.getCopyFromReg(DAG.getEntryNode(), V8::SP, MVT::i32);
|
||||
NullSV = DAG.getSrcValue(NULL);
|
||||
}
|
||||
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,
|
||||
ValToStore, PtrOff, NullSV));
|
||||
}
|
||||
ArgOffset += ObjSize;
|
||||
}
|
||||
|
||||
// Emit all stores, make sure the occur before any copies into physregs.
|
||||
if (!Stores.empty())
|
||||
Chain = DAG.getNode(ISD::TokenFactor, MVT::Other, Stores);
|
||||
|
||||
static const unsigned ArgRegs[] = {
|
||||
V8::O0, V8::O1, V8::O2, V8::O3, V8::O4, V8::O5
|
||||
};
|
||||
|
||||
// Build a sequence of copy-to-reg nodes chained together with token chain
|
||||
// and flag operands which copy the outgoing args into O[0-5].
|
||||
SDOperand InFlag;
|
||||
for (unsigned i = 0, e = RegValuesToPass.size(); i != e; ++i) {
|
||||
Chain = DAG.getCopyToReg(Chain, ArgRegs[i], RegValuesToPass[i], InFlag);
|
||||
InFlag = Chain.getValue(1);
|
||||
}
|
||||
|
||||
std::vector<MVT::ValueType> RetVals;
|
||||
RetVals.push_back(MVT::Other);
|
||||
RetVals.push_back(MVT::Flag);
|
||||
|
||||
// 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))
|
||||
Callee = DAG.getTargetGlobalAddress(G->getGlobal(), MVT::i32);
|
||||
|
||||
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.
|
||||
Chain = SDOperand(DAG.getCall(NodeTys, Chain, Callee, InFlag), 0);
|
||||
InFlag = Chain.getValue(1);
|
||||
|
||||
MVT::ValueType RetTyVT = getValueType(RetTy);
|
||||
SDOperand RetVal;
|
||||
if (RetTyVT != MVT::isVoid) {
|
||||
switch (RetTyVT) {
|
||||
default: assert(0 && "Unknown value type to return!");
|
||||
case MVT::i1:
|
||||
case MVT::i8:
|
||||
case MVT::i16:
|
||||
RetVal = DAG.getCopyFromReg(Chain, V8::O0, MVT::i32, InFlag);
|
||||
Chain = RetVal.getValue(1);
|
||||
|
||||
// Add a note to keep track of whether it is sign or zero extended.
|
||||
RetVal = DAG.getNode(RetTy->isSigned() ? ISD::AssertSext :ISD::AssertZext,
|
||||
MVT::i32, RetVal, DAG.getValueType(RetTyVT));
|
||||
RetVal = DAG.getNode(ISD::TRUNCATE, RetTyVT, RetVal);
|
||||
break;
|
||||
case MVT::i32:
|
||||
RetVal = DAG.getCopyFromReg(Chain, V8::O0, MVT::i32, InFlag);
|
||||
Chain = RetVal.getValue(1);
|
||||
break;
|
||||
case MVT::f32:
|
||||
RetVal = DAG.getCopyFromReg(Chain, V8::F0, MVT::f32, InFlag);
|
||||
Chain = RetVal.getValue(1);
|
||||
break;
|
||||
case MVT::f64:
|
||||
RetVal = DAG.getCopyFromReg(Chain, V8::D0, MVT::f64, InFlag);
|
||||
Chain = RetVal.getValue(1);
|
||||
break;
|
||||
case MVT::i64:
|
||||
SDOperand Lo = DAG.getCopyFromReg(Chain, V8::O0, MVT::i32, InFlag);
|
||||
SDOperand Hi = DAG.getCopyFromReg(Lo.getValue(1), V8::O0, MVT::i32,
|
||||
Lo.getValue(2));
|
||||
RetVal = DAG.getNode(ISD::BUILD_PAIR, MVT::i64, Lo, Hi);
|
||||
Chain = Hi.getValue(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Chain = DAG.getNode(ISD::CALLSEQ_END, MVT::Other, Chain,
|
||||
DAG.getConstant(ArgsSize, getPointerTy()));
|
||||
|
||||
MVT::ValueType ActualRetTyVT = RetTyVT;
|
||||
if (RetTyVT >= MVT::i1 && RetTyVT <= MVT::i16)
|
||||
ActualRetTyVT = MVT::i32; // Promote result to i32.
|
||||
|
||||
return std::make_pair(RetVal, Chain);
|
||||
}
|
||||
|
||||
SDOperand SparcV8TargetLowering::LowerReturnTo(SDOperand Chain, SDOperand Op,
|
||||
@ -734,6 +937,7 @@ SDOperand SparcV8DAGToDAGISel::Select(SDOperand Op) {
|
||||
}
|
||||
|
||||
case ISD::RET: {
|
||||
// FIXME: change this to use flag operands to allow autogen of ret.
|
||||
if (N->getNumOperands() == 2) {
|
||||
SDOperand Chain = Select(N->getOperand(0)); // Token chain.
|
||||
SDOperand Val = Select(N->getOperand(1));
|
||||
@ -757,6 +961,26 @@ SDOperand SparcV8DAGToDAGISel::Select(SDOperand Op) {
|
||||
}
|
||||
break; // Generated code handles the void case.
|
||||
}
|
||||
case ISD::CALL:
|
||||
// FIXME: This is a workaround for a bug in tblgen.
|
||||
{ // Pattern #47: (call:Flag (tglobaladdr:i32):$dst, ICC:Flag)
|
||||
// Emits: (CALL:void (tglobaladdr:i32):$dst)
|
||||
// Pattern complexity = 2 cost = 1
|
||||
SDOperand N1 = N->getOperand(1);
|
||||
if (N1.getOpcode() != ISD::TargetGlobalAddress) goto P47Fail;
|
||||
SDOperand N2 = N->getOperand(2);
|
||||
SDOperand InFlag = SDOperand(0,0);
|
||||
SDOperand Chain = N->getOperand(0);
|
||||
SDOperand Tmp0 = N1;
|
||||
Chain = Select(Chain);
|
||||
InFlag = Select(N2);
|
||||
SDOperand Result = CurDAG->getTargetNode(V8::CALL, MVT::Other, MVT::Flag, Tmp0, Chain, InFlag);
|
||||
Chain = CodeGenMap[SDOperand(N, 0)] = Result.getValue(0);
|
||||
CodeGenMap[SDOperand(N, 1)] = Result.getValue(1);
|
||||
return Result.getValue(Op.ResNo);
|
||||
}
|
||||
P47Fail:;
|
||||
|
||||
}
|
||||
|
||||
return SelectCode(Op);
|
||||
|
@ -57,6 +57,7 @@ def MEMri : Operand<i32> {
|
||||
|
||||
// Branch targets have OtherVT type.
|
||||
def brtarget : Operand<OtherVT>;
|
||||
def calltarget : Operand<i32>;
|
||||
|
||||
def SDTV8cmpicc :
|
||||
SDTypeProfile<1, 2, [SDTCisVT<0, FlagVT>, SDTCisInt<1>, SDTCisSameAs<1, 2>]>;
|
||||
@ -83,6 +84,15 @@ def V8itof : SDNode<"V8ISD::ITOF", SDTFPUnaryOp>;
|
||||
def V8selecticc : SDNode<"V8ISD::SELECT_ICC", SDTV8selectcc>;
|
||||
def V8selectfcc : SDNode<"V8ISD::SELECT_FCC", SDTV8selectcc>;
|
||||
|
||||
// These are target-independent nodes, but have target-specific formats.
|
||||
def SDT_V8CallSeq : SDTypeProfile<0, 1, [ SDTCisVT<0, i32> ]>;
|
||||
def callseq_start : SDNode<"ISD::CALLSEQ_START", SDT_V8CallSeq, [SDNPHasChain]>;
|
||||
def callseq_end : SDNode<"ISD::CALLSEQ_END", SDT_V8CallSeq, [SDNPHasChain]>;
|
||||
|
||||
def SDT_V8Call : SDTypeProfile<1, 2, [SDTCisVT<0, FlagVT>, SDTCisVT<1, i32>,
|
||||
SDTCisVT<2, FlagVT>]>;
|
||||
def call : SDNode<"ISD::CALL", SDT_V8Call, [SDNPHasChain]>;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Instructions
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -92,8 +102,12 @@ class Pseudo<dag ops, string asmstr, list<dag> pattern>
|
||||
: InstV8<ops, asmstr, pattern>;
|
||||
|
||||
def PHI : Pseudo<(ops variable_ops), "PHI", []>;
|
||||
def ADJCALLSTACKDOWN : Pseudo<(ops i32imm:$amt), "!ADJCALLSTACKDOWN $amt",[]>;
|
||||
def ADJCALLSTACKUP : Pseudo<(ops i32imm:$amt), "!ADJCALLSTACKUP $amt", []>;
|
||||
def ADJCALLSTACKDOWN : Pseudo<(ops i32imm:$amt),
|
||||
"!ADJCALLSTACKDOWN $amt",
|
||||
[(callseq_start imm:$amt)]>;
|
||||
def ADJCALLSTACKUP : Pseudo<(ops i32imm:$amt),
|
||||
"!ADJCALLSTACKUP $amt",
|
||||
[(callseq_end imm:$amt)]>;
|
||||
def IMPLICIT_DEF : Pseudo<(ops IntRegs:$dst), "!IMPLICIT_DEF $dst", []>;
|
||||
def FpMOVD : Pseudo<(ops DFPRegs:$dst, DFPRegs:$src),
|
||||
"!FpMOVD", []>; // pseudo 64-bit double move
|
||||
@ -523,23 +537,27 @@ def FBO : FPBranchV8<0b1111, (ops brtarget:$dst),
|
||||
|
||||
// Section B.24 - Call and Link Instruction, p. 125
|
||||
// This is the only Format 1 instruction
|
||||
let Uses = [O0, O1, O2, O3, O4, O5], hasDelaySlot = 1, isCall = 1 in {
|
||||
let Uses = [O0, O1, O2, O3, O4, O5], hasDelaySlot = 1, isCall = 1,
|
||||
Defs = [O0, O1, O2, O3, O4, O5, O7, G1, G2, G3, G4, G5, G6, G7,
|
||||
D0, D1, D2, D3, D4, D5, D6, D7, D8, D9, D10, D11, D12, D13, D14, D15] in {
|
||||
// pc-relative call:
|
||||
let Defs = [O0, O1, O2, O3, O4, O5, O7, G1, G2, G3, G4, G5, G6, G7,
|
||||
D0, D1, D2, D3, D4, D5, D6, D7, D8, D9, D10, D11, D12, D13, D14, D15] in
|
||||
def CALL : InstV8<(ops IntRegs:$dst), "call $dst", []> {
|
||||
def CALL : InstV8<(ops calltarget:$dst),
|
||||
"call $dst",
|
||||
[(set ICC/*bogus*/, (call tglobaladdr:$dst, ICC/*bogus*/))]> {
|
||||
bits<30> disp;
|
||||
let op = 1;
|
||||
let Inst{29-0} = disp;
|
||||
}
|
||||
|
||||
// indirect call (O7 is an EXPLICIT def in indirect calls, so it cannot also
|
||||
// be an implicit def):
|
||||
let Defs = [O0, O1, O2, O3, O4, O5, G1, G2, G3, G4, G5, G6, G7,
|
||||
D0, D1, D2, D3, D4, D5, D6, D7, D8, D9, D10, D11, D12, D13, D14, D15] in
|
||||
// indirect calls
|
||||
def JMPLrr : F3_1<2, 0b111000,
|
||||
(ops IntRegs:$dst, IntRegs:$b, IntRegs:$c),
|
||||
"jmpl $b+$c, $dst", []>;
|
||||
(ops MEMrr:$ptr),
|
||||
"jmpl $ptr",
|
||||
[(set ICC/*bogus*/, (call ADDRrr:$ptr, ICC/*bogus*/))]>;
|
||||
def JMPLri : F3_2<2, 0b111000,
|
||||
(ops MEMri:$ptr),
|
||||
"jmpl $ptr",
|
||||
[(set ICC/*bogus*/, (call ADDRri:$ptr, ICC/*bogus*/))]>;
|
||||
}
|
||||
|
||||
// Section B.28 - Read State Register Instructions
|
||||
|
@ -50,6 +50,7 @@ namespace V8ISD {
|
||||
|
||||
namespace {
|
||||
class SparcV8TargetLowering : public TargetLowering {
|
||||
int VarArgsFrameOffset; // Frame offset to start of varargs area.
|
||||
public:
|
||||
SparcV8TargetLowering(TargetMachine &TM);
|
||||
virtual SDOperand LowerOperation(SDOperand Op, SelectionDAG &DAG);
|
||||
@ -154,7 +155,6 @@ SparcV8TargetLowering::LowerArguments(Function &F, SelectionDAG &DAG) {
|
||||
|
||||
switch (ObjectVT) {
|
||||
default: assert(0 && "Unhandled argument type!");
|
||||
// TODO: FP
|
||||
case MVT::i1:
|
||||
case MVT::i8:
|
||||
case MVT::i16:
|
||||
@ -278,6 +278,9 @@ SparcV8TargetLowering::LowerArguments(Function &F, SelectionDAG &DAG) {
|
||||
|
||||
// Store remaining ArgRegs to the stack if this is a varargs function.
|
||||
if (F.getFunctionType()->isVarArg()) {
|
||||
// Remember the vararg offset for the va_start implementation.
|
||||
VarArgsFrameOffset = ArgOffset;
|
||||
|
||||
for (; CurArgReg != ArgRegEnd; ++CurArgReg) {
|
||||
unsigned VReg = RegMap->createVirtualRegister(&V8::IntRegsRegClass);
|
||||
MF.addLiveIn(*CurArgReg, VReg);
|
||||
@ -325,8 +328,208 @@ SparcV8TargetLowering::LowerCallTo(SDOperand Chain, const Type *RetTy,
|
||||
bool isVarArg, unsigned CC,
|
||||
bool isTailCall, SDOperand Callee,
|
||||
ArgListTy &Args, SelectionDAG &DAG) {
|
||||
assert(0 && "Unimp");
|
||||
abort();
|
||||
MachineFunction &MF = DAG.getMachineFunction();
|
||||
// Count the size of the outgoing arguments.
|
||||
unsigned ArgsSize = 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:
|
||||
case MVT::f32:
|
||||
ArgsSize += 4;
|
||||
break;
|
||||
case MVT::i64:
|
||||
case MVT::f64:
|
||||
ArgsSize += 8;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ArgsSize > 4*6)
|
||||
ArgsSize -= 4*6; // Space for first 6 arguments is prereserved.
|
||||
else
|
||||
ArgsSize = 0;
|
||||
|
||||
Chain = DAG.getNode(ISD::CALLSEQ_START, MVT::Other, Chain,
|
||||
DAG.getConstant(ArgsSize, getPointerTy()));
|
||||
|
||||
SDOperand StackPtr, NullSV;
|
||||
std::vector<SDOperand> Stores;
|
||||
std::vector<SDOperand> RegValuesToPass;
|
||||
unsigned ArgOffset = 68;
|
||||
for (unsigned i = 0, e = Args.size(); i != e; ++i) {
|
||||
SDOperand Val = Args[i].first;
|
||||
MVT::ValueType ObjectVT = Val.getValueType();
|
||||
SDOperand ValToStore;
|
||||
unsigned ObjSize;
|
||||
switch (ObjectVT) {
|
||||
default: assert(0 && "Unhandled argument type!");
|
||||
case MVT::i1:
|
||||
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.
|
||||
if (Args[i].second->isSigned())
|
||||
Val = DAG.getNode(ISD::SIGN_EXTEND, MVT::i32, Val);
|
||||
else
|
||||
Val = DAG.getNode(ISD::ZERO_EXTEND, MVT::i32, Val);
|
||||
// FALL THROUGH
|
||||
case MVT::i32:
|
||||
ObjSize = 4;
|
||||
|
||||
if (RegValuesToPass.size() >= 6) {
|
||||
ValToStore = Val;
|
||||
} else {
|
||||
RegValuesToPass.push_back(Val);
|
||||
}
|
||||
break;
|
||||
case MVT::f32:
|
||||
ObjSize = 4;
|
||||
if (RegValuesToPass.size() >= 6) {
|
||||
ValToStore = Val;
|
||||
} else {
|
||||
// Convert this to a FP value in an int reg.
|
||||
int FrameIdx = MF.getFrameInfo()->CreateStackObject(4, 4);
|
||||
SDOperand FIPtr = DAG.getFrameIndex(FrameIdx, MVT::i32);
|
||||
SDOperand SV = DAG.getSrcValue(0);
|
||||
SDOperand Store = DAG.getNode(ISD::STORE, MVT::Other, Chain,
|
||||
Val, FIPtr, SV);
|
||||
Val = DAG.getLoad(MVT::i32, Store, FIPtr, SV);
|
||||
RegValuesToPass.push_back(Val);
|
||||
}
|
||||
break;
|
||||
case MVT::f64: {
|
||||
ObjSize = 8;
|
||||
// If we can store this directly into the outgoing slot, do so. We can
|
||||
// do this when all ArgRegs are used and if the outgoing slot is aligned.
|
||||
if (RegValuesToPass.size() >= 6 && ((ArgOffset-68) & 7) == 0) {
|
||||
ValToStore = Val;
|
||||
break;
|
||||
}
|
||||
|
||||
// Otherwise, convert this to a FP value in int regs.
|
||||
int FrameIdx = MF.getFrameInfo()->CreateStackObject(8, 8);
|
||||
SDOperand FIPtr = DAG.getFrameIndex(FrameIdx, MVT::i32);
|
||||
SDOperand SV = DAG.getSrcValue(0);
|
||||
SDOperand Store = DAG.getNode(ISD::STORE, MVT::Other, Chain,
|
||||
Val, FIPtr, SV);
|
||||
Val = DAG.getLoad(MVT::i64, Store, FIPtr, SV);
|
||||
}
|
||||
// FALL THROUGH
|
||||
case MVT::i64:
|
||||
ObjSize = 8;
|
||||
if (RegValuesToPass.size() >= 6) {
|
||||
ValToStore = Val; // Whole thing is passed in memory.
|
||||
break;
|
||||
}
|
||||
|
||||
// Split the value into top and bottom part. Top part goes in a reg.
|
||||
SDOperand Hi = DAG.getNode(ISD::EXTRACT_ELEMENT, MVT::i32, Val,
|
||||
DAG.getConstant(1, MVT::i32));
|
||||
SDOperand Lo = DAG.getNode(ISD::EXTRACT_ELEMENT, MVT::i32, Val,
|
||||
DAG.getConstant(0, MVT::i32));
|
||||
RegValuesToPass.push_back(Hi);
|
||||
|
||||
if (RegValuesToPass.size() >= 6) {
|
||||
ValToStore = Lo;
|
||||
} else {
|
||||
RegValuesToPass.push_back(Lo);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (ValToStore.Val) {
|
||||
if (!StackPtr.Val) {
|
||||
StackPtr = DAG.getCopyFromReg(DAG.getEntryNode(), V8::SP, MVT::i32);
|
||||
NullSV = DAG.getSrcValue(NULL);
|
||||
}
|
||||
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,
|
||||
ValToStore, PtrOff, NullSV));
|
||||
}
|
||||
ArgOffset += ObjSize;
|
||||
}
|
||||
|
||||
// Emit all stores, make sure the occur before any copies into physregs.
|
||||
if (!Stores.empty())
|
||||
Chain = DAG.getNode(ISD::TokenFactor, MVT::Other, Stores);
|
||||
|
||||
static const unsigned ArgRegs[] = {
|
||||
V8::O0, V8::O1, V8::O2, V8::O3, V8::O4, V8::O5
|
||||
};
|
||||
|
||||
// Build a sequence of copy-to-reg nodes chained together with token chain
|
||||
// and flag operands which copy the outgoing args into O[0-5].
|
||||
SDOperand InFlag;
|
||||
for (unsigned i = 0, e = RegValuesToPass.size(); i != e; ++i) {
|
||||
Chain = DAG.getCopyToReg(Chain, ArgRegs[i], RegValuesToPass[i], InFlag);
|
||||
InFlag = Chain.getValue(1);
|
||||
}
|
||||
|
||||
std::vector<MVT::ValueType> RetVals;
|
||||
RetVals.push_back(MVT::Other);
|
||||
RetVals.push_back(MVT::Flag);
|
||||
|
||||
// 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))
|
||||
Callee = DAG.getTargetGlobalAddress(G->getGlobal(), MVT::i32);
|
||||
|
||||
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.
|
||||
Chain = SDOperand(DAG.getCall(NodeTys, Chain, Callee, InFlag), 0);
|
||||
InFlag = Chain.getValue(1);
|
||||
|
||||
MVT::ValueType RetTyVT = getValueType(RetTy);
|
||||
SDOperand RetVal;
|
||||
if (RetTyVT != MVT::isVoid) {
|
||||
switch (RetTyVT) {
|
||||
default: assert(0 && "Unknown value type to return!");
|
||||
case MVT::i1:
|
||||
case MVT::i8:
|
||||
case MVT::i16:
|
||||
RetVal = DAG.getCopyFromReg(Chain, V8::O0, MVT::i32, InFlag);
|
||||
Chain = RetVal.getValue(1);
|
||||
|
||||
// Add a note to keep track of whether it is sign or zero extended.
|
||||
RetVal = DAG.getNode(RetTy->isSigned() ? ISD::AssertSext :ISD::AssertZext,
|
||||
MVT::i32, RetVal, DAG.getValueType(RetTyVT));
|
||||
RetVal = DAG.getNode(ISD::TRUNCATE, RetTyVT, RetVal);
|
||||
break;
|
||||
case MVT::i32:
|
||||
RetVal = DAG.getCopyFromReg(Chain, V8::O0, MVT::i32, InFlag);
|
||||
Chain = RetVal.getValue(1);
|
||||
break;
|
||||
case MVT::f32:
|
||||
RetVal = DAG.getCopyFromReg(Chain, V8::F0, MVT::f32, InFlag);
|
||||
Chain = RetVal.getValue(1);
|
||||
break;
|
||||
case MVT::f64:
|
||||
RetVal = DAG.getCopyFromReg(Chain, V8::D0, MVT::f64, InFlag);
|
||||
Chain = RetVal.getValue(1);
|
||||
break;
|
||||
case MVT::i64:
|
||||
SDOperand Lo = DAG.getCopyFromReg(Chain, V8::O0, MVT::i32, InFlag);
|
||||
SDOperand Hi = DAG.getCopyFromReg(Lo.getValue(1), V8::O0, MVT::i32,
|
||||
Lo.getValue(2));
|
||||
RetVal = DAG.getNode(ISD::BUILD_PAIR, MVT::i64, Lo, Hi);
|
||||
Chain = Hi.getValue(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Chain = DAG.getNode(ISD::CALLSEQ_END, MVT::Other, Chain,
|
||||
DAG.getConstant(ArgsSize, getPointerTy()));
|
||||
|
||||
MVT::ValueType ActualRetTyVT = RetTyVT;
|
||||
if (RetTyVT >= MVT::i1 && RetTyVT <= MVT::i16)
|
||||
ActualRetTyVT = MVT::i32; // Promote result to i32.
|
||||
|
||||
return std::make_pair(RetVal, Chain);
|
||||
}
|
||||
|
||||
SDOperand SparcV8TargetLowering::LowerReturnTo(SDOperand Chain, SDOperand Op,
|
||||
@ -734,6 +937,7 @@ SDOperand SparcV8DAGToDAGISel::Select(SDOperand Op) {
|
||||
}
|
||||
|
||||
case ISD::RET: {
|
||||
// FIXME: change this to use flag operands to allow autogen of ret.
|
||||
if (N->getNumOperands() == 2) {
|
||||
SDOperand Chain = Select(N->getOperand(0)); // Token chain.
|
||||
SDOperand Val = Select(N->getOperand(1));
|
||||
@ -757,6 +961,26 @@ SDOperand SparcV8DAGToDAGISel::Select(SDOperand Op) {
|
||||
}
|
||||
break; // Generated code handles the void case.
|
||||
}
|
||||
case ISD::CALL:
|
||||
// FIXME: This is a workaround for a bug in tblgen.
|
||||
{ // Pattern #47: (call:Flag (tglobaladdr:i32):$dst, ICC:Flag)
|
||||
// Emits: (CALL:void (tglobaladdr:i32):$dst)
|
||||
// Pattern complexity = 2 cost = 1
|
||||
SDOperand N1 = N->getOperand(1);
|
||||
if (N1.getOpcode() != ISD::TargetGlobalAddress) goto P47Fail;
|
||||
SDOperand N2 = N->getOperand(2);
|
||||
SDOperand InFlag = SDOperand(0,0);
|
||||
SDOperand Chain = N->getOperand(0);
|
||||
SDOperand Tmp0 = N1;
|
||||
Chain = Select(Chain);
|
||||
InFlag = Select(N2);
|
||||
SDOperand Result = CurDAG->getTargetNode(V8::CALL, MVT::Other, MVT::Flag, Tmp0, Chain, InFlag);
|
||||
Chain = CodeGenMap[SDOperand(N, 0)] = Result.getValue(0);
|
||||
CodeGenMap[SDOperand(N, 1)] = Result.getValue(1);
|
||||
return Result.getValue(Op.ResNo);
|
||||
}
|
||||
P47Fail:;
|
||||
|
||||
}
|
||||
|
||||
return SelectCode(Op);
|
||||
|
@ -57,6 +57,7 @@ def MEMri : Operand<i32> {
|
||||
|
||||
// Branch targets have OtherVT type.
|
||||
def brtarget : Operand<OtherVT>;
|
||||
def calltarget : Operand<i32>;
|
||||
|
||||
def SDTV8cmpicc :
|
||||
SDTypeProfile<1, 2, [SDTCisVT<0, FlagVT>, SDTCisInt<1>, SDTCisSameAs<1, 2>]>;
|
||||
@ -83,6 +84,15 @@ def V8itof : SDNode<"V8ISD::ITOF", SDTFPUnaryOp>;
|
||||
def V8selecticc : SDNode<"V8ISD::SELECT_ICC", SDTV8selectcc>;
|
||||
def V8selectfcc : SDNode<"V8ISD::SELECT_FCC", SDTV8selectcc>;
|
||||
|
||||
// These are target-independent nodes, but have target-specific formats.
|
||||
def SDT_V8CallSeq : SDTypeProfile<0, 1, [ SDTCisVT<0, i32> ]>;
|
||||
def callseq_start : SDNode<"ISD::CALLSEQ_START", SDT_V8CallSeq, [SDNPHasChain]>;
|
||||
def callseq_end : SDNode<"ISD::CALLSEQ_END", SDT_V8CallSeq, [SDNPHasChain]>;
|
||||
|
||||
def SDT_V8Call : SDTypeProfile<1, 2, [SDTCisVT<0, FlagVT>, SDTCisVT<1, i32>,
|
||||
SDTCisVT<2, FlagVT>]>;
|
||||
def call : SDNode<"ISD::CALL", SDT_V8Call, [SDNPHasChain]>;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Instructions
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -92,8 +102,12 @@ class Pseudo<dag ops, string asmstr, list<dag> pattern>
|
||||
: InstV8<ops, asmstr, pattern>;
|
||||
|
||||
def PHI : Pseudo<(ops variable_ops), "PHI", []>;
|
||||
def ADJCALLSTACKDOWN : Pseudo<(ops i32imm:$amt), "!ADJCALLSTACKDOWN $amt",[]>;
|
||||
def ADJCALLSTACKUP : Pseudo<(ops i32imm:$amt), "!ADJCALLSTACKUP $amt", []>;
|
||||
def ADJCALLSTACKDOWN : Pseudo<(ops i32imm:$amt),
|
||||
"!ADJCALLSTACKDOWN $amt",
|
||||
[(callseq_start imm:$amt)]>;
|
||||
def ADJCALLSTACKUP : Pseudo<(ops i32imm:$amt),
|
||||
"!ADJCALLSTACKUP $amt",
|
||||
[(callseq_end imm:$amt)]>;
|
||||
def IMPLICIT_DEF : Pseudo<(ops IntRegs:$dst), "!IMPLICIT_DEF $dst", []>;
|
||||
def FpMOVD : Pseudo<(ops DFPRegs:$dst, DFPRegs:$src),
|
||||
"!FpMOVD", []>; // pseudo 64-bit double move
|
||||
@ -523,23 +537,27 @@ def FBO : FPBranchV8<0b1111, (ops brtarget:$dst),
|
||||
|
||||
// Section B.24 - Call and Link Instruction, p. 125
|
||||
// This is the only Format 1 instruction
|
||||
let Uses = [O0, O1, O2, O3, O4, O5], hasDelaySlot = 1, isCall = 1 in {
|
||||
let Uses = [O0, O1, O2, O3, O4, O5], hasDelaySlot = 1, isCall = 1,
|
||||
Defs = [O0, O1, O2, O3, O4, O5, O7, G1, G2, G3, G4, G5, G6, G7,
|
||||
D0, D1, D2, D3, D4, D5, D6, D7, D8, D9, D10, D11, D12, D13, D14, D15] in {
|
||||
// pc-relative call:
|
||||
let Defs = [O0, O1, O2, O3, O4, O5, O7, G1, G2, G3, G4, G5, G6, G7,
|
||||
D0, D1, D2, D3, D4, D5, D6, D7, D8, D9, D10, D11, D12, D13, D14, D15] in
|
||||
def CALL : InstV8<(ops IntRegs:$dst), "call $dst", []> {
|
||||
def CALL : InstV8<(ops calltarget:$dst),
|
||||
"call $dst",
|
||||
[(set ICC/*bogus*/, (call tglobaladdr:$dst, ICC/*bogus*/))]> {
|
||||
bits<30> disp;
|
||||
let op = 1;
|
||||
let Inst{29-0} = disp;
|
||||
}
|
||||
|
||||
// indirect call (O7 is an EXPLICIT def in indirect calls, so it cannot also
|
||||
// be an implicit def):
|
||||
let Defs = [O0, O1, O2, O3, O4, O5, G1, G2, G3, G4, G5, G6, G7,
|
||||
D0, D1, D2, D3, D4, D5, D6, D7, D8, D9, D10, D11, D12, D13, D14, D15] in
|
||||
// indirect calls
|
||||
def JMPLrr : F3_1<2, 0b111000,
|
||||
(ops IntRegs:$dst, IntRegs:$b, IntRegs:$c),
|
||||
"jmpl $b+$c, $dst", []>;
|
||||
(ops MEMrr:$ptr),
|
||||
"jmpl $ptr",
|
||||
[(set ICC/*bogus*/, (call ADDRrr:$ptr, ICC/*bogus*/))]>;
|
||||
def JMPLri : F3_2<2, 0b111000,
|
||||
(ops MEMri:$ptr),
|
||||
"jmpl $ptr",
|
||||
[(set ICC/*bogus*/, (call ADDRri:$ptr, ICC/*bogus*/))]>;
|
||||
}
|
||||
|
||||
// Section B.28 - Read State Register Instructions
|
||||
|
Loading…
Reference in New Issue
Block a user