cl::Hidden);
PPCTargetLowering::PPCTargetLowering(PPCTargetMachine &TM)
- : TargetLowering(TM), PPCSubTarget(*TM.getSubtargetImpl()) {
+ : TargetLowering(TM), PPCSubTarget(*TM.getSubtargetImpl()),
+ PPCAtomicLabelIndex(0) {
setPow2DivIsCheap();
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);
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";
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.
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);
FADDRTZ,
/// MTFSF = F8RC, INFLAG - This moves the register into the FPSCR.
- MTFSF
+ MTFSF,
+
+ /// LWARX = This corresponds to PPC lwarx instrcution: load word and
+ /// reserve indexed. This is used to implement atomic operations.
+ LWARX,
+
+ /// STWCX = This corresponds to PPC stwcx. instrcution: store word
+ /// conditional indexed. This is used to implement atomic operations.
+ STWCX,
+
+ /// CMP_UNRESERVE = Test for equality and "unreserve" if not true. This
+ /// is used to implement atomic operations.
+ CMP_UNRESERVE
};
}
/// the offset of the target addressing mode.
virtual bool isLegalAddressImmediate(GlobalValue *GV) const;
+ private:
+ /// PPCAtomicLabelIndex - Keep track the number of PPC atomic labels.
+ ///
+ unsigned PPCAtomicLabelIndex;
+
SDOperand LowerRETURNADDR(SDOperand Op, SelectionDAG &DAG);
SDOperand LowerFRAMEADDR(SDOperand Op, SelectionDAG &DAG);
SDOperand LowerConstantPool(SDOperand Op, SelectionDAG &DAG);
SDOperand LowerDYNAMIC_STACKALLOC(SDOperand Op, SelectionDAG &DAG,
const PPCSubtarget &Subtarget);
SDOperand LowerSELECT_CC(SDOperand Op, SelectionDAG &DAG);
+ SDOperand LowerAtomicLAS(SDOperand Op, SelectionDAG &DAG);
+ SDOperand LowerAtomicLCS(SDOperand Op, SelectionDAG &DAG);
+ SDOperand LowerAtomicSWAP(SDOperand Op, SelectionDAG &DAG);
SDOperand LowerFP_TO_SINT(SDOperand Op, SelectionDAG &DAG);
SDOperand LowerSINT_TO_FP(SDOperand Op, SelectionDAG &DAG);
SDOperand LowerFP_ROUND_INREG(SDOperand Op, SelectionDAG &DAG);
SDTCisVT<0, i32>, SDTCisPtrTy<1>, SDTCisVT<2, OtherVT>, SDTCisVT<3, OtherVT>
]>;
+def SDT_PPClwarx : SDTypeProfile<1, 2, [
+ SDTCisVT<0, i32>, SDTCisPtrTy<1>, SDTCisVT<2, i32>
+]>;
+def SDT_PPCstwcx : SDTypeProfile<0, 3, [
+ SDTCisVT<0, i32>, SDTCisPtrTy<1>, SDTCisVT<2, i32>
+]>;
+def SDT_PPCcmp_unres : SDTypeProfile<0, 3, [
+ SDTCisVT<0, i32>, SDTCisSameAs<0, 1>, SDTCisSameAs<1, 2>
+]>;
+
//===----------------------------------------------------------------------===//
// PowerPC specific DAG Nodes.
//
def PPCstbrx : SDNode<"PPCISD::STBRX", SDT_PPCstbrx,
[SDNPHasChain, SDNPMayStore]>;
+def PPClwarx : SDNode<"PPCISD::LWARX", SDT_PPClwarx,
+ [SDNPHasChain, SDNPMayLoad]>;
+def PPCstwcx : SDNode<"PPCISD::STWCX", SDT_PPCstwcx,
+ [SDNPHasChain, SDNPMayStore]>;
+def PPCcmp_unres : SDNode<"PPCISD::CMP_UNRESERVE", SDT_PPCcmp_unres,
+ [SDNPHasChain]>;
+
// Instructions to support dynamic alloca.
def SDTDynOp : SDTypeProfile<1, 2, []>;
def PPCdynalloc : SDNode<"PPCISD::DYNALLOC", SDTDynOp, [SDNPHasChain]>;
"dcbzl $dst", LdStDCBF, [(int_ppc_dcbzl xoaddr:$dst)]>,
PPC970_DGroup_Single;
+// Atomic operations.
+def LWARX : Pseudo<(outs GPRC:$rD), (ins memrr:$ptr, i32imm:$label),
+ "\nLa${label}_entry:\n\tlwarx $rD, $ptr",
+ [(set GPRC:$rD, (PPClwarx xoaddr:$ptr, imm:$label))]>;
+
+let Defs = [CR0] in {
+def STWCX : Pseudo<(outs), (ins GPRC:$rS, memrr:$dst, i32imm:$label),
+ "stwcx. $rS, $dst\n\tbne- La${label}_entry\nLa${label}_exit:",
+ [(PPCstwcx GPRC:$rS, xoaddr:$dst, imm:$label)]>;
+
+def CMP_UNRESw : Pseudo<(outs), (ins GPRC:$rA, GPRC:$rB, i32imm:$label),
+ "cmpw $rA, $rB\n\tbne- La${label}_exit",
+ [(PPCcmp_unres GPRC:$rA, GPRC:$rB, imm:$label)]>;
+def CMP_UNRESwi : Pseudo<(outs), (ins GPRC:$rA, s16imm:$imm, i32imm:$label),
+ "cmpwi $rA, $imm\n\tbne- La${label}_exit",
+ [(PPCcmp_unres GPRC:$rA, imm:$imm, imm:$label)]>;
+}
+
//===----------------------------------------------------------------------===//
// PPC32 Load Instructions.
//
def : Pat<(extloadf32 xaddr:$src),
(FMRSD (LFSX xaddr:$src))>;
+// Atomic operations
+def : Pat<(PPCcmp_unres imm:$imm, GPRC:$rA, imm:$label),
+ (CMP_UNRESwi GPRC:$rA, imm:$imm, imm:$label)>;
+
include "PPCInstrAltivec.td"
include "PPCInstr64Bit.td"