Implement llvm.atomic.cmp.swap.i32 on PPC. Patch by Gary Benson!


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@53505 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Target/PowerPC/PPCISelLowering.cpp b/lib/Target/PowerPC/PPCISelLowering.cpp
index dc38c7c..2537502 100644
--- a/lib/Target/PowerPC/PPCISelLowering.cpp
+++ b/lib/Target/PowerPC/PPCISelLowering.cpp
@@ -40,8 +40,7 @@
                                      cl::Hidden);
 
 PPCTargetLowering::PPCTargetLowering(PPCTargetMachine &TM)
-  : TargetLowering(TM), PPCSubTarget(*TM.getSubtargetImpl()),
-    PPCAtomicLabelIndex(0) {
+  : TargetLowering(TM), PPCSubTarget(*TM.getSubtargetImpl()) {
     
   setPow2DivIsCheap();
   
@@ -378,45 +377,47 @@
 const char *PPCTargetLowering::getTargetNodeName(unsigned Opcode) const {
   switch (Opcode) {
   default: return 0;
-  case PPCISD::FSEL:          return "PPCISD::FSEL";
-  case PPCISD::FCFID:         return "PPCISD::FCFID";
-  case PPCISD::FCTIDZ:        return "PPCISD::FCTIDZ";
-  case PPCISD::FCTIWZ:        return "PPCISD::FCTIWZ";
-  case PPCISD::STFIWX:        return "PPCISD::STFIWX";
-  case PPCISD::VMADDFP:       return "PPCISD::VMADDFP";
-  case PPCISD::VNMSUBFP:      return "PPCISD::VNMSUBFP";
-  case PPCISD::VPERM:         return "PPCISD::VPERM";
-  case PPCISD::Hi:            return "PPCISD::Hi";
-  case PPCISD::Lo:            return "PPCISD::Lo";
-  case PPCISD::DYNALLOC:      return "PPCISD::DYNALLOC";
-  case PPCISD::GlobalBaseReg: return "PPCISD::GlobalBaseReg";
-  case PPCISD::SRL:           return "PPCISD::SRL";
-  case PPCISD::SRA:           return "PPCISD::SRA";
-  case PPCISD::SHL:           return "PPCISD::SHL";
-  case PPCISD::EXTSW_32:      return "PPCISD::EXTSW_32";
-  case PPCISD::STD_32:        return "PPCISD::STD_32";
-  case PPCISD::CALL_ELF:      return "PPCISD::CALL_ELF";
-  case PPCISD::CALL_Macho:    return "PPCISD::CALL_Macho";
-  case PPCISD::MTCTR:         return "PPCISD::MTCTR";
-  case PPCISD::BCTRL_Macho:   return "PPCISD::BCTRL_Macho";
-  case PPCISD::BCTRL_ELF:     return "PPCISD::BCTRL_ELF";
-  case PPCISD::RET_FLAG:      return "PPCISD::RET_FLAG";
-  case PPCISD::MFCR:          return "PPCISD::MFCR";
-  case PPCISD::VCMP:          return "PPCISD::VCMP";
-  case PPCISD::VCMPo:         return "PPCISD::VCMPo";
-  case PPCISD::LBRX:          return "PPCISD::LBRX";
-  case PPCISD::STBRX:         return "PPCISD::STBRX";
-  case PPCISD::LARX:          return "PPCISD::LARX";
-  case PPCISD::STCX:          return "PPCISD::STCX";
-  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";
-  case PPCISD::MTFSB1:        return "PPCISD::MTFSB1";
-  case PPCISD::FADDRTZ:       return "PPCISD::FADDRTZ";
-  case PPCISD::MTFSF:         return "PPCISD::MTFSF";
-  case PPCISD::TAILCALL:      return "PPCISD::TAILCALL";
-  case PPCISD::TC_RETURN:     return "PPCISD::TC_RETURN";
+  case PPCISD::FSEL:            return "PPCISD::FSEL";
+  case PPCISD::FCFID:           return "PPCISD::FCFID";
+  case PPCISD::FCTIDZ:          return "PPCISD::FCTIDZ";
+  case PPCISD::FCTIWZ:          return "PPCISD::FCTIWZ";
+  case PPCISD::STFIWX:          return "PPCISD::STFIWX";
+  case PPCISD::VMADDFP:         return "PPCISD::VMADDFP";
+  case PPCISD::VNMSUBFP:        return "PPCISD::VNMSUBFP";
+  case PPCISD::VPERM:           return "PPCISD::VPERM";
+  case PPCISD::Hi:              return "PPCISD::Hi";
+  case PPCISD::Lo:              return "PPCISD::Lo";
+  case PPCISD::DYNALLOC:        return "PPCISD::DYNALLOC";
+  case PPCISD::GlobalBaseReg:   return "PPCISD::GlobalBaseReg";
+  case PPCISD::SRL:             return "PPCISD::SRL";
+  case PPCISD::SRA:             return "PPCISD::SRA";
+  case PPCISD::SHL:             return "PPCISD::SHL";
+  case PPCISD::EXTSW_32:        return "PPCISD::EXTSW_32";
+  case PPCISD::STD_32:          return "PPCISD::STD_32";
+  case PPCISD::CALL_ELF:        return "PPCISD::CALL_ELF";
+  case PPCISD::CALL_Macho:      return "PPCISD::CALL_Macho";
+  case PPCISD::MTCTR:           return "PPCISD::MTCTR";
+  case PPCISD::BCTRL_Macho:     return "PPCISD::BCTRL_Macho";
+  case PPCISD::BCTRL_ELF:       return "PPCISD::BCTRL_ELF";
+  case PPCISD::RET_FLAG:        return "PPCISD::RET_FLAG";
+  case PPCISD::MFCR:            return "PPCISD::MFCR";
+  case PPCISD::VCMP:            return "PPCISD::VCMP";
+  case PPCISD::VCMPo:           return "PPCISD::VCMPo";
+  case PPCISD::LBRX:            return "PPCISD::LBRX";
+  case PPCISD::STBRX:           return "PPCISD::STBRX";
+  case PPCISD::ATOMIC_LOAD_ADD: return "PPCISD::ATOMIC_LOAD_ADD";
+  case PPCISD::ATOMIC_CMP_SWAP: return "PPCISD::ATOMIC_CMP_SWAP";
+  case PPCISD::ATOMIC_SWAP:     return "PPCISD::ATOMIC_SWAP";
+  case PPCISD::LARX:            return "PPCISD::LARX";
+  case PPCISD::STCX:            return "PPCISD::STCX";
+  case PPCISD::COND_BRANCH:     return "PPCISD::COND_BRANCH";
+  case PPCISD::MFFS:            return "PPCISD::MFFS";
+  case PPCISD::MTFSB0:          return "PPCISD::MTFSB0";
+  case PPCISD::MTFSB1:          return "PPCISD::MTFSB1";
+  case PPCISD::FADDRTZ:         return "PPCISD::FADDRTZ";
+  case PPCISD::MTFSF:           return "PPCISD::MTFSF";
+  case PPCISD::TAILCALL:        return "PPCISD::TAILCALL";
+  case PPCISD::TC_RETURN:       return "PPCISD::TC_RETURN";
   }
 }
 
@@ -2726,33 +2727,13 @@
   SDOperand Ptr     = Op.getOperand(1);
   SDOperand Incr    = Op.getOperand(2);
 
-  // Issue a "load and reserve".
-  std::vector<MVT> VTs;
-  VTs.push_back(VT);
-  VTs.push_back(MVT::Other);
-
-  SDOperand Label  = DAG.getConstant(PPCAtomicLabelIndex++, MVT::i32);
+  SDVTList VTs = DAG.getVTList(VT, MVT::Other);
   SDOperand Ops[] = {
-    Chain,               // Chain
-    Ptr,                 // Ptr
-    Label,               // Label
+    Chain,
+    Ptr,
+    Incr,
   };
-  SDOperand Load = DAG.getNode(PPCISD::LARX, 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::STCX, MVT::Other, Ops2, 4);
-  SDOperand OutOps[] = { Load, Store };
-  return DAG.getMergeValues(OutOps, 2);
+  return DAG.getNode(PPCISD::ATOMIC_LOAD_ADD, VTs, Ops, 3);
 }
 
 SDOperand PPCTargetLowering::LowerAtomicCMP_SWAP(SDOperand Op, SelectionDAG &DAG) {
@@ -2762,39 +2743,14 @@
   SDOperand NewVal  = Op.getOperand(2);
   SDOperand OldVal  = Op.getOperand(3);
 
-  // Issue a "load and reserve".
-  std::vector<MVT> VTs;
-  VTs.push_back(VT);
-  VTs.push_back(MVT::Other);
-
-  SDOperand Label  = DAG.getConstant(PPCAtomicLabelIndex++, MVT::i32);
+  SDVTList VTs = DAG.getVTList(VT, MVT::Other);
   SDOperand Ops[] = {
-    Chain,               // Chain
-    Ptr,                 // Ptr
-    Label,               // Label
+    Chain,
+    Ptr,
+    OldVal,
+    NewVal,
   };
-  SDOperand Load = DAG.getNode(PPCISD::LARX, 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::STCX, MVT::Other, Ops3, 4);
-  SDOperand OutOps[] = { Load, Store };
-  return DAG.getMergeValues(OutOps, 2);
+  return DAG.getNode(PPCISD::ATOMIC_CMP_SWAP, VTs, Ops, 4);
 }
 
 SDOperand PPCTargetLowering::LowerAtomicSWAP(SDOperand Op, SelectionDAG &DAG) {
@@ -2803,30 +2759,13 @@
   SDOperand Ptr     = Op.getOperand(1);
   SDOperand NewVal  = Op.getOperand(2);
 
-  // Issue a "load and reserve".
-  std::vector<MVT> VTs;
-  VTs.push_back(VT);
-  VTs.push_back(MVT::Other);
-
-  SDOperand Label  = DAG.getConstant(PPCAtomicLabelIndex++, MVT::i32);
+  SDVTList VTs = DAG.getVTList(VT, MVT::Other);
   SDOperand Ops[] = {
-    Chain,               // Chain
-    Ptr,                 // Ptr
-    Label,               // Label
+    Chain,
+    Ptr,
+    NewVal,
   };
-  SDOperand Load = DAG.getNode(PPCISD::LARX, 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::STCX, MVT::Other, Ops2, 4);
-  SDOperand OutOps[] = { Load, Store };
-  return DAG.getMergeValues(OutOps, 2);
+  return DAG.getNode(PPCISD::ATOMIC_SWAP, VTs, Ops, 3);
 }
 
 /// LowerSELECT_CC - Lower floating point select_cc's into fsel instruction when
@@ -3981,58 +3920,197 @@
 PPCTargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI,
                                                MachineBasicBlock *BB) {
   const TargetInstrInfo *TII = getTargetMachine().getInstrInfo();
-  assert((MI->getOpcode() == PPC::SELECT_CC_I4 ||
-          MI->getOpcode() == PPC::SELECT_CC_I8 ||
-          MI->getOpcode() == PPC::SELECT_CC_F4 ||
-          MI->getOpcode() == PPC::SELECT_CC_F8 ||
-          MI->getOpcode() == PPC::SELECT_CC_VRRC) &&
-         "Unexpected instr type to insert");
-  
-  // To "insert" a SELECT_CC instruction, we actually have to insert the diamond
-  // control-flow pattern.  The incoming instruction knows the destination vreg
-  // to set, the condition code register to branch on, the true/false values to
-  // select between, and a branch opcode to use.
+
+  // To "insert" these instructions we actually have to insert their
+  // control-flow patterns.
   const BasicBlock *LLVM_BB = BB->getBasicBlock();
   MachineFunction::iterator It = BB;
   ++It;
-  
-  //  thisMBB:
-  //  ...
-  //   TrueVal = ...
-  //   cmpTY ccX, r1, r2
-  //   bCC copy1MBB
-  //   fallthrough --> copy0MBB
-  MachineBasicBlock *thisMBB = BB;
+
   MachineFunction *F = BB->getParent();
-  MachineBasicBlock *copy0MBB = F->CreateMachineBasicBlock(LLVM_BB);
-  MachineBasicBlock *sinkMBB = F->CreateMachineBasicBlock(LLVM_BB);
-  unsigned SelectPred = MI->getOperand(4).getImm();
-  BuildMI(BB, TII->get(PPC::BCC))
-    .addImm(SelectPred).addReg(MI->getOperand(1).getReg()).addMBB(sinkMBB);
-  F->insert(It, copy0MBB);
-  F->insert(It, sinkMBB);
-  // Update machine-CFG edges by transferring all successors of the current
-  // block to the new block which will contain the Phi node for the select.
-  sinkMBB->transferSuccessors(BB);
-  // Next, add the true and fallthrough blocks as its successors.
-  BB->addSuccessor(copy0MBB);
-  BB->addSuccessor(sinkMBB);
-  
-  //  copy0MBB:
-  //   %FalseValue = ...
-  //   # fallthrough to sinkMBB
-  BB = copy0MBB;
-  
-  // Update machine-CFG edges
-  BB->addSuccessor(sinkMBB);
-  
-  //  sinkMBB:
-  //   %Result = phi [ %FalseValue, copy0MBB ], [ %TrueValue, thisMBB ]
-  //  ...
-  BB = sinkMBB;
-  BuildMI(BB, TII->get(PPC::PHI), MI->getOperand(0).getReg())
-    .addReg(MI->getOperand(3).getReg()).addMBB(copy0MBB)
-    .addReg(MI->getOperand(2).getReg()).addMBB(thisMBB);
+
+  if (MI->getOpcode() == PPC::SELECT_CC_I4 ||
+      MI->getOpcode() == PPC::SELECT_CC_I8 ||
+      MI->getOpcode() == PPC::SELECT_CC_F4 ||
+      MI->getOpcode() == PPC::SELECT_CC_F8 ||
+      MI->getOpcode() == PPC::SELECT_CC_VRRC) {
+
+    // The incoming instruction knows the destination vreg to set, the
+    // condition code register to branch on, the true/false values to
+    // select between, and a branch opcode to use.
+
+    //  thisMBB:
+    //  ...
+    //   TrueVal = ...
+    //   cmpTY ccX, r1, r2
+    //   bCC copy1MBB
+    //   fallthrough --> copy0MBB
+    MachineBasicBlock *thisMBB = BB;
+    MachineBasicBlock *copy0MBB = F->CreateMachineBasicBlock(LLVM_BB);
+    MachineBasicBlock *sinkMBB = F->CreateMachineBasicBlock(LLVM_BB);
+    unsigned SelectPred = MI->getOperand(4).getImm();
+    BuildMI(BB, TII->get(PPC::BCC))
+      .addImm(SelectPred).addReg(MI->getOperand(1).getReg()).addMBB(sinkMBB);
+    F->insert(It, copy0MBB);
+    F->insert(It, sinkMBB);
+    // Update machine-CFG edges by transferring all successors of the current
+    // block to the new block which will contain the Phi node for the select.
+    sinkMBB->transferSuccessors(BB);
+    // Next, add the true and fallthrough blocks as its successors.
+    BB->addSuccessor(copy0MBB);
+    BB->addSuccessor(sinkMBB);
+    
+    //  copy0MBB:
+    //   %FalseValue = ...
+    //   # fallthrough to sinkMBB
+    BB = copy0MBB;
+    
+    // Update machine-CFG edges
+    BB->addSuccessor(sinkMBB);
+    
+    //  sinkMBB:
+    //   %Result = phi [ %FalseValue, copy0MBB ], [ %TrueValue, thisMBB ]
+    //  ...
+    BB = sinkMBB;
+    BuildMI(BB, TII->get(PPC::PHI), MI->getOperand(0).getReg())
+      .addReg(MI->getOperand(3).getReg()).addMBB(copy0MBB)
+      .addReg(MI->getOperand(2).getReg()).addMBB(thisMBB);
+  }
+  else if (MI->getOpcode() == PPC::ATOMIC_LOAD_ADD_I32 ||
+           MI->getOpcode() == PPC::ATOMIC_LOAD_ADD_I64) {
+    bool is64bit = MI->getOpcode() == PPC::ATOMIC_LOAD_ADD_I64;
+
+    unsigned dest = MI->getOperand(0).getReg();
+    unsigned ptrA = MI->getOperand(1).getReg();
+    unsigned ptrB = MI->getOperand(2).getReg();
+    unsigned incr = MI->getOperand(3).getReg();
+
+    MachineBasicBlock *loopMBB = F->CreateMachineBasicBlock(LLVM_BB);
+    MachineBasicBlock *exitMBB = F->CreateMachineBasicBlock(LLVM_BB);
+    F->insert(It, loopMBB);
+    F->insert(It, exitMBB);
+    exitMBB->transferSuccessors(BB);
+
+    MachineRegisterInfo &RegInfo = F->getRegInfo();
+    unsigned TmpReg = RegInfo.createVirtualRegister(
+      is64bit ? (const TargetRegisterClass *) &PPC::GPRCRegClass :
+                (const TargetRegisterClass *) &PPC::G8RCRegClass);
+
+    //  thisMBB:
+    //   ...
+    //   fallthrough --> loopMBB
+    BB->addSuccessor(loopMBB);
+
+    //  loopMBB:
+    //   l[wd]arx dest, ptr
+    //   add r0, dest, incr
+    //   st[wd]cx. r0, ptr
+    //   bne- loopMBB
+    //   fallthrough --> exitMBB
+    BB = loopMBB;
+    BuildMI(BB, TII->get(is64bit ? PPC::LDARX : PPC::LWARX), dest)
+      .addReg(ptrA).addReg(ptrB);
+    BuildMI(BB, TII->get(is64bit ? PPC::ADD4 : PPC::ADD8), TmpReg)
+      .addReg(incr).addReg(dest);
+    BuildMI(BB, TII->get(is64bit ? PPC::STDCX : PPC::STWCX))
+      .addReg(TmpReg).addReg(ptrA).addReg(ptrB);
+    BuildMI(BB, TII->get(PPC::BCC))
+      .addImm(PPC::PRED_NE).addReg(PPC::CR0).addMBB(loopMBB);    
+    BB->addSuccessor(loopMBB);
+    BB->addSuccessor(exitMBB);
+    
+    //  exitMBB:
+    //   ...
+    BB = exitMBB;
+  }
+  else if (MI->getOpcode() == PPC::ATOMIC_CMP_SWAP_I32 ||
+           MI->getOpcode() == PPC::ATOMIC_CMP_SWAP_I64) {
+    bool is64bit = MI->getOpcode() == PPC::ATOMIC_CMP_SWAP_I64;
+
+    unsigned dest   = MI->getOperand(0).getReg();
+    unsigned ptrA   = MI->getOperand(1).getReg();
+    unsigned ptrB   = MI->getOperand(2).getReg();
+    unsigned oldval = MI->getOperand(3).getReg();
+    unsigned newval = MI->getOperand(4).getReg();
+
+    MachineBasicBlock *loopMBB = F->CreateMachineBasicBlock(LLVM_BB);
+    MachineBasicBlock *exitMBB = F->CreateMachineBasicBlock(LLVM_BB);
+    F->insert(It, loopMBB);
+    F->insert(It, exitMBB);
+    exitMBB->transferSuccessors(BB);
+
+    //  thisMBB:
+    //   ...
+    //   fallthrough --> loopMBB
+    BB->addSuccessor(loopMBB);
+
+    //  loopMBB:
+    //   l[wd]arx dest, ptr
+    //   cmp[wd] dest, oldval
+    //   bne- exitMBB
+    //   st[wd]cx. newval, ptr
+    //   bne- loopMBB
+    //   fallthrough --> exitMBB
+    BB = loopMBB;
+    BuildMI(BB, TII->get(is64bit ? PPC::LDARX : PPC::LWARX), dest)
+      .addReg(ptrA).addReg(ptrB);
+    BuildMI(BB, TII->get(is64bit ? PPC::CMPD : PPC::CMPW), PPC::CR0)
+      .addReg(oldval).addReg(dest);
+    BuildMI(BB, TII->get(PPC::BCC))
+      .addImm(PPC::PRED_NE).addReg(PPC::CR0).addMBB(exitMBB);
+    BuildMI(BB, TII->get(is64bit ? PPC::STDCX : PPC::STWCX))
+      .addReg(newval).addReg(ptrA).addReg(ptrB);
+    BuildMI(BB, TII->get(PPC::BCC))
+      .addImm(PPC::PRED_NE).addReg(PPC::CR0).addMBB(loopMBB);    
+    BB->addSuccessor(loopMBB);
+    BB->addSuccessor(exitMBB);
+    
+    //  exitMBB:
+    //   ...
+    BB = exitMBB;
+  }
+  else if (MI->getOpcode() == PPC::ATOMIC_SWAP_I32 ||
+           MI->getOpcode() == PPC::ATOMIC_SWAP_I64) {
+    bool is64bit = MI->getOpcode() == PPC::ATOMIC_SWAP_I64;
+
+    unsigned dest   = MI->getOperand(0).getReg();
+    unsigned ptrA   = MI->getOperand(1).getReg();
+    unsigned ptrB   = MI->getOperand(2).getReg();
+    unsigned newval = MI->getOperand(3).getReg();
+
+    MachineBasicBlock *loopMBB = F->CreateMachineBasicBlock(LLVM_BB);
+    MachineBasicBlock *exitMBB = F->CreateMachineBasicBlock(LLVM_BB);
+    F->insert(It, loopMBB);
+    F->insert(It, exitMBB);
+    exitMBB->transferSuccessors(BB);
+
+    //  thisMBB:
+    //   ...
+    //   fallthrough --> loopMBB
+    BB->addSuccessor(loopMBB);
+
+    //  loopMBB:
+    //   l[wd]arx dest, ptr
+    //   st[wd]cx. newval, ptr
+    //   bne- loopMBB
+    //   fallthrough --> exitMBB
+    BB = loopMBB;
+    BuildMI(BB, TII->get(is64bit ? PPC::LDARX : PPC::LWARX), dest)
+      .addReg(ptrA).addReg(ptrB);
+    BuildMI(BB, TII->get(is64bit ? PPC::STDCX : PPC::STWCX))
+      .addReg(newval).addReg(ptrA).addReg(ptrB);
+    BuildMI(BB, TII->get(PPC::BCC))
+      .addImm(PPC::PRED_NE).addReg(PPC::CR0).addMBB(loopMBB);    
+    BB->addSuccessor(loopMBB);
+    BB->addSuccessor(exitMBB);
+    
+    //  exitMBB:
+    //   ...
+    BB = exitMBB;
+  }
+  else {
+    assert(0 && "Unexpected instr type to insert");
+  }
 
   F->DeleteMachineInstr(MI);   // The pseudo instruction is gone now.
   return BB;