X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FTarget%2FMips%2FMipsISelLowering.cpp;h=2ff369cfab2832cec5fc10bb2a1913e87f71876c;hb=cd7319dc5f91ac81ab9d8505f34937e91bfcf65d;hp=abf22bd8041f3b878b3f94a0f8a06e5924f5d161;hpb=864f66085cd9543070ef01b9f7371c110ecd7898;p=oota-llvm.git diff --git a/lib/Target/Mips/MipsISelLowering.cpp b/lib/Target/Mips/MipsISelLowering.cpp index abf22bd8041..2ff369cfab2 100644 --- a/lib/Target/Mips/MipsISelLowering.cpp +++ b/lib/Target/Mips/MipsISelLowering.cpp @@ -11,20 +11,16 @@ // selection DAG. // //===----------------------------------------------------------------------===// - #define DEBUG_TYPE "mips-lower" +#include #include "MipsISelLowering.h" +#include "InstPrinter/MipsInstPrinter.h" +#include "MCTargetDesc/MipsBaseInfo.h" #include "MipsMachineFunction.h" +#include "MipsSubtarget.h" #include "MipsTargetMachine.h" #include "MipsTargetObjectFile.h" -#include "MipsSubtarget.h" -#include "InstPrinter/MipsInstPrinter.h" -#include "MCTargetDesc/MipsBaseInfo.h" -#include "llvm/DerivedTypes.h" -#include "llvm/Function.h" -#include "llvm/GlobalVariable.h" -#include "llvm/Intrinsics.h" -#include "llvm/CallingConv.h" +#include "llvm/ADT/Statistic.h" #include "llvm/CodeGen/CallingConvLower.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunction.h" @@ -32,12 +28,49 @@ #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/SelectionDAGISel.h" #include "llvm/CodeGen/ValueTypes.h" +#include "llvm/IR/CallingConv.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/GlobalVariable.h" +#include "llvm/IR/Intrinsics.h" +#include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; +STATISTIC(NumTailCalls, "Number of tail calls"); + +static cl::opt +EnableMipsTailCalls("enable-mips-tail-calls", cl::Hidden, + cl::desc("MIPS: Enable tail calls."), cl::init(false)); + +static cl::opt +LargeGOT("mxgot", cl::Hidden, + cl::desc("MIPS: Enable GOT larger than 64k."), cl::init(false)); + +static cl::opt +Mips16HardFloat("mips16-hard-float", cl::NotHidden, + cl::desc("MIPS: mips16 hard float enable."), + cl::init(false)); + + + +static const uint16_t O32IntRegs[4] = { + Mips::A0, Mips::A1, Mips::A2, Mips::A3 +}; + +static const uint16_t Mips64IntRegs[8] = { + Mips::A0_64, Mips::A1_64, Mips::A2_64, Mips::A3_64, + Mips::T0_64, Mips::T1_64, Mips::T2_64, Mips::T3_64 +}; + +static const uint16_t Mips64DPRegs[8] = { + Mips::D12_64, Mips::D13_64, Mips::D14_64, Mips::D15_64, + Mips::D16_64, Mips::D17_64, Mips::D18_64, Mips::D19_64 +}; + // If I is a shifted mask, set the size (Size) and the first bit of the // mask (Pos), and return true. // For example, if I is 0x003ff800, (Pos, Size) = (11, 11). @@ -55,14 +88,81 @@ static SDValue GetGlobalReg(SelectionDAG &DAG, EVT Ty) { return DAG.getRegister(FI->getGlobalBaseReg(), Ty); } +static SDValue getTargetNode(SDValue Op, SelectionDAG &DAG, unsigned Flag) { + EVT Ty = Op.getValueType(); + + if (GlobalAddressSDNode *N = dyn_cast(Op)) + return DAG.getTargetGlobalAddress(N->getGlobal(), Op.getDebugLoc(), Ty, 0, + Flag); + if (ExternalSymbolSDNode *N = dyn_cast(Op)) + return DAG.getTargetExternalSymbol(N->getSymbol(), Ty, Flag); + if (BlockAddressSDNode *N = dyn_cast(Op)) + return DAG.getTargetBlockAddress(N->getBlockAddress(), Ty, 0, Flag); + if (JumpTableSDNode *N = dyn_cast(Op)) + return DAG.getTargetJumpTable(N->getIndex(), Ty, Flag); + if (ConstantPoolSDNode *N = dyn_cast(Op)) + return DAG.getTargetConstantPool(N->getConstVal(), Ty, N->getAlignment(), + N->getOffset(), Flag); + + llvm_unreachable("Unexpected node type."); + return SDValue(); +} + +static SDValue getAddrNonPIC(SDValue Op, SelectionDAG &DAG) { + DebugLoc DL = Op.getDebugLoc(); + EVT Ty = Op.getValueType(); + SDValue Hi = getTargetNode(Op, DAG, MipsII::MO_ABS_HI); + SDValue Lo = getTargetNode(Op, DAG, MipsII::MO_ABS_LO); + return DAG.getNode(ISD::ADD, DL, Ty, + DAG.getNode(MipsISD::Hi, DL, Ty, Hi), + DAG.getNode(MipsISD::Lo, DL, Ty, Lo)); +} + +static SDValue getAddrLocal(SDValue Op, SelectionDAG &DAG, bool HasMips64) { + DebugLoc DL = Op.getDebugLoc(); + EVT Ty = Op.getValueType(); + unsigned GOTFlag = HasMips64 ? MipsII::MO_GOT_PAGE : MipsII::MO_GOT; + SDValue GOT = DAG.getNode(MipsISD::Wrapper, DL, Ty, GetGlobalReg(DAG, Ty), + getTargetNode(Op, DAG, GOTFlag)); + SDValue Load = DAG.getLoad(Ty, DL, DAG.getEntryNode(), GOT, + MachinePointerInfo::getGOT(), false, false, false, + 0); + unsigned LoFlag = HasMips64 ? MipsII::MO_GOT_OFST : MipsII::MO_ABS_LO; + SDValue Lo = DAG.getNode(MipsISD::Lo, DL, Ty, getTargetNode(Op, DAG, LoFlag)); + return DAG.getNode(ISD::ADD, DL, Ty, Load, Lo); +} + +static SDValue getAddrGlobal(SDValue Op, SelectionDAG &DAG, unsigned Flag) { + DebugLoc DL = Op.getDebugLoc(); + EVT Ty = Op.getValueType(); + SDValue Tgt = DAG.getNode(MipsISD::Wrapper, DL, Ty, GetGlobalReg(DAG, Ty), + getTargetNode(Op, DAG, Flag)); + return DAG.getLoad(Ty, DL, DAG.getEntryNode(), Tgt, + MachinePointerInfo::getGOT(), false, false, false, 0); +} + +static SDValue getAddrGlobalLargeGOT(SDValue Op, SelectionDAG &DAG, + unsigned HiFlag, unsigned LoFlag) { + DebugLoc DL = Op.getDebugLoc(); + EVT Ty = Op.getValueType(); + SDValue Hi = DAG.getNode(MipsISD::Hi, DL, Ty, getTargetNode(Op, DAG, HiFlag)); + Hi = DAG.getNode(ISD::ADD, DL, Ty, Hi, GetGlobalReg(DAG, Ty)); + SDValue Wrapper = DAG.getNode(MipsISD::Wrapper, DL, Ty, Hi, + getTargetNode(Op, DAG, LoFlag)); + return DAG.getLoad(Ty, DL, DAG.getEntryNode(), Wrapper, + MachinePointerInfo::getGOT(), false, false, false, 0); +} + const char *MipsTargetLowering::getTargetNodeName(unsigned Opcode) const { switch (Opcode) { case MipsISD::JmpLink: return "MipsISD::JmpLink"; + case MipsISD::TailCall: return "MipsISD::TailCall"; case MipsISD::Hi: return "MipsISD::Hi"; case MipsISD::Lo: return "MipsISD::Lo"; case MipsISD::GPRel: return "MipsISD::GPRel"; case MipsISD::ThreadPointer: return "MipsISD::ThreadPointer"; case MipsISD::Ret: return "MipsISD::Ret"; + case MipsISD::EH_RETURN: return "MipsISD::EH_RETURN"; case MipsISD::FPBrcond: return "MipsISD::FPBrcond"; case MipsISD::FPCmp: return "MipsISD::FPCmp"; case MipsISD::CMovFP_T: return "MipsISD::CMovFP_T"; @@ -77,7 +177,6 @@ const char *MipsTargetLowering::getTargetNodeName(unsigned Opcode) const { case MipsISD::BuildPairF64: return "MipsISD::BuildPairF64"; case MipsISD::ExtractElementF64: return "MipsISD::ExtractElementF64"; case MipsISD::Wrapper: return "MipsISD::Wrapper"; - case MipsISD::DynAlloc: return "MipsISD::DynAlloc"; case MipsISD::Sync: return "MipsISD::Sync"; case MipsISD::Ext: return "MipsISD::Ext"; case MipsISD::Ins: return "MipsISD::Ins"; @@ -89,10 +188,76 @@ const char *MipsTargetLowering::getTargetNodeName(unsigned Opcode) const { case MipsISD::LDR: return "MipsISD::LDR"; case MipsISD::SDL: return "MipsISD::SDL"; case MipsISD::SDR: return "MipsISD::SDR"; + case MipsISD::EXTP: return "MipsISD::EXTP"; + case MipsISD::EXTPDP: return "MipsISD::EXTPDP"; + case MipsISD::EXTR_S_H: return "MipsISD::EXTR_S_H"; + case MipsISD::EXTR_W: return "MipsISD::EXTR_W"; + case MipsISD::EXTR_R_W: return "MipsISD::EXTR_R_W"; + case MipsISD::EXTR_RS_W: return "MipsISD::EXTR_RS_W"; + case MipsISD::SHILO: return "MipsISD::SHILO"; + case MipsISD::MTHLIP: return "MipsISD::MTHLIP"; + case MipsISD::MULT: return "MipsISD::MULT"; + case MipsISD::MULTU: return "MipsISD::MULTU"; + case MipsISD::MADD_DSP: return "MipsISD::MADD_DSPDSP"; + case MipsISD::MADDU_DSP: return "MipsISD::MADDU_DSP"; + case MipsISD::MSUB_DSP: return "MipsISD::MSUB_DSP"; + case MipsISD::MSUBU_DSP: return "MipsISD::MSUBU_DSP"; default: return NULL; } } +namespace { + struct ltstr { + bool operator()(const char *s1, const char *s2) const + { + return strcmp(s1, s2) < 0; + } + }; + + std::set noHelperNeeded; +} + +void MipsTargetLowering::SetMips16LibcallName + (RTLIB::Libcall l, const char *Name) { + setLibcallName(l, Name); + noHelperNeeded.insert(Name); +} + +void MipsTargetLowering::setMips16HardFloatLibCalls() { + SetMips16LibcallName(RTLIB::ADD_F32, "__mips16_addsf3"); + SetMips16LibcallName(RTLIB::ADD_F64, "__mips16_adddf3"); + SetMips16LibcallName(RTLIB::SUB_F32, "__mips16_subsf3"); + SetMips16LibcallName(RTLIB::SUB_F64, "__mips16_subdf3"); + SetMips16LibcallName(RTLIB::MUL_F32, "__mips16_mulsf3"); + SetMips16LibcallName(RTLIB::MUL_F64, "__mips16_muldf3"); + SetMips16LibcallName(RTLIB::DIV_F32, "__mips16_divsf3"); + SetMips16LibcallName(RTLIB::DIV_F64, "__mips16_divdf3"); + SetMips16LibcallName(RTLIB::FPEXT_F32_F64, "__mips16_extendsfdf2"); + SetMips16LibcallName(RTLIB::FPROUND_F64_F32, "__mips16_truncdfsf2"); + SetMips16LibcallName(RTLIB::FPTOSINT_F32_I32, "__mips16_fix_truncsfsi"); + SetMips16LibcallName(RTLIB::FPTOSINT_F64_I32, "__mips16_fix_truncdfsi"); + SetMips16LibcallName(RTLIB::SINTTOFP_I32_F32, "__mips16_floatsisf"); + SetMips16LibcallName(RTLIB::SINTTOFP_I32_F64, "__mips16_floatsidf"); + SetMips16LibcallName(RTLIB::UINTTOFP_I32_F32, "__mips16_floatunsisf"); + SetMips16LibcallName(RTLIB::UINTTOFP_I32_F64, "__mips16_floatunsidf"); + SetMips16LibcallName(RTLIB::OEQ_F32, "__mips16_eqsf2"); + SetMips16LibcallName(RTLIB::OEQ_F64, "__mips16_eqdf2"); + SetMips16LibcallName(RTLIB::UNE_F32, "__mips16_nesf2"); + SetMips16LibcallName(RTLIB::UNE_F64, "__mips16_nedf2"); + SetMips16LibcallName(RTLIB::OGE_F32, "__mips16_gesf2"); + SetMips16LibcallName(RTLIB::OGE_F64, "__mips16_gedf2"); + SetMips16LibcallName(RTLIB::OLT_F32, "__mips16_ltsf2"); + SetMips16LibcallName(RTLIB::OLT_F64, "__mips16_ltdf2"); + SetMips16LibcallName(RTLIB::OLE_F32, "__mips16_lesf2"); + SetMips16LibcallName(RTLIB::OLE_F64, "__mips16_ledf2"); + SetMips16LibcallName(RTLIB::OGT_F32, "__mips16_gtsf2"); + SetMips16LibcallName(RTLIB::OGT_F64, "__mips16_gtdf2"); + SetMips16LibcallName(RTLIB::UO_F32, "__mips16_unordsf2"); + SetMips16LibcallName(RTLIB::UO_F64, "__mips16_unorddf2"); + SetMips16LibcallName(RTLIB::O_F32, "__mips16_unordsf2"); + SetMips16LibcallName(RTLIB::O_F64, "__mips16_unorddf2"); +} + MipsTargetLowering:: MipsTargetLowering(MipsTargetMachine &TM) : TargetLowering(TM, new MipsTargetObjectFile()), @@ -113,7 +278,24 @@ MipsTargetLowering(MipsTargetMachine &TM) if (Subtarget->inMips16Mode()) { addRegisterClass(MVT::i32, &Mips::CPU16RegsRegClass); - addRegisterClass(MVT::i32, &Mips::CPURARegRegClass); + if (Mips16HardFloat) + setMips16HardFloatLibCalls(); + } + + if (Subtarget->hasDSP()) { + MVT::SimpleValueType VecTys[2] = {MVT::v2i16, MVT::v4i8}; + + for (unsigned i = 0; i < array_lengthof(VecTys); ++i) { + addRegisterClass(VecTys[i], &Mips::DSPRegsRegClass); + + // Expand all builtin opcodes. + for (unsigned Opc = 0; Opc < ISD::BUILTIN_OP_END; ++Opc) + setOperationAction(Opc, VecTys[i], Expand); + + setOperationAction(ISD::LOAD, VecTys[i], Legal); + setOperationAction(ISD::STORE, VecTys[i], Legal); + setOperationAction(ISD::BITCAST, VecTys[i], Legal); + } } if (!TM.Options.UseSoftFloat) { @@ -152,17 +334,26 @@ MipsTargetLowering(MipsTargetMachine &TM) setOperationAction(ISD::SELECT, MVT::f32, Custom); setOperationAction(ISD::SELECT, MVT::f64, Custom); setOperationAction(ISD::SELECT, MVT::i32, Custom); + setOperationAction(ISD::SELECT_CC, MVT::f32, Custom); + setOperationAction(ISD::SELECT_CC, MVT::f64, Custom); setOperationAction(ISD::SETCC, MVT::f32, Custom); setOperationAction(ISD::SETCC, MVT::f64, Custom); setOperationAction(ISD::BRCOND, MVT::Other, Custom); - setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i32, Custom); setOperationAction(ISD::VASTART, MVT::Other, Custom); setOperationAction(ISD::FCOPYSIGN, MVT::f32, Custom); setOperationAction(ISD::FCOPYSIGN, MVT::f64, Custom); - setOperationAction(ISD::MEMBARRIER, MVT::Other, Custom); - setOperationAction(ISD::ATOMIC_FENCE, MVT::Other, Custom); - setOperationAction(ISD::LOAD, MVT::i32, Custom); - setOperationAction(ISD::STORE, MVT::i32, Custom); + if (Subtarget->inMips16Mode()) { + setOperationAction(ISD::MEMBARRIER, MVT::Other, Expand); + setOperationAction(ISD::ATOMIC_FENCE, MVT::Other, Expand); + } + else { + setOperationAction(ISD::MEMBARRIER, MVT::Other, Custom); + setOperationAction(ISD::ATOMIC_FENCE, MVT::Other, Custom); + } + if (!Subtarget->inMips16Mode()) { + setOperationAction(ISD::LOAD, MVT::i32, Custom); + setOperationAction(ISD::STORE, MVT::i32, Custom); + } if (!TM.Options.NoNaNsFPMath) { setOperationAction(ISD::FABS, MVT::f32, Custom); @@ -176,7 +367,6 @@ MipsTargetLowering(MipsTargetMachine &TM) setOperationAction(ISD::JumpTable, MVT::i64, Custom); setOperationAction(ISD::ConstantPool, MVT::i64, Custom); setOperationAction(ISD::SELECT, MVT::i64, Custom); - setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i64, Custom); setOperationAction(ISD::LOAD, MVT::i64, Custom); setOperationAction(ISD::STORE, MVT::i64, Custom); } @@ -187,6 +377,10 @@ MipsTargetLowering(MipsTargetMachine &TM) setOperationAction(ISD::SRL_PARTS, MVT::i32, Custom); } + setOperationAction(ISD::ADD, MVT::i32, Custom); + if (HasMips64) + setOperationAction(ISD::ADD, MVT::i64, Custom); + setOperationAction(ISD::SDIV, MVT::i32, Expand); setOperationAction(ISD::SREM, MVT::i32, Expand); setOperationAction(ISD::UDIV, MVT::i32, Expand); @@ -215,6 +409,8 @@ MipsTargetLowering(MipsTargetMachine &TM) setOperationAction(ISD::CTLZ_ZERO_UNDEF, MVT::i64, Expand); setOperationAction(ISD::ROTL, MVT::i32, Expand); setOperationAction(ISD::ROTL, MVT::i64, Expand); + setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i32, Expand); + setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i64, Expand); if (!Subtarget->hasMips32r2()) setOperationAction(ISD::ROTR, MVT::i32, Expand); @@ -226,6 +422,8 @@ MipsTargetLowering(MipsTargetMachine &TM) setOperationAction(ISD::FSIN, MVT::f64, Expand); setOperationAction(ISD::FCOS, MVT::f32, Expand); setOperationAction(ISD::FCOS, MVT::f64, Expand); + setOperationAction(ISD::FSINCOS, MVT::f32, Expand); + setOperationAction(ISD::FSINCOS, MVT::f64, Expand); setOperationAction(ISD::FPOWI, MVT::f32, Expand); setOperationAction(ISD::FPOW, MVT::f32, Expand); setOperationAction(ISD::FPOW, MVT::f64, Expand); @@ -248,10 +446,15 @@ MipsTargetLowering(MipsTargetMachine &TM) setOperationAction(ISD::EHSELECTION, MVT::i32, Expand); setOperationAction(ISD::EHSELECTION, MVT::i64, Expand); + setOperationAction(ISD::EH_RETURN, MVT::Other, Custom); + setOperationAction(ISD::VAARG, MVT::Other, Expand); setOperationAction(ISD::VACOPY, MVT::Other, Expand); setOperationAction(ISD::VAEND, MVT::Other, Expand); + setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::i64, Custom); + setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::i64, Custom); + // Use the default for now setOperationAction(ISD::STACKSAVE, MVT::Other, Expand); setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand); @@ -261,10 +464,22 @@ MipsTargetLowering(MipsTargetMachine &TM) setOperationAction(ISD::ATOMIC_STORE, MVT::i32, Expand); setOperationAction(ISD::ATOMIC_STORE, MVT::i64, Expand); - setInsertFencesForAtomic(true); + if (Subtarget->inMips16Mode()) { + setOperationAction(ISD::ATOMIC_CMP_SWAP, MVT::i32, Expand); + setOperationAction(ISD::ATOMIC_SWAP, MVT::i32, Expand); + setOperationAction(ISD::ATOMIC_LOAD_ADD, MVT::i32, Expand); + setOperationAction(ISD::ATOMIC_LOAD_SUB, MVT::i32, Expand); + setOperationAction(ISD::ATOMIC_LOAD_AND, MVT::i32, Expand); + setOperationAction(ISD::ATOMIC_LOAD_OR, MVT::i32, Expand); + setOperationAction(ISD::ATOMIC_LOAD_XOR, MVT::i32, Expand); + setOperationAction(ISD::ATOMIC_LOAD_NAND, MVT::i32, Expand); + setOperationAction(ISD::ATOMIC_LOAD_MIN, MVT::i32, Expand); + setOperationAction(ISD::ATOMIC_LOAD_MAX, MVT::i32, Expand); + setOperationAction(ISD::ATOMIC_LOAD_UMIN, MVT::i32, Expand); + setOperationAction(ISD::ATOMIC_LOAD_UMAX, MVT::i32, Expand); + } - if (Subtarget->isSingleFloat()) - setOperationAction(ISD::SELECT_CC, MVT::f64, Expand); + setInsertFencesForAtomic(true); if (!Subtarget->hasSEInReg()) { setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i8, Expand); @@ -308,22 +523,28 @@ MipsTargetLowering(MipsTargetMachine &TM) maxStoresPerMemcpy = 16; } -bool MipsTargetLowering::allowsUnalignedMemoryAccesses(EVT VT) const { +bool +MipsTargetLowering::allowsUnalignedMemoryAccesses(EVT VT, bool *Fast) const { MVT::SimpleValueType SVT = VT.getSimpleVT().SimpleTy; + if (Subtarget->inMips16Mode()) + return false; + switch (SVT) { case MVT::i64: case MVT::i32: + if (Fast) + *Fast = true; return true; - case MVT::f32: - return Subtarget->hasMips32r2Or64(); default: return false; } } EVT MipsTargetLowering::getSetCCResultType(EVT VT) const { - return MVT::i32; + if (!VT.isVector()) + return MVT::i32; + return VT.changeVectorElementTypeToInteger(); } // SelectMadd - @@ -788,6 +1009,26 @@ SDValue MipsTargetLowering::PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI) return SDValue(); } +void +MipsTargetLowering::LowerOperationWrapper(SDNode *N, + SmallVectorImpl &Results, + SelectionDAG &DAG) const { + SDValue Res = LowerOperation(SDValue(N, 0), DAG); + + for (unsigned I = 0, E = Res->getNumValues(); I != E; ++I) + Results.push_back(Res.getValue(I)); +} + +void +MipsTargetLowering::ReplaceNodeResults(SDNode *N, + SmallVectorImpl &Results, + SelectionDAG &DAG) const { + SDValue Res = LowerOperation(SDValue(N, 0), DAG); + + for (unsigned I = 0, E = Res->getNumValues(); I != E; ++I) + Results.push_back(Res.getValue(I)); +} + SDValue MipsTargetLowering:: LowerOperation(SDValue Op, SelectionDAG &DAG) const { @@ -795,17 +1036,19 @@ LowerOperation(SDValue Op, SelectionDAG &DAG) const { case ISD::BRCOND: return LowerBRCOND(Op, DAG); case ISD::ConstantPool: return LowerConstantPool(Op, DAG); - case ISD::DYNAMIC_STACKALLOC: return LowerDYNAMIC_STACKALLOC(Op, DAG); case ISD::GlobalAddress: return LowerGlobalAddress(Op, DAG); case ISD::BlockAddress: return LowerBlockAddress(Op, DAG); case ISD::GlobalTLSAddress: return LowerGlobalTLSAddress(Op, DAG); case ISD::JumpTable: return LowerJumpTable(Op, DAG); case ISD::SELECT: return LowerSELECT(Op, DAG); + case ISD::SELECT_CC: return LowerSELECT_CC(Op, DAG); case ISD::SETCC: return LowerSETCC(Op, DAG); case ISD::VASTART: return LowerVASTART(Op, DAG); case ISD::FCOPYSIGN: return LowerFCOPYSIGN(Op, DAG); case ISD::FABS: return LowerFABS(Op, DAG); case ISD::FRAMEADDR: return LowerFRAMEADDR(Op, DAG); + case ISD::RETURNADDR: return LowerRETURNADDR(Op, DAG); + case ISD::EH_RETURN: return LowerEH_RETURN(Op, DAG); case ISD::MEMBARRIER: return LowerMEMBARRIER(Op, DAG); case ISD::ATOMIC_FENCE: return LowerATOMIC_FENCE(Op, DAG); case ISD::SHL_PARTS: return LowerShiftLeftParts(Op, DAG); @@ -813,6 +1056,9 @@ LowerOperation(SDValue Op, SelectionDAG &DAG) const case ISD::SRL_PARTS: return LowerShiftRightParts(Op, DAG, false); case ISD::LOAD: return LowerLOAD(Op, DAG); case ISD::STORE: return LowerSTORE(Op, DAG); + case ISD::INTRINSIC_WO_CHAIN: return LowerINTRINSIC_WO_CHAIN(Op, DAG); + case ISD::INTRINSIC_W_CHAIN: return LowerINTRINSIC_W_CHAIN(Op, DAG); + case ISD::ADD: return LowerADD(Op, DAG); } return SDValue(); } @@ -827,7 +1073,6 @@ LowerOperation(SDValue Op, SelectionDAG &DAG) const static unsigned AddLiveIn(MachineFunction &MF, unsigned PReg, const TargetRegisterClass *RC) { - assert(RC->contains(PReg) && "Not the correct regclass!"); unsigned VReg = MF.getRegInfo().createVirtualRegister(RC); MF.getRegInfo().addLiveIn(PReg, VReg); return VReg; @@ -921,6 +1166,70 @@ static MachineBasicBlock* ExpandCondMov(MachineInstr *MI, MachineBasicBlock *BB, return BB; } */ + +MachineBasicBlock * +MipsTargetLowering::EmitBPOSGE32(MachineInstr *MI, MachineBasicBlock *BB) const{ + // $bb: + // bposge32_pseudo $vr0 + // => + // $bb: + // bposge32 $tbb + // $fbb: + // li $vr2, 0 + // b $sink + // $tbb: + // li $vr1, 1 + // $sink: + // $vr0 = phi($vr2, $fbb, $vr1, $tbb) + + MachineRegisterInfo &RegInfo = BB->getParent()->getRegInfo(); + const TargetInstrInfo *TII = getTargetMachine().getInstrInfo(); + const TargetRegisterClass *RC = &Mips::CPURegsRegClass; + DebugLoc DL = MI->getDebugLoc(); + const BasicBlock *LLVM_BB = BB->getBasicBlock(); + MachineFunction::iterator It = llvm::next(MachineFunction::iterator(BB)); + MachineFunction *F = BB->getParent(); + MachineBasicBlock *FBB = F->CreateMachineBasicBlock(LLVM_BB); + MachineBasicBlock *TBB = F->CreateMachineBasicBlock(LLVM_BB); + MachineBasicBlock *Sink = F->CreateMachineBasicBlock(LLVM_BB); + F->insert(It, FBB); + F->insert(It, TBB); + F->insert(It, Sink); + + // Transfer the remainder of BB and its successor edges to Sink. + Sink->splice(Sink->begin(), BB, llvm::next(MachineBasicBlock::iterator(MI)), + BB->end()); + Sink->transferSuccessorsAndUpdatePHIs(BB); + + // Add successors. + BB->addSuccessor(FBB); + BB->addSuccessor(TBB); + FBB->addSuccessor(Sink); + TBB->addSuccessor(Sink); + + // Insert the real bposge32 instruction to $BB. + BuildMI(BB, DL, TII->get(Mips::BPOSGE32)).addMBB(TBB); + + // Fill $FBB. + unsigned VR2 = RegInfo.createVirtualRegister(RC); + BuildMI(*FBB, FBB->end(), DL, TII->get(Mips::ADDiu), VR2) + .addReg(Mips::ZERO).addImm(0); + BuildMI(*FBB, FBB->end(), DL, TII->get(Mips::B)).addMBB(Sink); + + // Fill $TBB. + unsigned VR1 = RegInfo.createVirtualRegister(RC); + BuildMI(*TBB, TBB->end(), DL, TII->get(Mips::ADDiu), VR1) + .addReg(Mips::ZERO).addImm(1); + + // Insert phi function to $Sink. + BuildMI(*Sink, Sink->begin(), DL, TII->get(Mips::PHI), + MI->getOperand(0).getReg()) + .addReg(VR2).addMBB(FBB).addReg(VR1).addMBB(TBB); + + MI->eraseFromParent(); // The pseudo instruction is gone now. + return Sink; +} + MachineBasicBlock * MipsTargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI, MachineBasicBlock *BB) const { @@ -1029,6 +1338,8 @@ MipsTargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI, case Mips::ATOMIC_CMP_SWAP_I64: case Mips::ATOMIC_CMP_SWAP_I64_P8: return EmitAtomicCmpSwap(MI, BB, 8); + case Mips::BPOSGE32_PSEUDO: + return EmitBPOSGE32(MI, BB); } } @@ -1502,42 +1813,6 @@ MipsTargetLowering::EmitAtomicCmpSwapPartword(MachineInstr *MI, //===----------------------------------------------------------------------===// // Misc Lower Operation implementation //===----------------------------------------------------------------------===// -SDValue MipsTargetLowering:: -LowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG) const -{ - MachineFunction &MF = DAG.getMachineFunction(); - MipsFunctionInfo *MipsFI = MF.getInfo(); - unsigned SP = IsN64 ? Mips::SP_64 : Mips::SP; - - assert(getTargetMachine().getFrameLowering()->getStackAlignment() >= - cast(Op.getOperand(2).getNode())->getZExtValue() && - "Cannot lower if the alignment of the allocated space is larger than \ - that of the stack."); - - SDValue Chain = Op.getOperand(0); - SDValue Size = Op.getOperand(1); - DebugLoc dl = Op.getDebugLoc(); - - // Get a reference from Mips stack pointer - SDValue StackPointer = DAG.getCopyFromReg(Chain, dl, SP, getPointerTy()); - - // Subtract the dynamic size from the actual stack size to - // obtain the new stack size. - SDValue Sub = DAG.getNode(ISD::SUB, dl, getPointerTy(), StackPointer, Size); - - // The Sub result contains the new stack start address, so it - // must be placed in the stack pointer register. - Chain = DAG.getCopyToReg(StackPointer.getValue(1), dl, SP, Sub, SDValue()); - - // This node always has two return values: a new stack pointer - // value and a chain - SDVTList VTLs = DAG.getVTList(getPointerTy(), MVT::Other); - SDValue Ptr = DAG.getFrameIndex(MipsFI->getDynAllocFI(), getPointerTy()); - SDValue Ops[] = { Chain, Ptr, Chain.getValue(1) }; - - return DAG.getNode(MipsISD::DynAlloc, dl, VTLs, Ops, 3); -} - SDValue MipsTargetLowering:: LowerBRCOND(SDValue Op, SelectionDAG &DAG) const { @@ -1575,6 +1850,19 @@ LowerSELECT(SDValue Op, SelectionDAG &DAG) const Op.getDebugLoc()); } +SDValue MipsTargetLowering:: +LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) const +{ + DebugLoc DL = Op.getDebugLoc(); + EVT Ty = Op.getOperand(0).getValueType(); + SDValue Cond = DAG.getNode(ISD::SETCC, DL, getSetCCResultType(Ty), + Op.getOperand(0), Op.getOperand(1), + Op.getOperand(4)); + + return DAG.getNode(ISD::SELECT, DL, Op.getValueType(), Cond, Op.getOperand(2), + Op.getOperand(3)); +} + SDValue MipsTargetLowering::LowerSETCC(SDValue Op, SelectionDAG &DAG) const { SDValue Cond = CreateFPCmp(DAG, Op); @@ -1594,75 +1882,40 @@ SDValue MipsTargetLowering::LowerGlobalAddress(SDValue Op, const GlobalValue *GV = cast(Op)->getGlobal(); if (getTargetMachine().getRelocationModel() != Reloc::PIC_ && !IsN64) { - SDVTList VTs = DAG.getVTList(MVT::i32); - - MipsTargetObjectFile &TLOF = (MipsTargetObjectFile&)getObjFileLowering(); + const MipsTargetObjectFile &TLOF = + (const MipsTargetObjectFile&)getObjFileLowering(); // %gp_rel relocation if (TLOF.IsGlobalInSmallSection(GV, getTargetMachine())) { SDValue GA = DAG.getTargetGlobalAddress(GV, dl, MVT::i32, 0, MipsII::MO_GPREL); - SDValue GPRelNode = DAG.getNode(MipsISD::GPRel, dl, VTs, &GA, 1); - SDValue GOT = DAG.getGLOBAL_OFFSET_TABLE(MVT::i32); - return DAG.getNode(ISD::ADD, dl, MVT::i32, GOT, GPRelNode); + SDValue GPRelNode = DAG.getNode(MipsISD::GPRel, dl, + DAG.getVTList(MVT::i32), &GA, 1); + SDValue GPReg = DAG.getRegister(Mips::GP, MVT::i32); + return DAG.getNode(ISD::ADD, dl, MVT::i32, GPReg, GPRelNode); } + // %hi/%lo relocation - SDValue GAHi = DAG.getTargetGlobalAddress(GV, dl, MVT::i32, 0, - MipsII::MO_ABS_HI); - SDValue GALo = DAG.getTargetGlobalAddress(GV, dl, MVT::i32, 0, - MipsII::MO_ABS_LO); - SDValue HiPart = DAG.getNode(MipsISD::Hi, dl, VTs, &GAHi, 1); - SDValue Lo = DAG.getNode(MipsISD::Lo, dl, MVT::i32, GALo); - return DAG.getNode(ISD::ADD, dl, MVT::i32, HiPart, Lo); - } - - EVT ValTy = Op.getValueType(); - bool HasGotOfst = (GV->hasInternalLinkage() || - (GV->hasLocalLinkage() && !isa(GV))); - unsigned GotFlag = HasMips64 ? - (HasGotOfst ? MipsII::MO_GOT_PAGE : MipsII::MO_GOT_DISP) : - (HasGotOfst ? MipsII::MO_GOT : MipsII::MO_GOT16); - SDValue GA = DAG.getTargetGlobalAddress(GV, dl, ValTy, 0, GotFlag); - GA = DAG.getNode(MipsISD::Wrapper, dl, ValTy, GetGlobalReg(DAG, ValTy), GA); - SDValue ResNode = DAG.getLoad(ValTy, dl, DAG.getEntryNode(), GA, - MachinePointerInfo(), false, false, false, 0); - // On functions and global targets not internal linked only - // a load from got/GP is necessary for PIC to work. - if (!HasGotOfst) - return ResNode; - SDValue GALo = DAG.getTargetGlobalAddress(GV, dl, ValTy, 0, - HasMips64 ? MipsII::MO_GOT_OFST : - MipsII::MO_ABS_LO); - SDValue Lo = DAG.getNode(MipsISD::Lo, dl, ValTy, GALo); - return DAG.getNode(ISD::ADD, dl, ValTy, ResNode, Lo); + return getAddrNonPIC(Op, DAG); + } + + if (GV->hasInternalLinkage() || (GV->hasLocalLinkage() && !isa(GV))) + return getAddrLocal(Op, DAG, HasMips64); + + if (LargeGOT) + return getAddrGlobalLargeGOT(Op, DAG, MipsII::MO_GOT_HI16, + MipsII::MO_GOT_LO16); + + return getAddrGlobal(Op, DAG, + HasMips64 ? MipsII::MO_GOT_DISP : MipsII::MO_GOT16); } SDValue MipsTargetLowering::LowerBlockAddress(SDValue Op, SelectionDAG &DAG) const { - const BlockAddress *BA = cast(Op)->getBlockAddress(); - // FIXME there isn't actually debug info here - DebugLoc dl = Op.getDebugLoc(); - - if (getTargetMachine().getRelocationModel() != Reloc::PIC_ && !IsN64) { - // %hi/%lo relocation - SDValue BAHi = DAG.getBlockAddress(BA, MVT::i32, true, MipsII::MO_ABS_HI); - SDValue BALo = DAG.getBlockAddress(BA, MVT::i32, true, MipsII::MO_ABS_LO); - SDValue Hi = DAG.getNode(MipsISD::Hi, dl, MVT::i32, BAHi); - SDValue Lo = DAG.getNode(MipsISD::Lo, dl, MVT::i32, BALo); - return DAG.getNode(ISD::ADD, dl, MVT::i32, Hi, Lo); - } + if (getTargetMachine().getRelocationModel() != Reloc::PIC_ && !IsN64) + return getAddrNonPIC(Op, DAG); - EVT ValTy = Op.getValueType(); - unsigned GOTFlag = HasMips64 ? MipsII::MO_GOT_PAGE : MipsII::MO_GOT; - unsigned OFSTFlag = HasMips64 ? MipsII::MO_GOT_OFST : MipsII::MO_ABS_LO; - SDValue BAGOTOffset = DAG.getBlockAddress(BA, ValTy, true, GOTFlag); - BAGOTOffset = DAG.getNode(MipsISD::Wrapper, dl, ValTy, - GetGlobalReg(DAG, ValTy), BAGOTOffset); - SDValue BALOOffset = DAG.getBlockAddress(BA, ValTy, true, OFSTFlag); - SDValue Load = DAG.getLoad(ValTy, dl, DAG.getEntryNode(), BAGOTOffset, - MachinePointerInfo(), false, false, false, 0); - SDValue Lo = DAG.getNode(MipsISD::Lo, dl, ValTy, BALOOffset); - return DAG.getNode(ISD::ADD, dl, ValTy, Load, Lo); + return getAddrLocal(Op, DAG, HasMips64); } SDValue MipsTargetLowering:: @@ -1749,41 +2002,15 @@ LowerGlobalTLSAddress(SDValue Op, SelectionDAG &DAG) const SDValue MipsTargetLowering:: LowerJumpTable(SDValue Op, SelectionDAG &DAG) const { - SDValue HiPart, JTI, JTILo; - // FIXME there isn't actually debug info here - DebugLoc dl = Op.getDebugLoc(); - bool IsPIC = getTargetMachine().getRelocationModel() == Reloc::PIC_; - EVT PtrVT = Op.getValueType(); - JumpTableSDNode *JT = cast(Op); + if (getTargetMachine().getRelocationModel() != Reloc::PIC_ && !IsN64) + return getAddrNonPIC(Op, DAG); - if (!IsPIC && !IsN64) { - JTI = DAG.getTargetJumpTable(JT->getIndex(), PtrVT, MipsII::MO_ABS_HI); - HiPart = DAG.getNode(MipsISD::Hi, dl, PtrVT, JTI); - JTILo = DAG.getTargetJumpTable(JT->getIndex(), PtrVT, MipsII::MO_ABS_LO); - } else {// Emit Load from Global Pointer - unsigned GOTFlag = HasMips64 ? MipsII::MO_GOT_PAGE : MipsII::MO_GOT; - unsigned OfstFlag = HasMips64 ? MipsII::MO_GOT_OFST : MipsII::MO_ABS_LO; - JTI = DAG.getTargetJumpTable(JT->getIndex(), PtrVT, GOTFlag); - JTI = DAG.getNode(MipsISD::Wrapper, dl, PtrVT, GetGlobalReg(DAG, PtrVT), - JTI); - HiPart = DAG.getLoad(PtrVT, dl, DAG.getEntryNode(), JTI, - MachinePointerInfo(), false, false, false, 0); - JTILo = DAG.getTargetJumpTable(JT->getIndex(), PtrVT, OfstFlag); - } - - SDValue Lo = DAG.getNode(MipsISD::Lo, dl, PtrVT, JTILo); - return DAG.getNode(ISD::ADD, dl, PtrVT, HiPart, Lo); + return getAddrLocal(Op, DAG, HasMips64); } SDValue MipsTargetLowering:: LowerConstantPool(SDValue Op, SelectionDAG &DAG) const { - SDValue ResNode; - ConstantPoolSDNode *N = cast(Op); - const Constant *C = N->getConstVal(); - // FIXME there isn't actually debug info here - DebugLoc dl = Op.getDebugLoc(); - // gp_rel relocation // FIXME: we should reference the constant pool using small data sections, // but the asm printer currently doesn't support this feature without @@ -1794,31 +2021,10 @@ LowerConstantPool(SDValue Op, SelectionDAG &DAG) const // SDValue GOT = DAG.getGLOBAL_OFFSET_TABLE(MVT::i32); // ResNode = DAG.getNode(ISD::ADD, MVT::i32, GOT, GPRelNode); - if (getTargetMachine().getRelocationModel() != Reloc::PIC_ && !IsN64) { - SDValue CPHi = DAG.getTargetConstantPool(C, MVT::i32, N->getAlignment(), - N->getOffset(), MipsII::MO_ABS_HI); - SDValue CPLo = DAG.getTargetConstantPool(C, MVT::i32, N->getAlignment(), - N->getOffset(), MipsII::MO_ABS_LO); - SDValue HiPart = DAG.getNode(MipsISD::Hi, dl, MVT::i32, CPHi); - SDValue Lo = DAG.getNode(MipsISD::Lo, dl, MVT::i32, CPLo); - ResNode = DAG.getNode(ISD::ADD, dl, MVT::i32, HiPart, Lo); - } else { - EVT ValTy = Op.getValueType(); - unsigned GOTFlag = HasMips64 ? MipsII::MO_GOT_PAGE : MipsII::MO_GOT; - unsigned OFSTFlag = HasMips64 ? MipsII::MO_GOT_OFST : MipsII::MO_ABS_LO; - SDValue CP = DAG.getTargetConstantPool(C, ValTy, N->getAlignment(), - N->getOffset(), GOTFlag); - CP = DAG.getNode(MipsISD::Wrapper, dl, ValTy, GetGlobalReg(DAG, ValTy), CP); - SDValue Load = DAG.getLoad(ValTy, dl, DAG.getEntryNode(), CP, - MachinePointerInfo::getConstantPool(), false, - false, false, 0); - SDValue CPLo = DAG.getTargetConstantPool(C, ValTy, N->getAlignment(), - N->getOffset(), OFSTFlag); - SDValue Lo = DAG.getNode(MipsISD::Lo, dl, ValTy, CPLo); - ResNode = DAG.getNode(ISD::ADD, dl, ValTy, Load, Lo); - } + if (getTargetMachine().getRelocationModel() != Reloc::PIC_ && !IsN64) + return getAddrNonPIC(Op, DAG); - return ResNode; + return getAddrLocal(Op, DAG, HasMips64); } SDValue MipsTargetLowering::LowerVASTART(SDValue Op, SelectionDAG &DAG) const { @@ -2009,6 +2215,51 @@ LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const { return FrameAddr; } +SDValue MipsTargetLowering::LowerRETURNADDR(SDValue Op, + SelectionDAG &DAG) const { + // check the depth + assert((cast(Op.getOperand(0))->getZExtValue() == 0) && + "Return address can be determined only for current frame."); + + MachineFunction &MF = DAG.getMachineFunction(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + MVT VT = Op.getSimpleValueType(); + unsigned RA = IsN64 ? Mips::RA_64 : Mips::RA; + MFI->setReturnAddressIsTaken(true); + + // Return RA, which contains the return address. Mark it an implicit live-in. + unsigned Reg = MF.addLiveIn(RA, getRegClassFor(VT)); + return DAG.getCopyFromReg(DAG.getEntryNode(), Op.getDebugLoc(), Reg, VT); +} + +// An EH_RETURN is the result of lowering llvm.eh.return which in turn is +// generated from __builtin_eh_return (offset, handler) +// The effect of this is to adjust the stack pointer by "offset" +// and then branch to "handler". +SDValue MipsTargetLowering::LowerEH_RETURN(SDValue Op, SelectionDAG &DAG) + const { + MachineFunction &MF = DAG.getMachineFunction(); + MipsFunctionInfo *MipsFI = MF.getInfo(); + + MipsFI->setCallsEhReturn(); + SDValue Chain = Op.getOperand(0); + SDValue Offset = Op.getOperand(1); + SDValue Handler = Op.getOperand(2); + DebugLoc DL = Op.getDebugLoc(); + EVT Ty = IsN64 ? MVT::i64 : MVT::i32; + + // Store stack offset in V1, store jump target in V0. Glue CopyToReg and + // EH_RETURN nodes, so that instructions are emitted back-to-back. + unsigned OffsetReg = IsN64 ? Mips::V1_64 : Mips::V1; + unsigned AddrReg = IsN64 ? Mips::V0_64 : Mips::V0; + Chain = DAG.getCopyToReg(Chain, DL, OffsetReg, Offset, SDValue()); + Chain = DAG.getCopyToReg(Chain, DL, AddrReg, Handler, Chain.getValue(1)); + return DAG.getNode(MipsISD::EH_RETURN, DL, MVT::Other, Chain, + DAG.getRegister(OffsetReg, Ty), + DAG.getRegister(AddrReg, getPointerTy()), + Chain.getValue(1)); +} + // TODO: set SType according to the desired memory barrier behavior. SDValue MipsTargetLowering::LowerMEMBARRIER(SDValue Op, SelectionDAG &DAG) const { @@ -2232,6 +2483,172 @@ SDValue MipsTargetLowering::LowerSTORE(SDValue Op, SelectionDAG &DAG) const { return CreateStoreLR(MipsISD::SDR, DAG, SD, SDL, IsLittle ? 0 : 7); } +// This function expands mips intrinsic nodes which have 64-bit input operands +// or output values. +// +// out64 = intrinsic-node in64 +// => +// lo = copy (extract-element (in64, 0)) +// hi = copy (extract-element (in64, 1)) +// mips-specific-node +// v0 = copy lo +// v1 = copy hi +// out64 = merge-values (v0, v1) +// +static SDValue LowerDSPIntr(SDValue Op, SelectionDAG &DAG, + unsigned Opc, bool HasI64In, bool HasI64Out) { + DebugLoc DL = Op.getDebugLoc(); + bool HasChainIn = Op->getOperand(0).getValueType() == MVT::Other; + SDValue Chain = HasChainIn ? Op->getOperand(0) : DAG.getEntryNode(); + SmallVector Ops; + + if (HasI64In) { + SDValue InLo = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i32, + Op->getOperand(1 + HasChainIn), + DAG.getConstant(0, MVT::i32)); + SDValue InHi = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, MVT::i32, + Op->getOperand(1 + HasChainIn), + DAG.getConstant(1, MVT::i32)); + + Chain = DAG.getCopyToReg(Chain, DL, Mips::LO, InLo, SDValue()); + Chain = DAG.getCopyToReg(Chain, DL, Mips::HI, InHi, Chain.getValue(1)); + + Ops.push_back(Chain); + Ops.append(Op->op_begin() + HasChainIn + 2, Op->op_end()); + Ops.push_back(Chain.getValue(1)); + } else { + Ops.push_back(Chain); + Ops.append(Op->op_begin() + HasChainIn + 1, Op->op_end()); + } + + if (!HasI64Out) + return DAG.getNode(Opc, DL, Op->value_begin(), Op->getNumValues(), + Ops.begin(), Ops.size()); + + SDValue Intr = DAG.getNode(Opc, DL, DAG.getVTList(MVT::Other, MVT::Glue), + Ops.begin(), Ops.size()); + SDValue OutLo = DAG.getCopyFromReg(Intr.getValue(0), DL, Mips::LO, MVT::i32, + Intr.getValue(1)); + SDValue OutHi = DAG.getCopyFromReg(OutLo.getValue(1), DL, Mips::HI, MVT::i32, + OutLo.getValue(2)); + SDValue Out = DAG.getNode(ISD::BUILD_PAIR, DL, MVT::i64, OutLo, OutHi); + + if (!HasChainIn) + return Out; + + SDValue Vals[] = { Out, OutHi.getValue(1) }; + return DAG.getMergeValues(Vals, 2, DL); +} + +SDValue MipsTargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op, + SelectionDAG &DAG) const { + switch (cast(Op->getOperand(0))->getZExtValue()) { + default: + return SDValue(); + case Intrinsic::mips_shilo: + return LowerDSPIntr(Op, DAG, MipsISD::SHILO, true, true); + case Intrinsic::mips_dpau_h_qbl: + return LowerDSPIntr(Op, DAG, MipsISD::DPAU_H_QBL, true, true); + case Intrinsic::mips_dpau_h_qbr: + return LowerDSPIntr(Op, DAG, MipsISD::DPAU_H_QBR, true, true); + case Intrinsic::mips_dpsu_h_qbl: + return LowerDSPIntr(Op, DAG, MipsISD::DPSU_H_QBL, true, true); + case Intrinsic::mips_dpsu_h_qbr: + return LowerDSPIntr(Op, DAG, MipsISD::DPSU_H_QBR, true, true); + case Intrinsic::mips_dpa_w_ph: + return LowerDSPIntr(Op, DAG, MipsISD::DPA_W_PH, true, true); + case Intrinsic::mips_dps_w_ph: + return LowerDSPIntr(Op, DAG, MipsISD::DPS_W_PH, true, true); + case Intrinsic::mips_dpax_w_ph: + return LowerDSPIntr(Op, DAG, MipsISD::DPAX_W_PH, true, true); + case Intrinsic::mips_dpsx_w_ph: + return LowerDSPIntr(Op, DAG, MipsISD::DPSX_W_PH, true, true); + case Intrinsic::mips_mulsa_w_ph: + return LowerDSPIntr(Op, DAG, MipsISD::MULSA_W_PH, true, true); + case Intrinsic::mips_mult: + return LowerDSPIntr(Op, DAG, MipsISD::MULT, false, true); + case Intrinsic::mips_multu: + return LowerDSPIntr(Op, DAG, MipsISD::MULTU, false, true); + case Intrinsic::mips_madd: + return LowerDSPIntr(Op, DAG, MipsISD::MADD_DSP, true, true); + case Intrinsic::mips_maddu: + return LowerDSPIntr(Op, DAG, MipsISD::MADDU_DSP, true, true); + case Intrinsic::mips_msub: + return LowerDSPIntr(Op, DAG, MipsISD::MSUB_DSP, true, true); + case Intrinsic::mips_msubu: + return LowerDSPIntr(Op, DAG, MipsISD::MSUBU_DSP, true, true); + } +} + +SDValue MipsTargetLowering::LowerINTRINSIC_W_CHAIN(SDValue Op, + SelectionDAG &DAG) const { + switch (cast(Op->getOperand(1))->getZExtValue()) { + default: + return SDValue(); + case Intrinsic::mips_extp: + return LowerDSPIntr(Op, DAG, MipsISD::EXTP, true, false); + case Intrinsic::mips_extpdp: + return LowerDSPIntr(Op, DAG, MipsISD::EXTPDP, true, false); + case Intrinsic::mips_extr_w: + return LowerDSPIntr(Op, DAG, MipsISD::EXTR_W, true, false); + case Intrinsic::mips_extr_r_w: + return LowerDSPIntr(Op, DAG, MipsISD::EXTR_R_W, true, false); + case Intrinsic::mips_extr_rs_w: + return LowerDSPIntr(Op, DAG, MipsISD::EXTR_RS_W, true, false); + case Intrinsic::mips_extr_s_h: + return LowerDSPIntr(Op, DAG, MipsISD::EXTR_S_H, true, false); + case Intrinsic::mips_mthlip: + return LowerDSPIntr(Op, DAG, MipsISD::MTHLIP, true, true); + case Intrinsic::mips_mulsaq_s_w_ph: + return LowerDSPIntr(Op, DAG, MipsISD::MULSAQ_S_W_PH, true, true); + case Intrinsic::mips_maq_s_w_phl: + return LowerDSPIntr(Op, DAG, MipsISD::MAQ_S_W_PHL, true, true); + case Intrinsic::mips_maq_s_w_phr: + return LowerDSPIntr(Op, DAG, MipsISD::MAQ_S_W_PHR, true, true); + case Intrinsic::mips_maq_sa_w_phl: + return LowerDSPIntr(Op, DAG, MipsISD::MAQ_SA_W_PHL, true, true); + case Intrinsic::mips_maq_sa_w_phr: + return LowerDSPIntr(Op, DAG, MipsISD::MAQ_SA_W_PHR, true, true); + case Intrinsic::mips_dpaq_s_w_ph: + return LowerDSPIntr(Op, DAG, MipsISD::DPAQ_S_W_PH, true, true); + case Intrinsic::mips_dpsq_s_w_ph: + return LowerDSPIntr(Op, DAG, MipsISD::DPSQ_S_W_PH, true, true); + case Intrinsic::mips_dpaq_sa_l_w: + return LowerDSPIntr(Op, DAG, MipsISD::DPAQ_SA_L_W, true, true); + case Intrinsic::mips_dpsq_sa_l_w: + return LowerDSPIntr(Op, DAG, MipsISD::DPSQ_SA_L_W, true, true); + case Intrinsic::mips_dpaqx_s_w_ph: + return LowerDSPIntr(Op, DAG, MipsISD::DPAQX_S_W_PH, true, true); + case Intrinsic::mips_dpaqx_sa_w_ph: + return LowerDSPIntr(Op, DAG, MipsISD::DPAQX_SA_W_PH, true, true); + case Intrinsic::mips_dpsqx_s_w_ph: + return LowerDSPIntr(Op, DAG, MipsISD::DPSQX_S_W_PH, true, true); + case Intrinsic::mips_dpsqx_sa_w_ph: + return LowerDSPIntr(Op, DAG, MipsISD::DPSQX_SA_W_PH, true, true); + } +} + +SDValue MipsTargetLowering::LowerADD(SDValue Op, SelectionDAG &DAG) const { + if (Op->getOperand(0).getOpcode() != ISD::FRAMEADDR + || cast + (Op->getOperand(0).getOperand(0))->getZExtValue() != 0 + || Op->getOperand(1).getOpcode() != ISD::FRAME_TO_ARGS_OFFSET) + return SDValue(); + + // The pattern + // (add (frameaddr 0), (frame_to_args_offset)) + // results from lowering llvm.eh.dwarf.cfa intrinsic. Transform it to + // (add FrameObject, 0) + // where FrameObject is a fixed StackObject with offset 0 which points to + // the old stack pointer. + MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo(); + EVT ValTy = Op->getValueType(0); + int FI = MFI->CreateFixedObject(Op.getValueSizeInBits() / 8, 0, false); + SDValue InArgsAddr = DAG.getFrameIndex(FI, ValTy); + return DAG.getNode(ISD::ADD, Op->getDebugLoc(), ValTy, InArgsAddr, + DAG.getConstant(0, ValTy)); +} + //===----------------------------------------------------------------------===// // Calling Convention Implementation //===----------------------------------------------------------------------===// @@ -2267,16 +2684,9 @@ static bool CC_MipsO32(unsigned ValNo, MVT ValVT, Mips::D6, Mips::D7 }; - // ByVal Args - if (ArgFlags.isByVal()) { - State.HandleByVal(ValNo, ValVT, LocVT, LocInfo, - 1 /*MinSize*/, 4 /*MinAlign*/, ArgFlags); - unsigned NextReg = (State.getNextStackOffset() + 3) / 4; - for (unsigned r = State.getFirstUnallocated(IntRegs, IntRegsSize); - r < std::min(IntRegsSize, NextReg); ++r) - State.AllocateReg(IntRegs[r]); - return false; - } + // Do not process byval args here. + if (ArgFlags.isByVal()) + return true; // Promote i8 and i16 if (LocVT == MVT::i8 || LocVT == MVT::i16) { @@ -2331,279 +2741,229 @@ static bool CC_MipsO32(unsigned ValNo, MVT ValVT, } else llvm_unreachable("Cannot handle this ValVT."); - unsigned SizeInBytes = ValVT.getSizeInBits() >> 3; - unsigned Offset = State.AllocateStack(SizeInBytes, OrigAlign); - - if (!Reg) + if (!Reg) { + unsigned Offset = State.AllocateStack(ValVT.getSizeInBits() >> 3, + OrigAlign); State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset, LocVT, LocInfo)); - else + } else State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo)); - return false; // CC must always match -} - -static const uint16_t Mips64IntRegs[8] = - {Mips::A0_64, Mips::A1_64, Mips::A2_64, Mips::A3_64, - Mips::T0_64, Mips::T1_64, Mips::T2_64, Mips::T3_64}; -static const uint16_t Mips64DPRegs[8] = - {Mips::D12_64, Mips::D13_64, Mips::D14_64, Mips::D15_64, - Mips::D16_64, Mips::D17_64, Mips::D18_64, Mips::D19_64}; - -static bool CC_Mips64Byval(unsigned ValNo, MVT ValVT, MVT LocVT, - CCValAssign::LocInfo LocInfo, - ISD::ArgFlagsTy ArgFlags, CCState &State) { - unsigned Align = std::max(ArgFlags.getByValAlign(), (unsigned)8); - unsigned Size = (ArgFlags.getByValSize() + 7) / 8 * 8; - unsigned FirstIdx = State.getFirstUnallocated(Mips64IntRegs, 8); - - assert(Align <= 16 && "Cannot handle alignments larger than 16."); - - // If byval is 16-byte aligned, the first arg register must be even. - if ((Align == 16) && (FirstIdx % 2)) { - State.AllocateReg(Mips64IntRegs[FirstIdx], Mips64DPRegs[FirstIdx]); - ++FirstIdx; - } - - // Mark the registers allocated. - for (unsigned I = FirstIdx; Size && (I < 8); Size -= 8, ++I) - State.AllocateReg(Mips64IntRegs[I], Mips64DPRegs[I]); - - // Allocate space on caller's stack. - unsigned Offset = State.AllocateStack(Size, Align); - - if (FirstIdx < 8) - State.addLoc(CCValAssign::getReg(ValNo, ValVT, Mips64IntRegs[FirstIdx], - LocVT, LocInfo)); - else - State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset, LocVT, LocInfo)); - - return true; + return false; } #include "MipsGenCallingConv.inc" -static void -AnalyzeMips64CallOperands(CCState &CCInfo, - const SmallVectorImpl &Outs) { - unsigned NumOps = Outs.size(); - for (unsigned i = 0; i != NumOps; ++i) { - MVT ArgVT = Outs[i].VT; - ISD::ArgFlagsTy ArgFlags = Outs[i].Flags; - bool R; - - if (Outs[i].IsFixed) - R = CC_MipsN(i, ArgVT, ArgVT, CCValAssign::Full, ArgFlags, CCInfo); - else - R = CC_MipsN_VarArg(i, ArgVT, ArgVT, CCValAssign::Full, ArgFlags, CCInfo); - - if (R) { -#ifndef NDEBUG - dbgs() << "Call operand #" << i << " has unhandled type " - << EVT(ArgVT).getEVTString(); -#endif - llvm_unreachable(0); - } - } -} - //===----------------------------------------------------------------------===// // Call Calling Convention Implementation //===----------------------------------------------------------------------===// static const unsigned O32IntRegsSize = 4; -static const uint16_t O32IntRegs[] = { - Mips::A0, Mips::A1, Mips::A2, Mips::A3 -}; - // Return next O32 integer argument register. static unsigned getNextIntArgReg(unsigned Reg) { assert((Reg == Mips::A0) || (Reg == Mips::A2)); return (Reg == Mips::A0) ? Mips::A1 : Mips::A3; } -// Write ByVal Arg to arg registers and stack. -static void -WriteByValArg(SDValue& ByValChain, SDValue Chain, DebugLoc dl, - SmallVector, 16> &RegsToPass, - SmallVector &MemOpChains, int &LastFI, - MachineFrameInfo *MFI, SelectionDAG &DAG, SDValue Arg, - const CCValAssign &VA, const ISD::ArgFlagsTy &Flags, - MVT PtrType, bool isLittle) { - unsigned LocMemOffset = VA.getLocMemOffset(); - unsigned Offset = 0; - uint32_t RemainingSize = Flags.getByValSize(); - unsigned ByValAlign = Flags.getByValAlign(); - - // Copy the first 4 words of byval arg to registers A0 - A3. - // FIXME: Use a stricter alignment if it enables better optimization in passes - // run later. - for (; RemainingSize >= 4 && LocMemOffset < 4 * 4; - Offset += 4, RemainingSize -= 4, LocMemOffset += 4) { - SDValue LoadPtr = DAG.getNode(ISD::ADD, dl, MVT::i32, Arg, - DAG.getConstant(Offset, MVT::i32)); - SDValue LoadVal = DAG.getLoad(MVT::i32, dl, Chain, LoadPtr, - MachinePointerInfo(), false, false, false, - std::min(ByValAlign, (unsigned )4)); - MemOpChains.push_back(LoadVal.getValue(1)); - unsigned DstReg = O32IntRegs[LocMemOffset / 4]; - RegsToPass.push_back(std::make_pair(DstReg, LoadVal)); - } - - if (RemainingSize == 0) - return; - - // If there still is a register available for argument passing, write the - // remaining part of the structure to it using subword loads and shifts. - if (LocMemOffset < 4 * 4) { - assert(RemainingSize <= 3 && RemainingSize >= 1 && - "There must be one to three bytes remaining."); - unsigned LoadSize = (RemainingSize == 3 ? 2 : RemainingSize); - SDValue LoadPtr = DAG.getNode(ISD::ADD, dl, MVT::i32, Arg, - DAG.getConstant(Offset, MVT::i32)); - unsigned Alignment = std::min(ByValAlign, (unsigned )4); - SDValue LoadVal = DAG.getExtLoad(ISD::ZEXTLOAD, dl, MVT::i32, Chain, - LoadPtr, MachinePointerInfo(), - MVT::getIntegerVT(LoadSize * 8), false, - false, Alignment); - MemOpChains.push_back(LoadVal.getValue(1)); - - // If target is big endian, shift it to the most significant half-word or - // byte. - if (!isLittle) - LoadVal = DAG.getNode(ISD::SHL, dl, MVT::i32, LoadVal, - DAG.getConstant(32 - LoadSize * 8, MVT::i32)); - - Offset += LoadSize; - RemainingSize -= LoadSize; - - // Read second subword if necessary. - if (RemainingSize != 0) { - assert(RemainingSize == 1 && "There must be one byte remaining."); - LoadPtr = DAG.getNode(ISD::ADD, dl, MVT::i32, Arg, - DAG.getConstant(Offset, MVT::i32)); - unsigned Alignment = std::min(ByValAlign, (unsigned )2); - SDValue Subword = DAG.getExtLoad(ISD::ZEXTLOAD, dl, MVT::i32, Chain, - LoadPtr, MachinePointerInfo(), - MVT::i8, false, false, Alignment); - MemOpChains.push_back(Subword.getValue(1)); - // Insert the loaded byte to LoadVal. - // FIXME: Use INS if supported by target. - unsigned ShiftAmt = isLittle ? 16 : 8; - SDValue Shift = DAG.getNode(ISD::SHL, dl, MVT::i32, Subword, - DAG.getConstant(ShiftAmt, MVT::i32)); - LoadVal = DAG.getNode(ISD::OR, dl, MVT::i32, LoadVal, Shift); - } - - unsigned DstReg = O32IntRegs[LocMemOffset / 4]; - RegsToPass.push_back(std::make_pair(DstReg, LoadVal)); - return; - } - - // Create a fixed object on stack at offset LocMemOffset and copy - // remaining part of byval arg to it using memcpy. - SDValue Src = DAG.getNode(ISD::ADD, dl, MVT::i32, Arg, - DAG.getConstant(Offset, MVT::i32)); - LastFI = MFI->CreateFixedObject(RemainingSize, LocMemOffset, true); - SDValue Dst = DAG.getFrameIndex(LastFI, PtrType); - ByValChain = DAG.getMemcpy(ByValChain, dl, Dst, Src, - DAG.getConstant(RemainingSize, MVT::i32), - std::min(ByValAlign, (unsigned)4), - /*isVolatile=*/false, /*AlwaysInline=*/false, - MachinePointerInfo(0), MachinePointerInfo(0)); -} - -// Copy Mips64 byVal arg to registers and stack. -void static -PassByValArg64(SDValue& ByValChain, SDValue Chain, DebugLoc dl, - SmallVector, 16> &RegsToPass, - SmallVector &MemOpChains, int &LastFI, - MachineFrameInfo *MFI, SelectionDAG &DAG, SDValue Arg, - const CCValAssign &VA, const ISD::ArgFlagsTy &Flags, - EVT PtrTy, bool isLittle) { - unsigned ByValSize = Flags.getByValSize(); - unsigned Alignment = std::min(Flags.getByValAlign(), (unsigned)8); - bool IsRegLoc = VA.isRegLoc(); - unsigned Offset = 0; // Offset in # of bytes from the beginning of struct. - unsigned LocMemOffset = 0; - unsigned MemCpySize = ByValSize; - - if (!IsRegLoc) - LocMemOffset = VA.getLocMemOffset(); - else { - const uint16_t *Reg = std::find(Mips64IntRegs, Mips64IntRegs + 8, - VA.getLocReg()); - const uint16_t *RegEnd = Mips64IntRegs + 8; +/// IsEligibleForTailCallOptimization - Check whether the call is eligible +/// for tail call optimization. +bool MipsTargetLowering:: +IsEligibleForTailCallOptimization(const MipsCC &MipsCCInfo, + unsigned NextStackOffset, + const MipsFunctionInfo& FI) const { + if (!EnableMipsTailCalls) + return false; - // Copy double words to registers. - for (; (Reg != RegEnd) && (ByValSize >= Offset + 8); ++Reg, Offset += 8) { - SDValue LoadPtr = DAG.getNode(ISD::ADD, dl, PtrTy, Arg, - DAG.getConstant(Offset, PtrTy)); - SDValue LoadVal = DAG.getLoad(MVT::i64, dl, Chain, LoadPtr, - MachinePointerInfo(), false, false, false, - Alignment); - MemOpChains.push_back(LoadVal.getValue(1)); - RegsToPass.push_back(std::make_pair(*Reg, LoadVal)); - } + // No tail call optimization for mips16. + if (Subtarget->inMips16Mode()) + return false; - // Return if the struct has been fully copied. - if (!(MemCpySize = ByValSize - Offset)) - return; + // Return false if either the callee or caller has a byval argument. + if (MipsCCInfo.hasByValArg() || FI.hasByvalArg()) + return false; - // If there is an argument register available, copy the remainder of the - // byval argument with sub-doubleword loads and shifts. - if (Reg != RegEnd) { - assert((ByValSize < Offset + 8) && - "Size of the remainder should be smaller than 8-byte."); - SDValue Val; - for (unsigned LoadSize = 4; Offset < ByValSize; LoadSize /= 2) { - unsigned RemSize = ByValSize - Offset; + // Return true if the callee's argument area is no larger than the + // caller's. + return NextStackOffset <= FI.getIncomingArgSize(); +} - if (RemSize < LoadSize) - continue; +SDValue +MipsTargetLowering::passArgOnStack(SDValue StackPtr, unsigned Offset, + SDValue Chain, SDValue Arg, DebugLoc DL, + bool IsTailCall, SelectionDAG &DAG) const { + if (!IsTailCall) { + SDValue PtrOff = DAG.getNode(ISD::ADD, DL, getPointerTy(), StackPtr, + DAG.getIntPtrConstant(Offset)); + return DAG.getStore(Chain, DL, Arg, PtrOff, MachinePointerInfo(), false, + false, 0); + } - SDValue LoadPtr = DAG.getNode(ISD::ADD, dl, PtrTy, Arg, - DAG.getConstant(Offset, PtrTy)); - SDValue LoadVal = - DAG.getExtLoad(ISD::ZEXTLOAD, dl, MVT::i64, Chain, LoadPtr, - MachinePointerInfo(), MVT::getIntegerVT(LoadSize * 8), - false, false, Alignment); - MemOpChains.push_back(LoadVal.getValue(1)); + MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo(); + int FI = MFI->CreateFixedObject(Arg.getValueSizeInBits() / 8, Offset, false); + SDValue FIN = DAG.getFrameIndex(FI, getPointerTy()); + return DAG.getStore(Chain, DL, Arg, FIN, MachinePointerInfo(), + /*isVolatile=*/ true, false, 0); +} - // Offset in number of bits from double word boundary. - unsigned OffsetDW = (Offset % 8) * 8; - unsigned Shamt = isLittle ? OffsetDW : 64 - (OffsetDW + LoadSize * 8); - SDValue Shift = DAG.getNode(ISD::SHL, dl, MVT::i64, LoadVal, - DAG.getConstant(Shamt, MVT::i32)); +// +// The Mips16 hard float is a crazy quilt inherited from gcc. I have a much +// cleaner way to do all of this but it will have to wait until the traditional +// gcc mechanism is completed. +// +// For Pic, in order for Mips16 code to call Mips32 code which according the abi +// have either arguments or returned values placed in floating point registers, +// we use a set of helper functions. (This includes functions which return type +// complex which on Mips are returned in a pair of floating point registers). +// +// This is an encoding that we inherited from gcc. +// In Mips traditional O32, N32 ABI, floating point numbers are passed in +// floating point argument registers 1,2 only when the first and optionally +// the second arguments are float (sf) or double (df). +// For Mips16 we are only concerned with the situations where floating point +// arguments are being passed in floating point registers by the ABI, because +// Mips16 mode code cannot execute floating point instructions to load those +// values and hence helper functions are needed. +// The possibilities are (), (sf), (sf, sf), (sf, df), (df), (df, sf), (df, df) +// the helper function suffixs for these are: +// 0, 1, 5, 9, 2, 6, 10 +// this suffix can then be calculated as follows: +// for a given argument Arg: +// Arg1x, Arg2x = 1 : Arg is sf +// 2 : Arg is df +// 0: Arg is neither sf or df +// So this stub is the string for number Arg1x + Arg2x*4. +// However not all numbers between 0 and 10 are possible, we check anyway and +// assert if the impossible exists. +// - Val = Val.getNode() ? DAG.getNode(ISD::OR, dl, MVT::i64, Val, Shift) : - Shift; - Offset += LoadSize; - Alignment = std::min(Alignment, LoadSize); +unsigned int MipsTargetLowering::getMips16HelperFunctionStubNumber + (ArgListTy &Args) const { + unsigned int resultNum = 0; + if (Args.size() >= 1) { + Type *t = Args[0].Ty; + if (t->isFloatTy()) { + resultNum = 1; + } + else if (t->isDoubleTy()) { + resultNum = 2; + } + } + if (resultNum) { + if (Args.size() >=2) { + Type *t = Args[1].Ty; + if (t->isFloatTy()) { + resultNum += 4; + } + else if (t->isDoubleTy()) { + resultNum += 8; } - - RegsToPass.push_back(std::make_pair(*Reg, Val)); - return; } } + return resultNum; +} - assert(MemCpySize && "MemCpySize must not be zero."); - - // Create a fixed object on stack at offset LocMemOffset and copy - // remainder of byval arg to it with memcpy. - SDValue Src = DAG.getNode(ISD::ADD, dl, PtrTy, Arg, - DAG.getConstant(Offset, PtrTy)); - LastFI = MFI->CreateFixedObject(MemCpySize, LocMemOffset, true); - SDValue Dst = DAG.getFrameIndex(LastFI, PtrTy); - ByValChain = DAG.getMemcpy(ByValChain, dl, Dst, Src, - DAG.getConstant(MemCpySize, PtrTy), Alignment, - /*isVolatile=*/false, /*AlwaysInline=*/false, - MachinePointerInfo(0), MachinePointerInfo(0)); +// +// prefixs are attached to stub numbers depending on the return type . +// return type: float sf_ +// double df_ +// single complex sc_ +// double complext dc_ +// others NO PREFIX +// +// +// The full name of a helper function is__mips16_call_stub + +// return type dependent prefix + stub number +// +// +// This is something that probably should be in a different source file and +// perhaps done differently but my main purpose is to not waste runtime +// on something that we can enumerate in the source. Another possibility is +// to have a python script to generate these mapping tables. This will do +// for now. There are a whole series of helper function mapping arrays, one +// for each return type class as outlined above. There there are 11 possible +// entries. Ones with 0 are ones which should never be selected +// +// All the arrays are similar except for ones which return neither +// sf, df, sc, dc, in which only care about ones which have sf or df as a +// first parameter. +// +#define P_ "__mips16_call_stub_" +#define MAX_STUB_NUMBER 10 +#define T1 P "1", P "2", 0, 0, P "5", P "6", 0, 0, P "9", P "10" +#define T P "0" , T1 +#define P P_ +static char const * vMips16Helper[MAX_STUB_NUMBER+1] = + {0, T1 }; +#undef P +#define P P_ "sf_" +static char const * sfMips16Helper[MAX_STUB_NUMBER+1] = + { T }; +#undef P +#define P P_ "df_" +static char const * dfMips16Helper[MAX_STUB_NUMBER+1] = + { T }; +#undef P +#define P P_ "sc_" +static char const * scMips16Helper[MAX_STUB_NUMBER+1] = + { T }; +#undef P +#define P P_ "dc_" +static char const * dcMips16Helper[MAX_STUB_NUMBER+1] = + { T }; +#undef P +#undef P_ + + +const char* MipsTargetLowering:: + getMips16HelperFunction + (Type* RetTy, ArgListTy &Args, bool &needHelper) const { + const unsigned int stubNum = getMips16HelperFunctionStubNumber(Args); +#ifndef NDEBUG + const unsigned int maxStubNum = 10; + assert(stubNum <= maxStubNum); + const bool validStubNum[maxStubNum+1] = + {true, true, true, false, false, true, true, false, false, true, true}; + assert(validStubNum[stubNum]); +#endif + const char *result; + if (RetTy->isFloatTy()) { + result = sfMips16Helper[stubNum]; + } + else if (RetTy ->isDoubleTy()) { + result = dfMips16Helper[stubNum]; + } + else if (RetTy->isStructTy()) { + // check if it's complex + if (RetTy->getNumContainedTypes() == 2) { + if ((RetTy->getContainedType(0)->isFloatTy()) && + (RetTy->getContainedType(1)->isFloatTy())) { + result = scMips16Helper[stubNum]; + } + else if ((RetTy->getContainedType(0)->isDoubleTy()) && + (RetTy->getContainedType(1)->isDoubleTy())) { + result = dcMips16Helper[stubNum]; + } + else { + llvm_unreachable("Uncovered condition"); + } + } + else { + llvm_unreachable("Uncovered condition"); + } + } + else { + if (stubNum == 0) { + needHelper = false; + return ""; + } + result = vMips16Helper[stubNum]; + } + needHelper = true; + return result; } /// LowerCall - functions arguments are copied from virtual regs to /// (physical regs)/(stack frame), CALLSEQ_START and CALLSEQ_END are emitted. -/// TODO: isTailCall. SDValue MipsTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, SmallVectorImpl &InVals) const { @@ -2612,76 +2972,75 @@ MipsTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, SmallVector &Outs = CLI.Outs; SmallVector &OutVals = CLI.OutVals; SmallVector &Ins = CLI.Ins; - SDValue InChain = CLI.Chain; + SDValue Chain = CLI.Chain; SDValue Callee = CLI.Callee; bool &isTailCall = CLI.IsTailCall; CallingConv::ID CallConv = CLI.CallConv; bool isVarArg = CLI.IsVarArg; - // MIPs target does not yet support tail call optimization. - isTailCall = false; + const char* mips16HelperFunction = 0; + bool needMips16Helper = false; + + if (Subtarget->inMips16Mode() && getTargetMachine().Options.UseSoftFloat && + Mips16HardFloat) { + // + // currently we don't have symbols tagged with the mips16 or mips32 + // qualifier so we will assume that we don't know what kind it is. + // and generate the helper + // + bool lookupHelper = true; + if (ExternalSymbolSDNode *S = dyn_cast(Callee)) { + if (noHelperNeeded.find(S->getSymbol()) != noHelperNeeded.end()) { + lookupHelper = false; + } + } + if (lookupHelper) mips16HelperFunction = + getMips16HelperFunction(CLI.RetTy, CLI.Args, needMips16Helper); + } MachineFunction &MF = DAG.getMachineFunction(); MachineFrameInfo *MFI = MF.getFrameInfo(); const TargetFrameLowering *TFL = MF.getTarget().getFrameLowering(); bool IsPIC = getTargetMachine().getRelocationModel() == Reloc::PIC_; - MipsFunctionInfo *MipsFI = MF.getInfo(); // Analyze operands of the call, assigning locations to each operand. SmallVector ArgLocs; CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), getTargetMachine(), ArgLocs, *DAG.getContext()); + MipsCC MipsCCInfo(CallConv, isVarArg, IsO32, CCInfo); - if (CallConv == CallingConv::Fast) - CCInfo.AnalyzeCallOperands(Outs, CC_Mips_FastCC); - else if (IsO32) - CCInfo.AnalyzeCallOperands(Outs, CC_MipsO32); - else if (HasMips64) - AnalyzeMips64CallOperands(CCInfo, Outs); - else - CCInfo.AnalyzeCallOperands(Outs, CC_Mips); + MipsCCInfo.analyzeCallOperands(Outs); // Get a count of how many bytes are to be pushed on the stack. unsigned NextStackOffset = CCInfo.getNextStackOffset(); + // Check if it's really possible to do a tail call. + if (isTailCall) + isTailCall = + IsEligibleForTailCallOptimization(MipsCCInfo, NextStackOffset, + *MF.getInfo()); + + if (isTailCall) + ++NumTailCalls; + // Chain is the output chain of the last Load/Store or CopyToReg node. // ByValChain is the output chain of the last Memcpy node created for copying // byval arguments to the stack. - SDValue Chain, CallSeqStart, ByValChain; + unsigned StackAlignment = TFL->getStackAlignment(); + NextStackOffset = RoundUpToAlignment(NextStackOffset, StackAlignment); SDValue NextStackOffsetVal = DAG.getIntPtrConstant(NextStackOffset, true); - Chain = CallSeqStart = DAG.getCALLSEQ_START(InChain, NextStackOffsetVal); - ByValChain = InChain; - // Get the frame index of the stack frame object that points to the location - // of dynamically allocated area on the stack. - int DynAllocFI = MipsFI->getDynAllocFI(); + if (!isTailCall) + Chain = DAG.getCALLSEQ_START(Chain, NextStackOffsetVal); - // Update size of the maximum argument space. - // For O32, a minimum of four words (16 bytes) of argument space is - // allocated. - if (IsO32 && (CallConv != CallingConv::Fast)) - NextStackOffset = std::max(NextStackOffset, (unsigned)16); - - unsigned MaxCallFrameSize = MipsFI->getMaxCallFrameSize(); - - if (MaxCallFrameSize < NextStackOffset) { - MipsFI->setMaxCallFrameSize(NextStackOffset); - - // Set the offsets relative to $sp of the $gp restore slot and dynamically - // allocated stack space. These offsets must be aligned to a boundary - // determined by the stack alignment of the ABI. - unsigned StackAlignment = TFL->getStackAlignment(); - NextStackOffset = (NextStackOffset + StackAlignment - 1) / - StackAlignment * StackAlignment; - - MFI->setObjectOffset(DynAllocFI, NextStackOffset); - } + SDValue StackPtr = DAG.getCopyFromReg(Chain, dl, + IsN64 ? Mips::SP_64 : Mips::SP, + getPointerTy()); // With EABI is it possible to have 16 args on registers. - SmallVector, 16> RegsToPass; + std::deque< std::pair > RegsToPass; SmallVector MemOpChains; - - int FirstFI = -MFI->getNumFixedObjects() - 1, LastFI = 0; + MipsCC::byval_iterator ByValArg = MipsCCInfo.byval_begin(); // Walk the register/memloc assignments, inserting copies/loads. for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { @@ -2694,14 +3053,12 @@ MipsTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, if (Flags.isByVal()) { assert(Flags.getByValSize() && "ByVal args of size 0 should have been ignored by front-end."); - if (IsO32) - WriteByValArg(ByValChain, Chain, dl, RegsToPass, MemOpChains, LastFI, - MFI, DAG, Arg, VA, Flags, getPointerTy(), - Subtarget->isLittle()); - else - PassByValArg64(ByValChain, Chain, dl, RegsToPass, MemOpChains, LastFI, - MFI, DAG, Arg, VA, Flags, getPointerTy(), - Subtarget->isLittle()); + assert(ByValArg != MipsCCInfo.byval_end()); + assert(!isTailCall && + "Do not tail-call optimize if there is a byval argument."); + passByValArg(Chain, dl, RegsToPass, MemOpChains, StackPtr, MFI, DAG, Arg, + MipsCCInfo, *ByValArg, Flags, Subtarget->isLittle()); + ++ByValArg; continue; } @@ -2749,29 +3106,12 @@ MipsTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, // Register can't get to this point... assert(VA.isMemLoc()); - // Create the frame index object for this incoming parameter - LastFI = MFI->CreateFixedObject(ValVT.getSizeInBits()/8, - VA.getLocMemOffset(), true); - SDValue PtrOff = DAG.getFrameIndex(LastFI, getPointerTy()); - // emit ISD::STORE whichs stores the // parameter value to a stack Location - MemOpChains.push_back(DAG.getStore(Chain, dl, Arg, PtrOff, - MachinePointerInfo(), false, false, 0)); + MemOpChains.push_back(passArgOnStack(StackPtr, VA.getLocMemOffset(), + Chain, Arg, dl, isTailCall, DAG)); } - // Extend range of indices of frame objects for outgoing arguments that were - // created during this function call. Skip this step if no such objects were - // created. - if (LastFI) - MipsFI->extendOutArgFIRange(FirstFI, LastFI); - - // If a memcpy has been created to copy a byval arg to a stack, replace the - // chain input of CallSeqStart with ByValChain. - if (InChain != ByValChain) - DAG.UpdateNodeOperands(CallSeqStart.getNode(), ByValChain, - NextStackOffsetVal); - // Transform all store nodes into one single node because all store // nodes are independent of each other. if (!MemOpChains.empty()) @@ -2781,73 +3121,68 @@ MipsTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, // If the callee is a GlobalAddress/ExternalSymbol node (quite common, every // direct call is) turn it into a TargetGlobalAddress/TargetExternalSymbol // node so that legalize doesn't hack it. - unsigned char OpFlag; bool IsPICCall = (IsN64 || IsPIC); // true if calls are translated to jalr $25 - bool GlobalOrExternal = false; + bool GlobalOrExternal = false, InternalLinkage = false; SDValue CalleeLo; if (GlobalAddressSDNode *G = dyn_cast(Callee)) { - if (IsPICCall && G->getGlobal()->hasInternalLinkage()) { - OpFlag = IsO32 ? MipsII::MO_GOT : MipsII::MO_GOT_PAGE; - unsigned char LoFlag = IsO32 ? MipsII::MO_ABS_LO : MipsII::MO_GOT_OFST; + if (IsPICCall) { + InternalLinkage = G->getGlobal()->hasInternalLinkage(); + + if (InternalLinkage) + Callee = getAddrLocal(Callee, DAG, HasMips64); + else if (LargeGOT) + Callee = getAddrGlobalLargeGOT(Callee, DAG, MipsII::MO_CALL_HI16, + MipsII::MO_CALL_LO16); + else + Callee = getAddrGlobal(Callee, DAG, MipsII::MO_GOT_CALL); + } else Callee = DAG.getTargetGlobalAddress(G->getGlobal(), dl, getPointerTy(), 0, - OpFlag); - CalleeLo = DAG.getTargetGlobalAddress(G->getGlobal(), dl, getPointerTy(), - 0, LoFlag); - } else { - OpFlag = IsPICCall ? MipsII::MO_GOT_CALL : MipsII::MO_NO_FLAG; - Callee = DAG.getTargetGlobalAddress(G->getGlobal(), dl, - getPointerTy(), 0, OpFlag); - } - + MipsII::MO_NO_FLAG); GlobalOrExternal = true; } else if (ExternalSymbolSDNode *S = dyn_cast(Callee)) { - if (IsN64 || (!IsO32 && IsPIC)) - OpFlag = MipsII::MO_GOT_DISP; - else if (!IsPIC) // !N64 && static - OpFlag = MipsII::MO_NO_FLAG; + if (!IsN64 && !IsPIC) // !N64 && static + Callee = DAG.getTargetExternalSymbol(S->getSymbol(), getPointerTy(), + MipsII::MO_NO_FLAG); + else if (LargeGOT) + Callee = getAddrGlobalLargeGOT(Callee, DAG, MipsII::MO_CALL_HI16, + MipsII::MO_CALL_LO16); + else if (HasMips64) + Callee = getAddrGlobal(Callee, DAG, MipsII::MO_GOT_DISP); else // O32 & PIC - OpFlag = MipsII::MO_GOT_CALL; - Callee = DAG.getTargetExternalSymbol(S->getSymbol(), getPointerTy(), - OpFlag); + Callee = getAddrGlobal(Callee, DAG, MipsII::MO_GOT_CALL); + GlobalOrExternal = true; } - SDValue InFlag; - - // Create nodes that load address of callee and copy it to T9 - if (IsPICCall) { - if (GlobalOrExternal) { - // Load callee address - Callee = DAG.getNode(MipsISD::Wrapper, dl, getPointerTy(), - GetGlobalReg(DAG, getPointerTy()), Callee); - SDValue LoadValue = DAG.getLoad(getPointerTy(), dl, DAG.getEntryNode(), - Callee, MachinePointerInfo::getGOT(), - false, false, false, 0); - - // Use GOT+LO if callee has internal linkage. - if (CalleeLo.getNode()) { - SDValue Lo = DAG.getNode(MipsISD::Lo, dl, getPointerTy(), CalleeLo); - Callee = DAG.getNode(ISD::ADD, dl, getPointerTy(), LoadValue, Lo); - } else - Callee = LoadValue; - } - } + SDValue JumpTarget = Callee; // T9 should contain the address of the callee function if // -reloction-model=pic or it is an indirect call. if (IsPICCall || !GlobalOrExternal) { - // copy to T9 unsigned T9Reg = IsN64 ? Mips::T9_64 : Mips::T9; - Chain = DAG.getCopyToReg(Chain, dl, T9Reg, Callee, SDValue(0, 0)); - InFlag = Chain.getValue(1); - Callee = DAG.getRegister(T9Reg, getPointerTy()); + unsigned V0Reg = Mips::V0; + if (needMips16Helper) { + RegsToPass.push_front(std::make_pair(V0Reg, Callee)); + JumpTarget = DAG.getExternalSymbol( + mips16HelperFunction, getPointerTy()); + JumpTarget = getAddrGlobal(JumpTarget, DAG, MipsII::MO_GOT); + } + else { + RegsToPass.push_front(std::make_pair(T9Reg, Callee)); + + if (!Subtarget->inMips16Mode()) + JumpTarget = SDValue(); + } } // Insert node "GP copy globalreg" before call to function. - // Lazy-binding stubs require GP to point to the GOT. - if (IsPICCall) { + // + // R_MIPS_CALL* operators (emitted when non-internal functions are called + // in PIC mode) allow symbols to be resolved via lazy binding. + // The lazy binding stub requires GP to point to the GOT. + if (IsPICCall && !InternalLinkage) { unsigned GPReg = IsN64 ? Mips::GP_64 : Mips::GP; EVT Ty = IsN64 ? MVT::i64 : MVT::i32; RegsToPass.push_back(std::make_pair(GPReg, GetGlobalReg(DAG, Ty))); @@ -2857,6 +3192,8 @@ MipsTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, // chain and flag operands which copy the outgoing args into registers. // The InFlag in necessary since all emitted instructions must be // stuck together. + SDValue InFlag; + for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) { Chain = DAG.getCopyToReg(Chain, dl, RegsToPass[i].first, RegsToPass[i].second, InFlag); @@ -2868,9 +3205,10 @@ MipsTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, // // Returns a chain & a flag for retval copy to use. SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue); - SmallVector Ops; - Ops.push_back(Chain); - Ops.push_back(Callee); + SmallVector Ops(1, Chain); + + if (JumpTarget.getNode()) + Ops.push_back(JumpTarget); // Add argument registers to the end of the list so that they are // known live into the call. @@ -2887,12 +3225,14 @@ MipsTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, if (InFlag.getNode()) Ops.push_back(InFlag); + if (isTailCall) + return DAG.getNode(MipsISD::TailCall, dl, MVT::Other, &Ops[0], Ops.size()); + Chain = DAG.getNode(MipsISD::JmpLink, dl, NodeTys, &Ops[0], Ops.size()); InFlag = Chain.getValue(1); // Create the CALLSEQ_END node. - Chain = DAG.getCALLSEQ_END(Chain, - DAG.getIntPtrConstant(NextStackOffset, true), + Chain = DAG.getCALLSEQ_END(Chain, NextStackOffsetVal, DAG.getIntPtrConstant(0, true), InFlag); InFlag = Chain.getValue(1); @@ -2931,70 +3271,6 @@ MipsTargetLowering::LowerCallResult(SDValue Chain, SDValue InFlag, //===----------------------------------------------------------------------===// // Formal Arguments Calling Convention Implementation //===----------------------------------------------------------------------===// -static void ReadByValArg(MachineFunction &MF, SDValue Chain, DebugLoc dl, - std::vector &OutChains, - SelectionDAG &DAG, unsigned NumWords, SDValue FIN, - const CCValAssign &VA, const ISD::ArgFlagsTy &Flags, - const Argument *FuncArg) { - unsigned LocMem = VA.getLocMemOffset(); - unsigned FirstWord = LocMem / 4; - - // copy register A0 - A3 to frame object - for (unsigned i = 0; i < NumWords; ++i) { - unsigned CurWord = FirstWord + i; - if (CurWord >= O32IntRegsSize) - break; - - unsigned SrcReg = O32IntRegs[CurWord]; - unsigned Reg = AddLiveIn(MF, SrcReg, &Mips::CPURegsRegClass); - SDValue StorePtr = DAG.getNode(ISD::ADD, dl, MVT::i32, FIN, - DAG.getConstant(i * 4, MVT::i32)); - SDValue Store = DAG.getStore(Chain, dl, DAG.getRegister(Reg, MVT::i32), - StorePtr, MachinePointerInfo(FuncArg, i * 4), - false, false, 0); - OutChains.push_back(Store); - } -} - -// Create frame object on stack and copy registers used for byval passing to it. -static unsigned -CopyMips64ByValRegs(MachineFunction &MF, SDValue Chain, DebugLoc dl, - std::vector &OutChains, SelectionDAG &DAG, - const CCValAssign &VA, const ISD::ArgFlagsTy &Flags, - MachineFrameInfo *MFI, bool IsRegLoc, - SmallVectorImpl &InVals, MipsFunctionInfo *MipsFI, - EVT PtrTy, const Argument *FuncArg) { - const uint16_t *Reg = Mips64IntRegs + 8; - int FOOffset; // Frame object offset from virtual frame pointer. - - if (IsRegLoc) { - Reg = std::find(Mips64IntRegs, Mips64IntRegs + 8, VA.getLocReg()); - FOOffset = (Reg - Mips64IntRegs) * 8 - 8 * 8; - } - else - FOOffset = VA.getLocMemOffset(); - - // Create frame object. - unsigned NumRegs = (Flags.getByValSize() + 7) / 8; - unsigned LastFI = MFI->CreateFixedObject(NumRegs * 8, FOOffset, true); - SDValue FIN = DAG.getFrameIndex(LastFI, PtrTy); - InVals.push_back(FIN); - - // Copy arg registers. - for (unsigned I = 0; (Reg != Mips64IntRegs + 8) && (I < NumRegs); - ++Reg, ++I) { - unsigned VReg = AddLiveIn(MF, *Reg, &Mips::CPU64RegsRegClass); - SDValue StorePtr = DAG.getNode(ISD::ADD, dl, PtrTy, FIN, - DAG.getConstant(I * 8, PtrTy)); - SDValue Store = DAG.getStore(Chain, dl, DAG.getRegister(VReg, MVT::i64), - StorePtr, MachinePointerInfo(FuncArg, I * 8), - false, false, 0); - OutChains.push_back(Store); - } - - return LastFI; -} - /// LowerFormalArguments - transform physical registers into virtual registers /// and generate load operations for arguments places on the stack. SDValue @@ -3018,20 +3294,21 @@ MipsTargetLowering::LowerFormalArguments(SDValue Chain, SmallVector ArgLocs; CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), getTargetMachine(), ArgLocs, *DAG.getContext()); + MipsCC MipsCCInfo(CallConv, isVarArg, IsO32, CCInfo); - if (CallConv == CallingConv::Fast) - CCInfo.AnalyzeFormalArguments(Ins, CC_Mips_FastCC); - else if (IsO32) - CCInfo.AnalyzeFormalArguments(Ins, CC_MipsO32); - else - CCInfo.AnalyzeFormalArguments(Ins, CC_Mips); + MipsCCInfo.analyzeFormalArguments(Ins); + MipsFI->setFormalArgInfo(CCInfo.getNextStackOffset(), + MipsCCInfo.hasByValArg()); Function::const_arg_iterator FuncArg = DAG.getMachineFunction().getFunction()->arg_begin(); - int LastFI = 0;// MipsFI->LastInArgFI is 0 at the entry of this function. + unsigned CurArgIdx = 0; + MipsCC::byval_iterator ByValArg = MipsCCInfo.byval_begin(); - for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i, ++FuncArg) { + for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { CCValAssign &VA = ArgLocs[i]; + std::advance(FuncArg, Ins[i].OrigArgIndex - CurArgIdx); + CurArgIdx = Ins[i].OrigArgIndex; EVT ValVT = VA.getValVT(); ISD::ArgFlagsTy Flags = Ins[i].Flags; bool IsRegLoc = VA.isRegLoc(); @@ -3039,18 +3316,10 @@ MipsTargetLowering::LowerFormalArguments(SDValue Chain, if (Flags.isByVal()) { assert(Flags.getByValSize() && "ByVal args of size 0 should have been ignored by front-end."); - if (IsO32) { - unsigned NumWords = (Flags.getByValSize() + 3) / 4; - LastFI = MFI->CreateFixedObject(NumWords * 4, VA.getLocMemOffset(), - true); - SDValue FIN = DAG.getFrameIndex(LastFI, getPointerTy()); - InVals.push_back(FIN); - ReadByValArg(MF, Chain, dl, OutChains, DAG, NumWords, FIN, VA, Flags, - &*FuncArg); - } else // N32/64 - LastFI = CopyMips64ByValRegs(MF, Chain, dl, OutChains, DAG, VA, Flags, - MFI, IsRegLoc, InVals, MipsFI, - getPointerTy(), &*FuncArg); + assert(ByValArg != MipsCCInfo.byval_end()); + copyByValRegs(Chain, dl, OutChains, DAG, Flags, InVals, &*FuncArg, + MipsCCInfo, *ByValArg); + ++ByValArg; continue; } @@ -3061,7 +3330,8 @@ MipsTargetLowering::LowerFormalArguments(SDValue Chain, const TargetRegisterClass *RC; if (RegVT == MVT::i32) - RC = &Mips::CPURegsRegClass; + RC = Subtarget->inMips16Mode()? &Mips::CPU16RegsRegClass : + &Mips::CPURegsRegClass; else if (RegVT == MVT::i64) RC = &Mips::CPU64RegsRegClass; else if (RegVT == MVT::f32) @@ -3112,13 +3382,13 @@ MipsTargetLowering::LowerFormalArguments(SDValue Chain, assert(VA.isMemLoc()); // The stack pointer offset is relative to the caller stack frame. - LastFI = MFI->CreateFixedObject(ValVT.getSizeInBits()/8, + int FI = MFI->CreateFixedObject(ValVT.getSizeInBits()/8, VA.getLocMemOffset(), true); // Create load nodes to retrieve arguments from the stack - SDValue FIN = DAG.getFrameIndex(LastFI, getPointerTy()); + SDValue FIN = DAG.getFrameIndex(FI, getPointerTy()); InVals.push_back(DAG.getLoad(ValVT, dl, Chain, FIN, - MachinePointerInfo::getFixedStack(LastFI), + MachinePointerInfo::getFixedStack(FI), false, false, false, 0)); } } @@ -3129,55 +3399,16 @@ MipsTargetLowering::LowerFormalArguments(SDValue Chain, if (DAG.getMachineFunction().getFunction()->hasStructRetAttr()) { unsigned Reg = MipsFI->getSRetReturnReg(); if (!Reg) { - Reg = MF.getRegInfo().createVirtualRegister(getRegClassFor(MVT::i32)); + Reg = MF.getRegInfo(). + createVirtualRegister(getRegClassFor(IsN64 ? MVT::i64 : MVT::i32)); MipsFI->setSRetReturnReg(Reg); } SDValue Copy = DAG.getCopyToReg(DAG.getEntryNode(), dl, Reg, InVals[0]); Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Copy, Chain); } - if (isVarArg) { - unsigned NumOfRegs = IsO32 ? 4 : 8; - const uint16_t *ArgRegs = IsO32 ? O32IntRegs : Mips64IntRegs; - unsigned Idx = CCInfo.getFirstUnallocated(ArgRegs, NumOfRegs); - int FirstRegSlotOffset = IsO32 ? 0 : -64 ; // offset of $a0's slot. - const TargetRegisterClass *RC = IsO32 ? - (const TargetRegisterClass*)&Mips::CPURegsRegClass : - (const TargetRegisterClass*)&Mips::CPU64RegsRegClass; - unsigned RegSize = RC->getSize(); - int RegSlotOffset = FirstRegSlotOffset + Idx * RegSize; - - // Offset of the first variable argument from stack pointer. - int FirstVaArgOffset; - - if (IsO32 || (Idx == NumOfRegs)) { - FirstVaArgOffset = - (CCInfo.getNextStackOffset() + RegSize - 1) / RegSize * RegSize; - } else - FirstVaArgOffset = RegSlotOffset; - - // Record the frame index of the first variable argument - // which is a value necessary to VASTART. - LastFI = MFI->CreateFixedObject(RegSize, FirstVaArgOffset, true); - MipsFI->setVarArgsFrameIndex(LastFI); - - // Copy the integer registers that have not been used for argument passing - // to the argument register save area. For O32, the save area is allocated - // in the caller's stack frame, while for N32/64, it is allocated in the - // callee's stack frame. - for (int StackOffset = RegSlotOffset; - Idx < NumOfRegs; ++Idx, StackOffset += RegSize) { - unsigned Reg = AddLiveIn(DAG.getMachineFunction(), ArgRegs[Idx], RC); - SDValue ArgValue = DAG.getCopyFromReg(Chain, dl, Reg, - MVT::getIntegerVT(RegSize * 8)); - LastFI = MFI->CreateFixedObject(RegSize, StackOffset, true); - SDValue PtrOff = DAG.getFrameIndex(LastFI, getPointerTy()); - OutChains.push_back(DAG.getStore(Chain, dl, ArgValue, PtrOff, - MachinePointerInfo(), false, false, 0)); - } - } - - MipsFI->setLastInArgFI(LastFI); + if (isVarArg) + writeVarArgRegs(OutChains, MipsCCInfo, Chain, dl, DAG); // All stores are grouped in one node to allow the matching between // the size of Ins and InVals. This only happens when on varg functions @@ -3194,6 +3425,17 @@ MipsTargetLowering::LowerFormalArguments(SDValue Chain, // Return Value Calling Convention Implementation //===----------------------------------------------------------------------===// +bool +MipsTargetLowering::CanLowerReturn(CallingConv::ID CallConv, + MachineFunction &MF, bool isVarArg, + const SmallVectorImpl &Outs, + LLVMContext &Context) const { + SmallVector RVLocs; + CCState CCInfo(CallConv, isVarArg, MF, getTargetMachine(), + RVLocs, Context); + return CCInfo.CheckReturn(Outs, RetCC_Mips); +} + SDValue MipsTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv, bool isVarArg, @@ -3212,15 +3454,8 @@ MipsTargetLowering::LowerReturn(SDValue Chain, // Analize return values. CCInfo.AnalyzeReturn(Outs, RetCC_Mips); - // If this is the first return lowered for this function, add - // the regs to the liveout set for the function. - if (DAG.getMachineFunction().getRegInfo().liveout_empty()) { - for (unsigned i = 0; i != RVLocs.size(); ++i) - if (RVLocs[i].isRegLoc()) - DAG.getMachineFunction().getRegInfo().addLiveOut(RVLocs[i].getLocReg()); - } - SDValue Flag; + SmallVector RetOps(1, Chain); // Copy the result values into the output registers. for (unsigned i = 0; i != RVLocs.size(); ++i) { @@ -3229,9 +3464,9 @@ MipsTargetLowering::LowerReturn(SDValue Chain, Chain = DAG.getCopyToReg(Chain, dl, VA.getLocReg(), OutVals[i], Flag); - // guarantee that all emitted copies are - // stuck together, avoiding something bad + // Guarantee that all emitted copies are stuck together with flags. Flag = Chain.getValue(1); + RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT())); } // The mips ABIs for returning structs by value requires that we copy @@ -3246,18 +3481,21 @@ MipsTargetLowering::LowerReturn(SDValue Chain, if (!Reg) llvm_unreachable("sret virtual register not created in the entry block"); SDValue Val = DAG.getCopyFromReg(Chain, dl, Reg, getPointerTy()); + unsigned V0 = IsN64 ? Mips::V0_64 : Mips::V0; - Chain = DAG.getCopyToReg(Chain, dl, Mips::V0, Val, Flag); + Chain = DAG.getCopyToReg(Chain, dl, V0, Val, Flag); Flag = Chain.getValue(1); + RetOps.push_back(DAG.getRegister(V0, getPointerTy())); } - // Return on Mips is always a "jr $ra" + RetOps[0] = Chain; // Update chain. + + // Add the flag if we have it. if (Flag.getNode()) - return DAG.getNode(MipsISD::Ret, dl, MVT::Other, - Chain, DAG.getRegister(Mips::RA, MVT::i32), Flag); - else // Return Void - return DAG.getNode(MipsISD::Ret, dl, MVT::Other, - Chain, DAG.getRegister(Mips::RA, MVT::i32)); + RetOps.push_back(Flag); + + // Return on Mips is always a "jr $ra" + return DAG.getNode(MipsISD::Ret, dl, MVT::Other, &RetOps[0], RetOps.size()); } //===----------------------------------------------------------------------===// @@ -3353,7 +3591,12 @@ getRegForInlineAsmConstraint(const std::string &Constraint, EVT VT) const case 'd': // Address register. Same as 'r' unless generating MIPS16 code. case 'y': // Same as 'r'. Exists for compatibility. case 'r': - if (VT == MVT::i32 || VT == MVT::i16 || VT == MVT::i8) + if (VT == MVT::i32 || VT == MVT::i16 || VT == MVT::i8) { + if (Subtarget->inMips16Mode()) + return std::make_pair(0U, &Mips::CPU16RegsRegClass); + return std::make_pair(0U, &Mips::CPURegsRegClass); + } + if (VT == MVT::i64 && !HasMips64) return std::make_pair(0U, &Mips::CPURegsRegClass); if (VT == MVT::i64 && HasMips64) return std::make_pair(0U, &Mips::CPU64RegsRegClass); @@ -3481,6 +3724,26 @@ void MipsTargetLowering::LowerAsmOperandForConstraint(SDValue Op, TargetLowering::LowerAsmOperandForConstraint(Op, Constraint, Ops, DAG); } +bool +MipsTargetLowering::isLegalAddressingMode(const AddrMode &AM, Type *Ty) const { + // No global is ever allowed as a base. + if (AM.BaseGV) + return false; + + switch (AM.Scale) { + case 0: // "r+i" or just "i", depending on HasBaseReg. + break; + case 1: + if (!AM.HasBaseReg) // allow "r+i". + break; + return false; // disallow "r+r" or "r+r+i". + default: + return false; + } + + return true; +} + bool MipsTargetLowering::isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const { // The Mips target isn't yet aware of offsets. @@ -3488,7 +3751,8 @@ MipsTargetLowering::isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const { } EVT MipsTargetLowering::getOptimalMemOpType(uint64_t Size, unsigned DstAlign, - unsigned SrcAlign, bool IsZeroVal, + unsigned SrcAlign, + bool IsMemset, bool ZeroMemset, bool MemcpyStrSrc, MachineFunction &MF) const { if (Subtarget->hasMips64()) @@ -3511,3 +3775,316 @@ unsigned MipsTargetLowering::getJumpTableEncoding() const { return TargetLowering::getJumpTableEncoding(); } + +MipsTargetLowering::MipsCC::MipsCC(CallingConv::ID CallConv, bool IsVarArg, + bool IsO32, CCState &Info) : CCInfo(Info) { + UseRegsForByval = true; + + if (IsO32) { + RegSize = 4; + NumIntArgRegs = array_lengthof(O32IntRegs); + ReservedArgArea = 16; + IntArgRegs = ShadowRegs = O32IntRegs; + FixedFn = VarFn = CC_MipsO32; + } else { + RegSize = 8; + NumIntArgRegs = array_lengthof(Mips64IntRegs); + ReservedArgArea = 0; + IntArgRegs = Mips64IntRegs; + ShadowRegs = Mips64DPRegs; + FixedFn = CC_MipsN; + VarFn = IsVarArg ? CC_MipsN_VarArg : CC_MipsN; + } + + if (CallConv == CallingConv::Fast) { + assert(!IsVarArg); + UseRegsForByval = false; + ReservedArgArea = 0; + FixedFn = VarFn = CC_Mips_FastCC; + } + + // Pre-allocate reserved argument area. + CCInfo.AllocateStack(ReservedArgArea, 1); +} + +void MipsTargetLowering::MipsCC:: +analyzeCallOperands(const SmallVectorImpl &Args) { + unsigned NumOpnds = Args.size(); + + for (unsigned I = 0; I != NumOpnds; ++I) { + MVT ArgVT = Args[I].VT; + ISD::ArgFlagsTy ArgFlags = Args[I].Flags; + bool R; + + if (ArgFlags.isByVal()) { + handleByValArg(I, ArgVT, ArgVT, CCValAssign::Full, ArgFlags); + continue; + } + + if (Args[I].IsFixed) + R = FixedFn(I, ArgVT, ArgVT, CCValAssign::Full, ArgFlags, CCInfo); + else + R = VarFn(I, ArgVT, ArgVT, CCValAssign::Full, ArgFlags, CCInfo); + + if (R) { +#ifndef NDEBUG + dbgs() << "Call operand #" << I << " has unhandled type " + << EVT(ArgVT).getEVTString(); +#endif + llvm_unreachable(0); + } + } +} + +void MipsTargetLowering::MipsCC:: +analyzeFormalArguments(const SmallVectorImpl &Args) { + unsigned NumArgs = Args.size(); + + for (unsigned I = 0; I != NumArgs; ++I) { + MVT ArgVT = Args[I].VT; + ISD::ArgFlagsTy ArgFlags = Args[I].Flags; + + if (ArgFlags.isByVal()) { + handleByValArg(I, ArgVT, ArgVT, CCValAssign::Full, ArgFlags); + continue; + } + + if (!FixedFn(I, ArgVT, ArgVT, CCValAssign::Full, ArgFlags, CCInfo)) + continue; + +#ifndef NDEBUG + dbgs() << "Formal Arg #" << I << " has unhandled type " + << EVT(ArgVT).getEVTString(); +#endif + llvm_unreachable(0); + } +} + +void +MipsTargetLowering::MipsCC::handleByValArg(unsigned ValNo, MVT ValVT, + MVT LocVT, + CCValAssign::LocInfo LocInfo, + ISD::ArgFlagsTy ArgFlags) { + assert(ArgFlags.getByValSize() && "Byval argument's size shouldn't be 0."); + + struct ByValArgInfo ByVal; + unsigned ByValSize = RoundUpToAlignment(ArgFlags.getByValSize(), RegSize); + unsigned Align = std::min(std::max(ArgFlags.getByValAlign(), RegSize), + RegSize * 2); + + if (UseRegsForByval) + allocateRegs(ByVal, ByValSize, Align); + + // Allocate space on caller's stack. + ByVal.Address = CCInfo.AllocateStack(ByValSize - RegSize * ByVal.NumRegs, + Align); + CCInfo.addLoc(CCValAssign::getMem(ValNo, ValVT, ByVal.Address, LocVT, + LocInfo)); + ByValArgs.push_back(ByVal); +} + +void MipsTargetLowering::MipsCC::allocateRegs(ByValArgInfo &ByVal, + unsigned ByValSize, + unsigned Align) { + assert(!(ByValSize % RegSize) && !(Align % RegSize) && + "Byval argument's size and alignment should be a multiple of" + "RegSize."); + + ByVal.FirstIdx = CCInfo.getFirstUnallocated(IntArgRegs, NumIntArgRegs); + + // If Align > RegSize, the first arg register must be even. + if ((Align > RegSize) && (ByVal.FirstIdx % 2)) { + CCInfo.AllocateReg(IntArgRegs[ByVal.FirstIdx], ShadowRegs[ByVal.FirstIdx]); + ++ByVal.FirstIdx; + } + + // Mark the registers allocated. + for (unsigned I = ByVal.FirstIdx; ByValSize && (I < NumIntArgRegs); + ByValSize -= RegSize, ++I, ++ByVal.NumRegs) + CCInfo.AllocateReg(IntArgRegs[I], ShadowRegs[I]); +} + +void MipsTargetLowering:: +copyByValRegs(SDValue Chain, DebugLoc DL, std::vector &OutChains, + SelectionDAG &DAG, const ISD::ArgFlagsTy &Flags, + SmallVectorImpl &InVals, const Argument *FuncArg, + const MipsCC &CC, const ByValArgInfo &ByVal) const { + MachineFunction &MF = DAG.getMachineFunction(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + unsigned RegAreaSize = ByVal.NumRegs * CC.regSize(); + unsigned FrameObjSize = std::max(Flags.getByValSize(), RegAreaSize); + int FrameObjOffset; + + if (RegAreaSize) + FrameObjOffset = (int)CC.reservedArgArea() - + (int)((CC.numIntArgRegs() - ByVal.FirstIdx) * CC.regSize()); + else + FrameObjOffset = ByVal.Address; + + // Create frame object. + EVT PtrTy = getPointerTy(); + int FI = MFI->CreateFixedObject(FrameObjSize, FrameObjOffset, true); + SDValue FIN = DAG.getFrameIndex(FI, PtrTy); + InVals.push_back(FIN); + + if (!ByVal.NumRegs) + return; + + // Copy arg registers. + MVT RegTy = MVT::getIntegerVT(CC.regSize() * 8); + const TargetRegisterClass *RC = getRegClassFor(RegTy); + + for (unsigned I = 0; I < ByVal.NumRegs; ++I) { + unsigned ArgReg = CC.intArgRegs()[ByVal.FirstIdx + I]; + unsigned VReg = AddLiveIn(MF, ArgReg, RC); + unsigned Offset = I * CC.regSize(); + SDValue StorePtr = DAG.getNode(ISD::ADD, DL, PtrTy, FIN, + DAG.getConstant(Offset, PtrTy)); + SDValue Store = DAG.getStore(Chain, DL, DAG.getRegister(VReg, RegTy), + StorePtr, MachinePointerInfo(FuncArg, Offset), + false, false, 0); + OutChains.push_back(Store); + } +} + +// Copy byVal arg to registers and stack. +void MipsTargetLowering:: +passByValArg(SDValue Chain, DebugLoc DL, + std::deque< std::pair > &RegsToPass, + SmallVector &MemOpChains, SDValue StackPtr, + MachineFrameInfo *MFI, SelectionDAG &DAG, SDValue Arg, + const MipsCC &CC, const ByValArgInfo &ByVal, + const ISD::ArgFlagsTy &Flags, bool isLittle) const { + unsigned ByValSize = Flags.getByValSize(); + unsigned Offset = 0; // Offset in # of bytes from the beginning of struct. + unsigned RegSize = CC.regSize(); + unsigned Alignment = std::min(Flags.getByValAlign(), RegSize); + EVT PtrTy = getPointerTy(), RegTy = MVT::getIntegerVT(RegSize * 8); + + if (ByVal.NumRegs) { + const uint16_t *ArgRegs = CC.intArgRegs(); + bool LeftoverBytes = (ByVal.NumRegs * RegSize > ByValSize); + unsigned I = 0; + + // Copy words to registers. + for (; I < ByVal.NumRegs - LeftoverBytes; ++I, Offset += RegSize) { + SDValue LoadPtr = DAG.getNode(ISD::ADD, DL, PtrTy, Arg, + DAG.getConstant(Offset, PtrTy)); + SDValue LoadVal = DAG.getLoad(RegTy, DL, Chain, LoadPtr, + MachinePointerInfo(), false, false, false, + Alignment); + MemOpChains.push_back(LoadVal.getValue(1)); + unsigned ArgReg = ArgRegs[ByVal.FirstIdx + I]; + RegsToPass.push_back(std::make_pair(ArgReg, LoadVal)); + } + + // Return if the struct has been fully copied. + if (ByValSize == Offset) + return; + + // Copy the remainder of the byval argument with sub-word loads and shifts. + if (LeftoverBytes) { + assert((ByValSize > Offset) && (ByValSize < Offset + RegSize) && + "Size of the remainder should be smaller than RegSize."); + SDValue Val; + + for (unsigned LoadSize = RegSize / 2, TotalSizeLoaded = 0; + Offset < ByValSize; LoadSize /= 2) { + unsigned RemSize = ByValSize - Offset; + + if (RemSize < LoadSize) + continue; + + // Load subword. + SDValue LoadPtr = DAG.getNode(ISD::ADD, DL, PtrTy, Arg, + DAG.getConstant(Offset, PtrTy)); + SDValue LoadVal = + DAG.getExtLoad(ISD::ZEXTLOAD, DL, RegTy, Chain, LoadPtr, + MachinePointerInfo(), MVT::getIntegerVT(LoadSize * 8), + false, false, Alignment); + MemOpChains.push_back(LoadVal.getValue(1)); + + // Shift the loaded value. + unsigned Shamt; + + if (isLittle) + Shamt = TotalSizeLoaded; + else + Shamt = (RegSize - (TotalSizeLoaded + LoadSize)) * 8; + + SDValue Shift = DAG.getNode(ISD::SHL, DL, RegTy, LoadVal, + DAG.getConstant(Shamt, MVT::i32)); + + if (Val.getNode()) + Val = DAG.getNode(ISD::OR, DL, RegTy, Val, Shift); + else + Val = Shift; + + Offset += LoadSize; + TotalSizeLoaded += LoadSize; + Alignment = std::min(Alignment, LoadSize); + } + + unsigned ArgReg = ArgRegs[ByVal.FirstIdx + I]; + RegsToPass.push_back(std::make_pair(ArgReg, Val)); + return; + } + } + + // Copy remainder of byval arg to it with memcpy. + unsigned MemCpySize = ByValSize - Offset; + SDValue Src = DAG.getNode(ISD::ADD, DL, PtrTy, Arg, + DAG.getConstant(Offset, PtrTy)); + SDValue Dst = DAG.getNode(ISD::ADD, DL, PtrTy, StackPtr, + DAG.getIntPtrConstant(ByVal.Address)); + Chain = DAG.getMemcpy(Chain, DL, Dst, Src, + DAG.getConstant(MemCpySize, PtrTy), Alignment, + /*isVolatile=*/false, /*AlwaysInline=*/false, + MachinePointerInfo(0), MachinePointerInfo(0)); + MemOpChains.push_back(Chain); +} + +void +MipsTargetLowering::writeVarArgRegs(std::vector &OutChains, + const MipsCC &CC, SDValue Chain, + DebugLoc DL, SelectionDAG &DAG) const { + unsigned NumRegs = CC.numIntArgRegs(); + const uint16_t *ArgRegs = CC.intArgRegs(); + const CCState &CCInfo = CC.getCCInfo(); + unsigned Idx = CCInfo.getFirstUnallocated(ArgRegs, NumRegs); + unsigned RegSize = CC.regSize(); + MVT RegTy = MVT::getIntegerVT(RegSize * 8); + const TargetRegisterClass *RC = getRegClassFor(RegTy); + MachineFunction &MF = DAG.getMachineFunction(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + MipsFunctionInfo *MipsFI = MF.getInfo(); + + // Offset of the first variable argument from stack pointer. + int VaArgOffset; + + if (NumRegs == Idx) + VaArgOffset = RoundUpToAlignment(CCInfo.getNextStackOffset(), RegSize); + else + VaArgOffset = + (int)CC.reservedArgArea() - (int)(RegSize * (NumRegs - Idx)); + + // Record the frame index of the first variable argument + // which is a value necessary to VASTART. + int FI = MFI->CreateFixedObject(RegSize, VaArgOffset, true); + MipsFI->setVarArgsFrameIndex(FI); + + // Copy the integer registers that have not been used for argument passing + // to the argument register save area. For O32, the save area is allocated + // in the caller's stack frame, while for N32/64, it is allocated in the + // callee's stack frame. + for (unsigned I = Idx; I < NumRegs; ++I, VaArgOffset += RegSize) { + unsigned Reg = AddLiveIn(MF, ArgRegs[I], RC); + SDValue ArgValue = DAG.getCopyFromReg(Chain, DL, Reg, RegTy); + FI = MFI->CreateFixedObject(RegSize, VaArgOffset, true); + SDValue PtrOff = DAG.getFrameIndex(FI, getPointerTy()); + SDValue Store = DAG.getStore(Chain, DL, ArgValue, PtrOff, + MachinePointerInfo(), false, false, 0); + cast(Store.getNode())->getMemOperand()->setValue(0); + OutChains.push_back(Store); + } +}