From 2db3ff66f1183fa65bd5102ad255a798f76cb3b2 Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Sun, 18 Dec 2005 15:55:15 +0000 Subject: [PATCH] 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 --- lib/Target/Sparc/SparcISelDAGToDAG.cpp | 230 ++++++++++++++++++++- lib/Target/Sparc/SparcInstrInfo.td | 42 ++-- lib/Target/SparcV8/SparcV8ISelDAGToDAG.cpp | 230 ++++++++++++++++++++- lib/Target/SparcV8/SparcV8InstrInfo.td | 42 ++-- 4 files changed, 514 insertions(+), 30 deletions(-) diff --git a/lib/Target/Sparc/SparcISelDAGToDAG.cpp b/lib/Target/Sparc/SparcISelDAGToDAG.cpp index fe6a2e1c09e..c121cf1fbda 100644 --- a/lib/Target/Sparc/SparcISelDAGToDAG.cpp +++ b/lib/Target/Sparc/SparcISelDAGToDAG.cpp @@ -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 Stores; + std::vector 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 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(Callee)) + Callee = DAG.getTargetGlobalAddress(G->getGlobal(), MVT::i32); + + std::vector 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); diff --git a/lib/Target/Sparc/SparcInstrInfo.td b/lib/Target/Sparc/SparcInstrInfo.td index 46d1d3a9ae8..c9777b93488 100644 --- a/lib/Target/Sparc/SparcInstrInfo.td +++ b/lib/Target/Sparc/SparcInstrInfo.td @@ -57,6 +57,7 @@ def MEMri : Operand { // Branch targets have OtherVT type. def brtarget : Operand; +def calltarget : Operand; 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 pattern> : InstV8; 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 diff --git a/lib/Target/SparcV8/SparcV8ISelDAGToDAG.cpp b/lib/Target/SparcV8/SparcV8ISelDAGToDAG.cpp index fe6a2e1c09e..c121cf1fbda 100644 --- a/lib/Target/SparcV8/SparcV8ISelDAGToDAG.cpp +++ b/lib/Target/SparcV8/SparcV8ISelDAGToDAG.cpp @@ -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 Stores; + std::vector 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 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(Callee)) + Callee = DAG.getTargetGlobalAddress(G->getGlobal(), MVT::i32); + + std::vector 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); diff --git a/lib/Target/SparcV8/SparcV8InstrInfo.td b/lib/Target/SparcV8/SparcV8InstrInfo.td index 46d1d3a9ae8..c9777b93488 100644 --- a/lib/Target/SparcV8/SparcV8InstrInfo.td +++ b/lib/Target/SparcV8/SparcV8InstrInfo.td @@ -57,6 +57,7 @@ def MEMri : Operand { // Branch targets have OtherVT type. def brtarget : Operand; +def calltarget : Operand; 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 pattern> : InstV8; 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 -- 2.34.1