diff options
| author | Evan Cheng <evan.cheng@apple.com> | 2008-04-19 01:30:48 +0000 |
|---|---|---|
| committer | Evan Cheng <evan.cheng@apple.com> | 2008-04-19 01:30:48 +0000 |
| commit | 51096affb5cc91953a9244ef01973fa2bdacc723 (patch) | |
| tree | 9d0d165f0edf8e0b04a7679218341bcb939f51f4 /llvm/lib/Target/PowerPC/PPCISelLowering.cpp | |
| parent | 7f4240a47caa0236234777bd68c59617bd208e2e (diff) | |
| download | bcm5719-llvm-51096affb5cc91953a9244ef01973fa2bdacc723.tar.gz bcm5719-llvm-51096affb5cc91953a9244ef01973fa2bdacc723.zip | |
PPC32 atomic operations.
llvm-svn: 49947
Diffstat (limited to 'llvm/lib/Target/PowerPC/PPCISelLowering.cpp')
| -rw-r--r-- | llvm/lib/Target/PowerPC/PPCISelLowering.cpp | 125 |
1 files changed, 124 insertions, 1 deletions
diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp index 83bea7e11c2..1d3bf224cda 100644 --- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp +++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp @@ -39,7 +39,8 @@ cl::desc("enable preincrement load/store generation on PPC (experimental)"), cl::Hidden); PPCTargetLowering::PPCTargetLowering(PPCTargetMachine &TM) - : TargetLowering(TM), PPCSubTarget(*TM.getSubtargetImpl()) { + : TargetLowering(TM), PPCSubTarget(*TM.getSubtargetImpl()), + PPCAtomicLabelIndex(0) { setPow2DivIsCheap(); @@ -202,6 +203,10 @@ PPCTargetLowering::PPCTargetLowering(PPCTargetMachine &TM) setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i32 , Custom); setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i64 , Custom); + setOperationAction(ISD::ATOMIC_LAS , MVT::i32 , Custom); + setOperationAction(ISD::ATOMIC_LCS , MVT::i32 , Custom); + setOperationAction(ISD::ATOMIC_SWAP , MVT::i32 , Custom); + // We want to custom lower some of our intrinsics. setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::Other, Custom); @@ -393,6 +398,9 @@ const char *PPCTargetLowering::getTargetNodeName(unsigned Opcode) const { case PPCISD::VCMPo: return "PPCISD::VCMPo"; case PPCISD::LBRX: return "PPCISD::LBRX"; case PPCISD::STBRX: return "PPCISD::STBRX"; + case PPCISD::LWARX: return "PPCISD::LWARX"; + case PPCISD::STWCX: return "PPCISD::STWCX"; + case PPCISD::CMP_UNRESERVE: return "PPCISD::CMP_UNRESERVE"; case PPCISD::COND_BRANCH: return "PPCISD::COND_BRANCH"; case PPCISD::MFFS: return "PPCISD::MFFS"; case PPCISD::MTFSB0: return "PPCISD::MTFSB0"; @@ -2295,6 +2303,117 @@ SDOperand PPCTargetLowering::LowerDYNAMIC_STACKALLOC(SDOperand Op, return DAG.getNode(PPCISD::DYNALLOC, VTs, Ops, 3); } +SDOperand PPCTargetLowering::LowerAtomicLAS(SDOperand Op, SelectionDAG &DAG) { + MVT::ValueType VT = Op.getValueType(); + SDOperand Chain = Op.getOperand(0); + SDOperand Ptr = Op.getOperand(1); + SDOperand Incr = Op.getOperand(2); + + // Issue a "load and reserve". + std::vector<MVT::ValueType> VTs; + VTs.push_back(VT); + VTs.push_back(MVT::Other); + + SDOperand Label = DAG.getConstant(PPCAtomicLabelIndex++, MVT::i32); + SDOperand Ops[] = { + Chain, // Chain + Ptr, // Ptr + Label, // Label + }; + SDOperand Load = DAG.getNode(PPCISD::LWARX, VTs, Ops, 3); + Chain = Load.getValue(1); + + // Compute new value. + SDOperand NewVal = DAG.getNode(ISD::ADD, VT, Load, Incr); + + // Issue a "store and check". + SDOperand Ops2[] = { + Chain, // Chain + NewVal, // Value + Ptr, // Ptr + Label, // Label + }; + SDOperand Store = DAG.getNode(PPCISD::STWCX, MVT::Other, Ops2, 4); + SDOperand OutOps[] = { Load, Store }; + return DAG.getNode(ISD::MERGE_VALUES, DAG.getVTList(VT, MVT::Other), + OutOps, 2); +} + +SDOperand PPCTargetLowering::LowerAtomicLCS(SDOperand Op, SelectionDAG &DAG) { + MVT::ValueType VT = Op.getValueType(); + SDOperand Chain = Op.getOperand(0); + SDOperand Ptr = Op.getOperand(1); + SDOperand NewVal = Op.getOperand(2); + SDOperand OldVal = Op.getOperand(3); + + // Issue a "load and reserve". + std::vector<MVT::ValueType> VTs; + VTs.push_back(VT); + VTs.push_back(MVT::Other); + + SDOperand Label = DAG.getConstant(PPCAtomicLabelIndex++, MVT::i32); + SDOperand Ops[] = { + Chain, // Chain + Ptr, // Ptr + Label, // Label + }; + SDOperand Load = DAG.getNode(PPCISD::LWARX, VTs, Ops, 3); + Chain = Load.getValue(1); + + // Compare and unreserve if not equal. + SDOperand Ops2[] = { + Chain, // Chain + OldVal, // Old value + Load, // Value in memory + Label, // Label + }; + Chain = DAG.getNode(PPCISD::CMP_UNRESERVE, MVT::Other, Ops2, 4); + + // Issue a "store and check". + SDOperand Ops3[] = { + Chain, // Chain + NewVal, // Value + Ptr, // Ptr + Label, // Label + }; + SDOperand Store = DAG.getNode(PPCISD::STWCX, MVT::Other, Ops3, 4); + SDOperand OutOps[] = { Load, Store }; + return DAG.getNode(ISD::MERGE_VALUES, DAG.getVTList(VT, MVT::Other), + OutOps, 2); +} + +SDOperand PPCTargetLowering::LowerAtomicSWAP(SDOperand Op, SelectionDAG &DAG) { + MVT::ValueType VT = Op.getValueType(); + SDOperand Chain = Op.getOperand(0); + SDOperand Ptr = Op.getOperand(1); + SDOperand NewVal = Op.getOperand(2); + + // Issue a "load and reserve". + std::vector<MVT::ValueType> VTs; + VTs.push_back(VT); + VTs.push_back(MVT::Other); + + SDOperand Label = DAG.getConstant(PPCAtomicLabelIndex++, MVT::i32); + SDOperand Ops[] = { + Chain, // Chain + Ptr, // Ptr + Label, // Label + }; + SDOperand Load = DAG.getNode(PPCISD::LWARX, VTs, Ops, 3); + Chain = Load.getValue(1); + + // Issue a "store and check". + SDOperand Ops2[] = { + Chain, // Chain + NewVal, // Value + Ptr, // Ptr + Label, // Label + }; + SDOperand Store = DAG.getNode(PPCISD::STWCX, MVT::Other, Ops2, 4); + SDOperand OutOps[] = { Load, Store }; + return DAG.getNode(ISD::MERGE_VALUES, DAG.getVTList(VT, MVT::Other), + OutOps, 2); +} /// LowerSELECT_CC - Lower floating point select_cc's into fsel instruction when /// possible. @@ -3404,6 +3523,10 @@ SDOperand PPCTargetLowering::LowerOperation(SDOperand Op, SelectionDAG &DAG) { case ISD::STACKRESTORE: return LowerSTACKRESTORE(Op, DAG, PPCSubTarget); case ISD::DYNAMIC_STACKALLOC: return LowerDYNAMIC_STACKALLOC(Op, DAG, PPCSubTarget); + + case ISD::ATOMIC_LAS: return LowerAtomicLAS(Op, DAG); + case ISD::ATOMIC_LCS: return LowerAtomicLCS(Op, DAG); + case ISD::ATOMIC_SWAP: return LowerAtomicSWAP(Op, DAG); case ISD::SELECT_CC: return LowerSELECT_CC(Op, DAG); case ISD::FP_TO_SINT: return LowerFP_TO_SINT(Op, DAG); |

