Atomic op support.  If any gcc test uses __sync builtins, it might start failing on archs that haven't implemented them yet

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@47430 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp b/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
index 429855d..91e52a6 100644
--- a/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
+++ b/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
@@ -1153,6 +1153,31 @@
     break;
   }
 
+  case ISD::ATOMIC_LCS:
+  case ISD::ATOMIC_LAS:
+  case ISD::ATOMIC_SWAP: {
+    assert(((Node->getNumOperands() == 4 && Node->getOpcode() == ISD::ATOMIC_LCS) ||
+            (Node->getNumOperands() == 3 && Node->getOpcode() == ISD::ATOMIC_LAS) ||
+            (Node->getNumOperands() == 3 && Node->getOpcode() == ISD::ATOMIC_SWAP)) &&
+           "Invalid MemBarrier node!");
+    int num = Node->getOpcode() == ISD::ATOMIC_LCS ? 4 : 3;
+    MVT::ValueType VT = Node->getValueType(0);
+    switch (TLI.getOperationAction(ISD::ATOMIC_LCS, VT)) {
+    default: assert(0 && "This action is not supported yet!");
+    case TargetLowering::Legal: {
+      SDOperand Ops[4];
+      for (int x = 0; x < num; ++x)
+        Ops[x] = LegalizeOp(Node->getOperand(x));
+      Result = DAG.UpdateNodeOperands(Result, &Ops[0], num);
+      AddLegalizedOperand(SDOperand(Node, 0), Result.getValue(0));
+      AddLegalizedOperand(SDOperand(Node, 1), Result.getValue(1));
+      return Result.getValue(Op.ResNo);
+      break;
+    }
+    }
+    break;
+  }
+
   case ISD::Constant: {
     ConstantSDNode *CN = cast<ConstantSDNode>(Node);
     unsigned opAction =
@@ -4228,6 +4253,27 @@
     break;
   }
     
+  case ISD::ATOMIC_LCS: {
+    Tmp2 = PromoteOp(Node->getOperand(2));
+    Tmp3 = PromoteOp(Node->getOperand(3));
+    Result = DAG.getAtomic(Node->getOpcode(), Node->getOperand(0), 
+                           Node->getOperand(1), Tmp2, Tmp3,
+                           cast<AtomicSDNode>(Node)->getVT());
+    // Remember that we legalized the chain.
+    AddLegalizedOperand(Op.getValue(1), LegalizeOp(Result.getValue(1)));
+    break;
+  }
+  case ISD::ATOMIC_LAS:
+  case ISD::ATOMIC_SWAP: {
+    Tmp2 = PromoteOp(Node->getOperand(2));
+    Result = DAG.getAtomic(Node->getOpcode(), Node->getOperand(0), 
+                           Node->getOperand(1), Tmp2,
+                           cast<AtomicSDNode>(Node)->getVT());
+    // Remember that we legalized the chain.
+    AddLegalizedOperand(Op.getValue(1), LegalizeOp(Result.getValue(1)));
+    break;
+  }
+
   case ISD::AND:
   case ISD::OR:
   case ISD::XOR:
diff --git a/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 28f612d..803a38c 100644
--- a/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -2427,6 +2427,43 @@
   return getNode(ISD::MEMSET, MVT::Other, Ops, 6);
 }
 
+SDOperand SelectionDAG::getAtomic(unsigned Opcode, SDOperand Chain, 
+                                  SDOperand Ptr, SDOperand A2, 
+                                  SDOperand A3, MVT::ValueType VT) {
+  assert(Opcode == ISD::ATOMIC_LCS && "Invalid Atomic Op");
+  SDVTList VTs = getVTList(A2.getValueType(), MVT::Other);
+  FoldingSetNodeID ID;
+  SDOperand Ops[] = {Chain, Ptr, A2, A3};
+  AddNodeIDNode(ID, Opcode, VTs, Ops, 4);
+  ID.AddInteger((unsigned int)VT);
+  void* IP = 0;
+  if (SDNode *E = CSEMap.FindNodeOrInsertPos(ID, IP))
+    return SDOperand(E, 0);
+  SDNode* N = new AtomicSDNode(Opcode, VTs, Chain, Ptr, A2, A3, VT);
+  CSEMap.InsertNode(N, IP);
+  AllNodes.push_back(N);
+  return SDOperand(N, 0);
+}
+
+SDOperand SelectionDAG::getAtomic(unsigned Opcode, SDOperand Chain, 
+                                  SDOperand Ptr, SDOperand A2, 
+                                  MVT::ValueType VT) {
+  assert((Opcode == ISD::ATOMIC_LAS || Opcode == ISD::ATOMIC_SWAP)
+         && "Invalid Atomic Op");
+  SDVTList VTs = getVTList(A2.getValueType(), MVT::Other);
+  FoldingSetNodeID ID;
+  SDOperand Ops[] = {Chain, Ptr, A2};
+  AddNodeIDNode(ID, Opcode, VTs, Ops, 3);
+  ID.AddInteger((unsigned int)VT);
+  void* IP = 0;
+  if (SDNode *E = CSEMap.FindNodeOrInsertPos(ID, IP))
+    return SDOperand(E, 0);
+  SDNode* N = new AtomicSDNode(Opcode, VTs, Chain, Ptr, A2, VT);
+  CSEMap.InsertNode(N, IP);
+  AllNodes.push_back(N);
+  return SDOperand(N, 0);
+}
+
 SDOperand SelectionDAG::getLoad(MVT::ValueType VT,
                                 SDOperand Chain, SDOperand Ptr,
                                 const Value *SV, int SVOffset,
@@ -3593,6 +3630,7 @@
 void VTSDNode::ANCHOR() {}
 void LoadSDNode::ANCHOR() {}
 void StoreSDNode::ANCHOR() {}
+void AtomicSDNode::ANCHOR() {}
 
 HandleSDNode::~HandleSDNode() {
   SDVTList VTs = { 0, 0 };
@@ -3821,6 +3859,9 @@
     }
    
   case ISD::MEMBARRIER:    return "MemBarrier";
+  case ISD::ATOMIC_LCS:    return "AtomicLCS";
+  case ISD::ATOMIC_LAS:    return "AtomicLAS";
+  case ISD::ATOMIC_SWAP:    return "AtomicSWAP";
   case ISD::PCMARKER:      return "PCMarker";
   case ISD::READCYCLECOUNTER: return "ReadCycleCounter";
   case ISD::SRCVALUE:      return "SrcValue";
diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
index d4e33b0..def4f9a 100644
--- a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
+++ b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
@@ -221,7 +221,7 @@
 
 /// isUsedOutsideOfDefiningBlock - Return true if this instruction is used by
 /// PHI nodes or outside of the basic block that defines it, or used by a 
-/// switch instruction, which may expand to multiple basic blocks.
+/// switch or atomic instruction, which may expand to multiple basic blocks.
 static bool isUsedOutsideOfDefiningBlock(Instruction *I) {
   if (isa<PHINode>(I)) return true;
   BasicBlock *BB = I->getParent();
@@ -3059,6 +3059,38 @@
     DAG.setRoot(DAG.getNode(ISD::MEMBARRIER, MVT::Other, &Ops[0], 6));
     return 0;
   }
+  case Intrinsic::atomic_lcs: {
+    SDOperand Root = getRoot();   
+    SDOperand O3 = getValue(I.getOperand(3));
+    SDOperand L = DAG.getAtomic(ISD::ATOMIC_LCS, Root, 
+                                getValue(I.getOperand(1)), 
+                                getValue(I.getOperand(2)),
+                                O3, O3.getValueType());
+    setValue(&I, L);
+    DAG.setRoot(L.getValue(1));
+    return 0;
+  }
+  case Intrinsic::atomic_las: {
+    SDOperand Root = getRoot();   
+    SDOperand O2 = getValue(I.getOperand(2));
+    SDOperand L = DAG.getAtomic(ISD::ATOMIC_LAS, Root, 
+                                getValue(I.getOperand(1)), 
+                                O2, O2.getValueType());
+    setValue(&I, L);
+    DAG.setRoot(L.getValue(1));
+    return 0;
+  }
+  case Intrinsic::atomic_swap: {
+    SDOperand Root = getRoot();   
+    SDOperand O2 = getValue(I.getOperand(2));
+    SDOperand L = DAG.getAtomic(ISD::ATOMIC_SWAP, Root, 
+                                getValue(I.getOperand(1)), 
+                                O2, O2.getValueType());
+    setValue(&I, L);
+    DAG.setRoot(L.getValue(1));
+    return 0;
+  }
+
   }
 }