diff options
author | Chris Lattner <sabre@nondot.org> | 2006-05-17 19:00:46 +0000 |
---|---|---|
committer | Chris Lattner <sabre@nondot.org> | 2006-05-17 19:00:46 +0000 |
commit | c703a8fbf8653ac8302ae368391a4954c307ca2c (patch) | |
tree | a8d8fea3c090dc7a4c3da0965a0e5576e61fc516 /lib/Target/PowerPC/PPCISelLowering.cpp | |
parent | 7e399c14abb27f9d1291442ee7f9251fa827f2e9 (diff) |
Make PPC call lowering more aggressive, making the isel matching code simple
enough to be autogenerated.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@28354 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Target/PowerPC/PPCISelLowering.cpp')
-rw-r--r-- | lib/Target/PowerPC/PPCISelLowering.cpp | 83 |
1 files changed, 71 insertions, 12 deletions
diff --git a/lib/Target/PowerPC/PPCISelLowering.cpp b/lib/Target/PowerPC/PPCISelLowering.cpp index 7a24b31c6b..87e2999eb6 100644 --- a/lib/Target/PowerPC/PPCISelLowering.cpp +++ b/lib/Target/PowerPC/PPCISelLowering.cpp @@ -276,6 +276,8 @@ const char *PPCTargetLowering::getTargetNodeName(unsigned Opcode) const { case PPCISD::EXTSW_32: return "PPCISD::EXTSW_32"; case PPCISD::STD_32: return "PPCISD::STD_32"; case PPCISD::CALL: return "PPCISD::CALL"; + case PPCISD::MTCTR: return "PPCISD::MTCTR"; + case PPCISD::BCTRL: return "PPCISD::BCTRL"; case PPCISD::RET_FLAG: return "PPCISD::RET_FLAG"; case PPCISD::MFCR: return "PPCISD::MFCR"; case PPCISD::VCMP: return "PPCISD::VCMP"; @@ -877,6 +879,21 @@ static SDOperand LowerFORMAL_ARGUMENTS(SDOperand Op, SelectionDAG &DAG, return DAG.getNode(ISD::MERGE_VALUES, RetVT, ArgValues); } +/// isCallCompatibleAddress - Return the immediate to use if the specified +/// 32-bit value is representable in the immediate field of a BxA instruction. +static SDNode *isBLACompatibleAddress(SDOperand Op, SelectionDAG &DAG) { + ConstantSDNode *C = dyn_cast<ConstantSDNode>(Op); + if (!C) return 0; + + int Addr = C->getValue(); + if ((Addr & 3) != 0 || // Low 2 bits are implicitly zero. + (Addr << 6 >> 6) != Addr) + return 0; // Top 6 bits have to be sext of immediate. + + return DAG.getConstant((int)C->getValue() >> 2, MVT::i32).Val; +} + + static SDOperand LowerCALL(SDOperand Op, SelectionDAG &DAG) { SDOperand Chain = Op.getOperand(0); unsigned CallingConv= cast<ConstantSDNode>(Op.getOperand(1))->getValue(); @@ -1026,22 +1043,59 @@ static SDOperand LowerCALL(SDOperand Op, SelectionDAG &DAG) { InFlag = Chain.getValue(1); } - // If the callee is a GlobalAddress node (quite common, every direct call is) - // turn it into a TargetGlobalAddress node so that legalize doesn't hack it. + std::vector<MVT::ValueType> NodeTys; + + // 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. if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) Callee = DAG.getTargetGlobalAddress(G->getGlobal(), Callee.getValueType()); + else if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(Callee)) + Callee = DAG.getTargetExternalSymbol(S->getSymbol(), Callee.getValueType()); + else if (SDNode *Dest = isBLACompatibleAddress(Callee, DAG)) + // If this is an absolute destination address, use the munged value. + Callee = SDOperand(Dest, 0); + else { + // Otherwise, this is an indirect call. We have to use a MTCTR/BCTRL pair + // to do the call, we can't use PPCISD::CALL. + std::vector<SDOperand> Ops; + Ops.push_back(Chain); + Ops.push_back(Callee); + NodeTys.push_back(MVT::Other); + NodeTys.push_back(MVT::Flag); + + if (InFlag.Val) + Ops.push_back(InFlag); + Chain = DAG.getNode(PPCISD::MTCTR, NodeTys, Ops); + InFlag = Chain.getValue(1); + + // Copy the callee address into R12 on darwin. + Chain = DAG.getCopyToReg(Chain, PPC::R12, Callee, InFlag); + InFlag = Chain.getValue(1); - // Create the PPCISD::CALL node itself. - std::vector<MVT::ValueType> NodeTys; - NodeTys.push_back(MVT::Other); // Returns a chain - NodeTys.push_back(MVT::Flag); // Returns a flag for retval copy to use. - std::vector<SDOperand> Ops; - Ops.push_back(Chain); - Ops.push_back(Callee); - if (InFlag.Val) + NodeTys.clear(); + NodeTys.push_back(MVT::Other); + NodeTys.push_back(MVT::Flag); + Ops.clear(); + Ops.push_back(Chain); Ops.push_back(InFlag); - Chain = DAG.getNode(PPCISD::CALL, NodeTys, Ops); - InFlag = Chain.getValue(1); + Chain = DAG.getNode(PPCISD::BCTRL, NodeTys, Ops); + InFlag = Chain.getValue(1); + Callee.Val = 0; + } + + // Create the PPCISD::CALL node itself. + if (Callee.Val) { + NodeTys.push_back(MVT::Other); // Returns a chain + NodeTys.push_back(MVT::Flag); // Returns a flag for retval copy to use. + std::vector<SDOperand> Ops; + Ops.push_back(Chain); + Ops.push_back(Callee); + if (InFlag.Val) + Ops.push_back(InFlag); + Chain = DAG.getNode(PPCISD::CALL, NodeTys, Ops); + InFlag = Chain.getValue(1); + } std::vector<SDOperand> ResultVals; NodeTys.clear(); @@ -1086,6 +1140,11 @@ static SDOperand LowerCALL(SDOperand Op, SelectionDAG &DAG) { DAG.getConstant(NumBytes, MVT::i32)); NodeTys.push_back(MVT::Other); + // If the function returns void, just return the chain. + if (ResultVals.empty()) + return Chain; + + // Otherwise, merge everything together with a MERGE_VALUES node. ResultVals.push_back(Chain); SDOperand Res = DAG.getNode(ISD::MERGE_VALUES, NodeTys, ResultVals); return Res.getValue(Op.ResNo); |