PPC32 atomic operations.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@49947 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Target/PowerPC/PPCISelLowering.cpp b/lib/Target/PowerPC/PPCISelLowering.cpp
index 83bea7e..1d3bf22 100644
--- a/lib/Target/PowerPC/PPCISelLowering.cpp
+++ b/lib/Target/PowerPC/PPCISelLowering.cpp
@@ -39,7 +39,8 @@
cl::Hidden);
PPCTargetLowering::PPCTargetLowering(PPCTargetMachine &TM)
- : TargetLowering(TM), PPCSubTarget(*TM.getSubtargetImpl()) {
+ : TargetLowering(TM), PPCSubTarget(*TM.getSubtargetImpl()),
+ PPCAtomicLabelIndex(0) {
setPow2DivIsCheap();
@@ -202,6 +203,10 @@
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 @@
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 @@
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 @@
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);