Atomic op support. If any gcc test uses __sync builtins, it might start failing...
authorAndrew Lenharth <andrewl@lenharth.org>
Thu, 21 Feb 2008 06:45:13 +0000 (06:45 +0000)
committerAndrew Lenharth <andrewl@lenharth.org>
Thu, 21 Feb 2008 06:45:13 +0000 (06:45 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@47430 91177308-0d34-0410-b5e6-96231b3b80d8

13 files changed:
docs/LangRef.html
include/llvm/CodeGen/SelectionDAG.h
include/llvm/CodeGen/SelectionDAGNodes.h
include/llvm/Intrinsics.td
include/llvm/Target/TargetLowering.h
lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
lib/CodeGen/SelectionDAG/SelectionDAG.cpp
lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
lib/Target/Alpha/AlphaISelLowering.cpp
lib/Target/Alpha/AlphaISelLowering.h
lib/Target/Alpha/AlphaInstrInfo.td
lib/Target/TargetSelectionDAG.td
lib/Target/X86/X86InstrInfo.td

index af88237adc817cec11db48d6d8192c96addb09eb..d09d34860e25522c7515e65a84f4cdd65ca121ae 100644 (file)
       </li>
           <li><a href="#int_atomics">Atomic intrinsics</a>
             <ol>
       </li>
           <li><a href="#int_atomics">Atomic intrinsics</a>
             <ol>
-              <li><a href="#int_memory_barrier"><tt>llvm.memory_barrier</tt></li>
+              <li><a href="#int_memory_barrier"><tt>llvm.memory_barrier</tt></a></li>
+              <li><a href="#int_atomic_lcs"><tt>llvm.atomic.lcs</tt></a></li>
+              <li><a href="#int_atomic_las"><tt>llvm.atomic.las</tt></a></li>
+              <li><a href="#int_atomic_swap"><tt>llvm.atomic.swap</tt></a></li>
             </ol>
           </li>
       <li><a href="#int_general">General intrinsics</a>
             </ol>
           </li>
       <li><a href="#int_general">General intrinsics</a>
@@ -5339,6 +5342,176 @@ i1 &lt;device&gt; )
 </pre>
 </div>
 
 </pre>
 </div>
 
+<!-- _______________________________________________________________________ -->
+<div class="doc_subsubsection">
+  <a name="int_atomic_lcs">'<tt>llvm.atomic.lcs.*</tt>' Intrinsic</a>
+</div>
+<div class="doc_text">
+<h5>Syntax:</h5>
+<p>
+  This is an overloaded intrinsic. You can use <tt>llvm.atomic.lcs</tt> on any 
+  integer bit width. Not all targets support all bit widths however.</p>
+
+<pre>
+declare i8 @llvm.atomic.lcs.i8( i8* &lt;ptr&gt;, i8 &lt;cmp&gt;, i8 &lt;val&gt; )
+declare i16 @llvm.atomic.lcs.i16( i16* &lt;ptr&gt;, i16 &lt;cmp&gt;, i16 &lt;val&gt; )
+declare i32 @llvm.atomic.lcs.i32( i32* &lt;ptr&gt;, i32 &lt;cmp&gt;, i32 &lt;val&gt; )
+declare i64 @llvm.atomic.lcs.i64( i64* &lt;ptr&gt;, i64 &lt;cmp&gt;, i64 &lt;val&gt; )
+
+</pre>
+<h5>Overview:</h5>
+<p>
+  This loads a value in memory and compares it to a given value. If they are 
+  equal, it stores a new value into the memory.
+</p>
+<h5>Arguments:</h5>
+<p>
+  The <tt>llvm.atomic.lcs</tt> intrinsic takes three arguments. The result as 
+  well as both <tt>cmp</tt> and <tt>val</tt> must be integer values with the 
+  same bit width. The <tt>ptr</tt> argument must be a pointer to a value of 
+  this integer type. While any bit width integer may be used, targets may only 
+  lower representations they support in hardware.
+
+</p>
+<h5>Semantics:</h5>
+<p>
+  This entire intrinsic must be executed atomically. It first loads the value 
+  in memory pointed to by <tt>ptr</tt> and compares it with the value 
+  <tt>cmp</tt>. If they are equal, <tt>val</tt> is stored into the memory. The 
+  loaded value is yielded in all cases. This provides the equivalent of an 
+  atomic compare-and-swap operation within the SSA framework.
+</p>
+<h5>Examples:</h5>
+
+<pre>
+%ptr      = malloc i32
+            store i32 4, %ptr
+
+%val1     = add i32 4, 4
+%result1  = call i32 @llvm.atomic.lcs.i32( i32* %ptr, i32 4, %val1 )
+                                          <i>; yields {i32}:result1 = 4</i>
+%stored1  = icmp eq i32 %result1, 4       <i>; yields {i1}:stored1 = true</i>
+%memval1  = load i32* %ptr                <i>; yields {i32}:memval1 = 8</i>
+
+%val2     = add i32 1, 1
+%result2  = call i32 @llvm.atomic.lcs.i32( i32* %ptr, i32 5, %val2 )
+                                          <i>; yields {i32}:result2 = 8</i>
+%stored2  = icmp eq i32 %result2, 5       <i>; yields {i1}:stored2 = false</i>
+
+%memval2  = load i32* %ptr                <i>; yields {i32}:memval2 = 8</i>
+</pre>
+</div>
+
+<!-- _______________________________________________________________________ -->
+<div class="doc_subsubsection">
+  <a name="int_atomic_swap">'<tt>llvm.atomic.swap.*</tt>' Intrinsic</a>
+</div>
+<div class="doc_text">
+<h5>Syntax:</h5>
+
+<p>
+  This is an overloaded intrinsic. You can use <tt>llvm.atomic.swap</tt> on any 
+  integer bit width. Not all targets support all bit widths however.</p>
+<pre>
+declare i8 @llvm.atomic.swap.i8( i8* &lt;ptr&gt;, i8 &lt;val&gt; )
+declare i16 @llvm.atomic.swap.i16( i16* &lt;ptr&gt;, i16 &lt;val&gt; )
+declare i32 @llvm.atomic.swap.i32( i32* &lt;ptr&gt;, i32 &lt;val&gt; )
+declare i64 @llvm.atomic.swap.i64( i64* &lt;ptr&gt;, i64 &lt;val&gt; )
+
+</pre>
+<h5>Overview:</h5>
+<p>
+  This intrinsic loads the value stored in memory at <tt>ptr</tt> and yields 
+  the value from memory. It then stores the value in <tt>val</tt> in the memory 
+  at <tt>ptr</tt>.
+</p>
+<h5>Arguments:</h5>
+
+<p>
+  The <tt>llvm.atomic.ls</tt> intrinsic takes two arguments. Both the 
+  <tt>val</tt> argument and the result must be integers of the same bit width. 
+  The first argument, <tt>ptr</tt>, must be a pointer to a value of this 
+  integer type. The targets may only lower integer representations they 
+  support.
+</p>
+<h5>Semantics:</h5>
+<p>
+  This intrinsic loads the value pointed to by <tt>ptr</tt>, yields it, and 
+  stores <tt>val</tt> back into <tt>ptr</tt> atomically. This provides the 
+  equivalent of an atomic swap operation within the SSA framework.
+
+</p>
+<h5>Examples:</h5>
+<pre>
+%ptr      = malloc i32
+            store i32 4, %ptr
+
+%val1     = add i32 4, 4
+%result1  = call i32 @llvm.atomic.swap.i32( i32* %ptr, i32 %val1 )
+                                        <i>; yields {i32}:result1 = 4</i>
+%stored1  = icmp eq i32 %result1, 4     <i>; yields {i1}:stored1 = true</i>
+%memval1  = load i32* %ptr              <i>; yields {i32}:memval1 = 8</i>
+
+%val2     = add i32 1, 1
+%result2  = call i32 @llvm.atomic.swap.i32( i32* %ptr, i32 %val2 )
+                                        <i>; yields {i32}:result2 = 8</i>
+
+%stored2  = icmp eq i32 %result2, 8     <i>; yields {i1}:stored2 = true</i>
+%memval2  = load i32* %ptr              <i>; yields {i32}:memval2 = 2</i>
+</pre>
+</div>
+
+<!-- _______________________________________________________________________ -->
+<div class="doc_subsubsection">
+  <a name="int_atomic_las">'<tt>llvm.atomic.las.*</tt>' Intrinsic</a>
+
+</div>
+<div class="doc_text">
+<h5>Syntax:</h5>
+<p>
+  This is an overloaded intrinsic. You can use <tt>llvm.atomic.las</tt> on any 
+  integer bit width. Not all targets support all bit widths however.</p>
+<pre>
+declare i8 @llvm.atomic.las.i8.( i8* &lt;ptr&gt;, i8 &lt;delta&gt; )
+declare i16 @llvm.atomic.las.i16.( i16* &lt;ptr&gt;, i16 &lt;delta&gt; )
+declare i32 @llvm.atomic.las.i32.( i32* &lt;ptr&gt;, i32 &lt;delta&gt; )
+declare i64 @llvm.atomic.las.i64.( i64* &lt;ptr&gt;, i64 &lt;delta&gt; )
+
+</pre>
+<h5>Overview:</h5>
+<p>
+  This intrinsic adds <tt>delta</tt> to the value stored in memory at 
+  <tt>ptr</tt>. It yields the original value at <tt>ptr</tt>.
+</p>
+<h5>Arguments:</h5>
+<p>
+
+  The intrinsic takes two arguments, the first a pointer to an integer value 
+  and the second an integer value. The result is also an integer value. These 
+  integer types can have any bit width, but they must all have the same bit 
+  width. The targets may only lower integer representations they support.
+</p>
+<h5>Semantics:</h5>
+<p>
+  This intrinsic does a series of operations atomically. It first loads the 
+  value stored at <tt>ptr</tt>. It then adds <tt>delta</tt>, stores the result 
+  to <tt>ptr</tt>. It yields the original value stored at <tt>ptr</tt>.
+</p>
+
+<h5>Examples:</h5>
+<pre>
+%ptr      = malloc i32
+        store i32 4, %ptr
+%result1  = call i32 @llvm.atomic.las.i32( i32* %ptr, i32 4 )
+                                <i>; yields {i32}:result1 = 4</i>
+%result2  = call i32 @llvm.atomic.las.i32( i32* %ptr, i32 2 )
+                                <i>; yields {i32}:result2 = 8</i>
+%result3  = call i32 @llvm.atomic.las.i32( i32* %ptr, i32 5 )
+                                <i>; yields {i32}:result3 = 10</i>
+%memval   = load i32* %ptr      <i>; yields {i32}:memval1 = 15</i>
+</pre>
+</div>
+
 
 <!-- ======================================================================= -->
 <div class="doc_subsection">
 
 <!-- ======================================================================= -->
 <div class="doc_subsection">
index 22487dd5c37b98e6d664c40598ea52931647cd2f..70c7185c613abf7935e94736ad4055aee3509157 100644 (file)
@@ -356,6 +356,16 @@ public:
   SDOperand getVAArg(MVT::ValueType VT, SDOperand Chain, SDOperand Ptr,
                      SDOperand SV);
 
   SDOperand getVAArg(MVT::ValueType VT, SDOperand Chain, SDOperand Ptr,
                      SDOperand SV);
 
+  /// getAtomic - Gets a node for an atomic op, produces result and chain, takes
+  // 3 operands
+  SDOperand getAtomic(unsigned Opcode, SDOperand Chain, SDOperand Ptr, 
+                      SDOperand A2, SDOperand A3, MVT::ValueType VT);
+
+  /// getAtomic - Gets a node for an atomic op, produces result and chain, takes
+  // 2 operands
+  SDOperand getAtomic(unsigned Opcode, SDOperand Chain, SDOperand Ptr, 
+                      SDOperand A2, MVT::ValueType VT);
+
   /// getLoad - Loads are not normal binary operators: their result type is not
   /// determined by their operands, and they produce a value AND a token chain.
   ///
   /// getLoad - Loads are not normal binary operators: their result type is not
   /// determined by their operands, and they produce a value AND a token chain.
   ///
index c1a50bb7dc7e2e4b3be7c5f8404ed15e53a76b25..293bb73a2390afbe1f585c25819e337b78c50c0f 100644 (file)
@@ -441,7 +441,7 @@ namespace ISD {
     // is added / subtracted from the base pointer to form the address (for
     // indexed memory ops).
     LOAD, STORE,
     // is added / subtracted from the base pointer to form the address (for
     // indexed memory ops).
     LOAD, STORE,
-    
+
     // DYNAMIC_STACKALLOC - Allocate some number of bytes on the stack aligned
     // to a specified boundary.  This node always has two return values: a new
     // stack pointer value and a chain. The first operand is the token chain,
     // DYNAMIC_STACKALLOC - Allocate some number of bytes on the stack aligned
     // to a specified boundary.  This node always has two return values: a new
     // stack pointer value and a chain. The first operand is the token chain,
@@ -591,12 +591,30 @@ namespace ISD {
 
     // OUTCHAIN = MEMBARRIER(INCHAIN, load-load, load-store, store-load, 
     //                       store-store, device)
 
     // OUTCHAIN = MEMBARRIER(INCHAIN, load-load, load-store, store-load, 
     //                       store-store, device)
-    // This corresponds to the atomic.barrier intrinsic.
+    // This corresponds to the memory.barrier intrinsic.
     // it takes an input chain, 4 operands to specify the type of barrier, an
     // operand specifying if the barrier applies to device and uncached memory
     // and produces an output chain.
     MEMBARRIER,
 
     // it takes an input chain, 4 operands to specify the type of barrier, an
     // operand specifying if the barrier applies to device and uncached memory
     // and produces an output chain.
     MEMBARRIER,
 
+    // Val, OUTCHAIN = ATOMIC_LCS(INCHAIN, ptr, cmp, swap)
+    // this corresponds to the atomic.lcs intrinsic.
+    // cmp is compared to *ptr, and if equal, swap is stored in *ptr.
+    // the return is always the original value in *ptr
+    ATOMIC_LCS,
+
+    // Val, OUTCHAIN = ATOMIC_LAS(INCHAIN, ptr, amt)
+    // this corresponds to the atomic.las intrinsic.
+    // *ptr + amt is stored to *ptr atomically.
+    // the return is always the original value in *ptr
+    ATOMIC_LAS,
+
+    // Val, OUTCHAIN = ATOMIC_SWAP(INCHAIN, ptr, amt)
+    // this corresponds to the atomic.swap intrinsic.
+    // amt is stored to *ptr atomically.
+    // the return is always the original value in *ptr
+    ATOMIC_SWAP,
+
     // BUILTIN_OP_END - This must be the last enum value in this list.
     BUILTIN_OP_END
   };
     // BUILTIN_OP_END - This must be the last enum value in this list.
     BUILTIN_OP_END
   };
@@ -1170,6 +1188,33 @@ public:
   SDOperand getValue() const { return Op; }
 };
 
   SDOperand getValue() const { return Op; }
 };
 
+class AtomicSDNode : public SDNode {
+  virtual void ANCHOR();  // Out-of-line virtual method to give class a home.
+  SDOperand Ops[4];
+  MVT::ValueType OrigVT;
+public:
+  AtomicSDNode(unsigned Opc, SDVTList VTL, SDOperand Chain, SDOperand X, 
+               SDOperand Y, SDOperand Z, MVT::ValueType VT)
+    : SDNode(Opc, VTL) {
+    Ops[0] = Chain;
+    Ops[1] = X;
+    Ops[2] = Y;
+    Ops[3] = Z;
+    InitOperands(Ops, 4);
+    OrigVT=VT;
+  }
+  AtomicSDNode(unsigned Opc, SDVTList VTL, SDOperand Chain, SDOperand X, 
+               SDOperand Y, MVT::ValueType VT)
+    : SDNode(Opc, VTL) {
+    Ops[0] = Chain;
+    Ops[1] = X;
+    Ops[2] = Y;
+    InitOperands(Ops, 3);
+    OrigVT=VT;
+  }
+  MVT::ValueType getVT() const { return OrigVT; }
+};
+
 class StringSDNode : public SDNode {
   std::string Value;
   virtual void ANCHOR();  // Out-of-line virtual method to give class a home.
 class StringSDNode : public SDNode {
   std::string Value;
   virtual void ANCHOR();  // Out-of-line virtual method to give class a home.
index 64b3abf52bfeaddff740222b01fdbd8c5b5d32fe..c29bd407fdcd542789390065e4fb4fbc4aea97e1 100644 (file)
@@ -64,7 +64,7 @@ class LLVMPointerType<LLVMType elty>
 class LLVMMatchType<int num>
   : LLVMType<OtherVT>{
   int Number = num;
 class LLVMMatchType<int num>
   : LLVMType<OtherVT>{
   int Number = num;
-} 
+}
 
 def llvm_void_ty       : LLVMType<isVoid>;
 def llvm_anyint_ty     : LLVMType<iAny>;
 
 def llvm_void_ty       : LLVMType<isVoid>;
 def llvm_anyint_ty     : LLVMType<iAny>;
@@ -267,6 +267,17 @@ def int_init_trampoline : Intrinsic<[llvm_ptr_ty, llvm_ptr_ty, llvm_ptr_ty,
 def int_memory_barrier : Intrinsic<[llvm_void_ty, llvm_i1_ty, llvm_i1_ty, 
                                        llvm_i1_ty, llvm_i1_ty, llvm_i1_ty], []>;
 
 def int_memory_barrier : Intrinsic<[llvm_void_ty, llvm_i1_ty, llvm_i1_ty, 
                                        llvm_i1_ty, llvm_i1_ty, llvm_i1_ty], []>;
 
+def int_atomic_lcs : Intrinsic<[llvm_anyint_ty, LLVMPointerType<LLVMMatchType<0>>,
+                                 LLVMMatchType<0>, LLVMMatchType<0>],
+                               [IntrWriteArgMem]>, GCCBuiltin<"__sync_val_compare_and_swap">;
+def int_atomic_las : Intrinsic<[llvm_anyint_ty, LLVMPointerType<LLVMMatchType<0>>,
+                                 LLVMMatchType<0>],
+                               [IntrWriteArgMem]>, GCCBuiltin<"__sync_fetch_and_add">;
+def int_atomic_swap : Intrinsic<[llvm_anyint_ty, LLVMPointerType<LLVMMatchType<0>>,
+                                 LLVMMatchType<0>],
+                               [IntrWriteArgMem]>, GCCBuiltin<"__sync_lock_test_and_set">;
+
+
 //===-------------------------- Other Intrinsics --------------------------===//
 //
 def int_flt_rounds : Intrinsic<[llvm_i32_ty]>,
 //===-------------------------- Other Intrinsics --------------------------===//
 //
 def int_flt_rounds : Intrinsic<[llvm_i32_ty]>,
index 0d03cdad1dc037d1287020056b73528dfabd88d8..4515b90b2baa18dda04d9422eb9913f5087829ab 100644 (file)
@@ -1252,7 +1252,7 @@ private:
   /// TargetDAGCombineArray - Targets can specify ISD nodes that they would
   /// like PerformDAGCombine callbacks for by calling setTargetDAGCombine(),
   /// which sets a bit in this array.
   /// TargetDAGCombineArray - Targets can specify ISD nodes that they would
   /// like PerformDAGCombine callbacks for by calling setTargetDAGCombine(),
   /// which sets a bit in this array.
-  unsigned char TargetDAGCombineArray[156/(sizeof(unsigned char)*8)];
+  unsigned char TargetDAGCombineArray[160/(sizeof(unsigned char)*8)];
   
   /// PromoteToType - For operations that must be promoted to a specific type,
   /// this holds the destination type.  This map should be sparse, so don't hold
   
   /// PromoteToType - For operations that must be promoted to a specific type,
   /// this holds the destination type.  This map should be sparse, so don't hold
index 429855db163cc2c6b91f8edf38c9ab2a3de0e437..91e52a6c9edcca7fb636a0bde7f657c3d8b086e7 100644 (file)
@@ -1153,6 +1153,31 @@ SDOperand SelectionDAGLegalize::LegalizeOp(SDOperand Op) {
     break;
   }
 
     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 =
   case ISD::Constant: {
     ConstantSDNode *CN = cast<ConstantSDNode>(Node);
     unsigned opAction =
@@ -4228,6 +4253,27 @@ SDOperand SelectionDAGLegalize::PromoteOp(SDOperand Op) {
     break;
   }
     
     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:
   case ISD::AND:
   case ISD::OR:
   case ISD::XOR:
index 28f612d8cd1e3c30beec4f75c31754b96a507e40..803a38cbe1356ebfb3062d9fbbb7c9098986db9e 100644 (file)
@@ -2427,6 +2427,43 @@ SDOperand SelectionDAG::getMemset(SDOperand Chain, SDOperand Dest,
   return getNode(ISD::MEMSET, MVT::Other, Ops, 6);
 }
 
   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,
 SDOperand SelectionDAG::getLoad(MVT::ValueType VT,
                                 SDOperand Chain, SDOperand Ptr,
                                 const Value *SV, int SVOffset,
@@ -3593,6 +3630,7 @@ void CondCodeSDNode::ANCHOR() {}
 void VTSDNode::ANCHOR() {}
 void LoadSDNode::ANCHOR() {}
 void StoreSDNode::ANCHOR() {}
 void VTSDNode::ANCHOR() {}
 void LoadSDNode::ANCHOR() {}
 void StoreSDNode::ANCHOR() {}
+void AtomicSDNode::ANCHOR() {}
 
 HandleSDNode::~HandleSDNode() {
   SDVTList VTs = { 0, 0 };
 
 HandleSDNode::~HandleSDNode() {
   SDVTList VTs = { 0, 0 };
@@ -3821,6 +3859,9 @@ std::string SDNode::getOperationName(const SelectionDAG *G) const {
     }
    
   case ISD::MEMBARRIER:    return "MemBarrier";
     }
    
   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";
   case ISD::PCMARKER:      return "PCMarker";
   case ISD::READCYCLECOUNTER: return "ReadCycleCounter";
   case ISD::SRCVALUE:      return "SrcValue";
index d4e33b0d1036c6a09d8aa4780aadcaf2380742df..def4f9a01820c02059a586aeb40e07e335324240 100644 (file)
@@ -221,7 +221,7 @@ static bool isSelector(Instruction *I) {
 
 /// isUsedOutsideOfDefiningBlock - Return true if this instruction is used by
 /// PHI nodes or outside of the basic block that defines it, or used by a 
 
 /// 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();
 static bool isUsedOutsideOfDefiningBlock(Instruction *I) {
   if (isa<PHINode>(I)) return true;
   BasicBlock *BB = I->getParent();
@@ -3059,6 +3059,38 @@ SelectionDAGLowering::visitIntrinsicCall(CallInst &I, unsigned Intrinsic) {
     DAG.setRoot(DAG.getNode(ISD::MEMBARRIER, MVT::Other, &Ops[0], 6));
     return 0;
   }
     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;
+  }
+
   }
 }
 
   }
 }
 
index 028f8851038b266381b7d587c38169353e165aa6..907415d73c3d29c95a61ce54a5d35bd8b594f34d 100644 (file)
@@ -629,3 +629,96 @@ getRegClassForInlineAsmConstraint(const std::string &Constraint,
   
   return std::vector<unsigned>();
 }
   
   return std::vector<unsigned>();
 }
+//===----------------------------------------------------------------------===//
+//  Other Lowering Code
+//===----------------------------------------------------------------------===//
+
+MachineBasicBlock *
+AlphaTargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI,
+                                                 MachineBasicBlock *BB) {
+  const TargetInstrInfo *TII = getTargetMachine().getInstrInfo();
+  assert((MI->getOpcode() == Alpha::CAS32 ||
+          MI->getOpcode() == Alpha::CAS64 ||
+          MI->getOpcode() == Alpha::LAS32 ||
+          MI->getOpcode() == Alpha::LAS64 ||
+          MI->getOpcode() == Alpha::SWAP32 ||
+          MI->getOpcode() == Alpha::SWAP64) &&
+         "Unexpected instr type to insert");
+
+  bool is32 = MI->getOpcode() == Alpha::CAS32 || 
+    MI->getOpcode() == Alpha::LAS32 ||
+    MI->getOpcode() == Alpha::SWAP32;
+  
+  //Load locked store conditional for atomic ops take on the same form
+  //start:
+  //ll
+  //do stuff (maybe branch to exit)
+  //sc
+  //test sc and maybe branck to start
+  //exit:
+  const BasicBlock *LLVM_BB = BB->getBasicBlock();
+  ilist<MachineBasicBlock>::iterator It = BB;
+  ++It;
+  
+  MachineBasicBlock *thisMBB = BB;
+  MachineBasicBlock *llscMBB = new MachineBasicBlock(LLVM_BB);
+  MachineBasicBlock *sinkMBB = new MachineBasicBlock(LLVM_BB);
+
+  for(MachineBasicBlock::succ_iterator i = thisMBB->succ_begin(), 
+        e = thisMBB->succ_end(); i != e; ++i)
+    sinkMBB->addSuccessor(*i);
+  while(!thisMBB->succ_empty())
+    thisMBB->removeSuccessor(thisMBB->succ_begin());
+
+  MachineFunction *F = BB->getParent();
+  F->getBasicBlockList().insert(It, llscMBB);
+  F->getBasicBlockList().insert(It, sinkMBB);
+
+  BuildMI(thisMBB, TII->get(Alpha::BR)).addMBB(llscMBB);
+  
+  unsigned reg_res = MI->getOperand(0).getReg(),
+    reg_ptr = MI->getOperand(1).getReg(),
+    reg_v2 = MI->getOperand(2).getReg(),
+    reg_store = F->getRegInfo().createVirtualRegister(&Alpha::GPRCRegClass);
+
+  BuildMI(llscMBB, TII->get(is32 ? Alpha::LDL_L : Alpha::LDQ_L), 
+          reg_res).addImm(0).addReg(reg_ptr);
+  switch (MI->getOpcode()) {
+  case Alpha::CAS32:
+  case Alpha::CAS64: {
+    unsigned reg_cmp 
+      = F->getRegInfo().createVirtualRegister(&Alpha::GPRCRegClass);
+    BuildMI(llscMBB, TII->get(Alpha::CMPEQ), reg_cmp)
+      .addReg(reg_v2).addReg(reg_res);
+    BuildMI(llscMBB, TII->get(Alpha::BEQ))
+      .addImm(0).addReg(reg_cmp).addMBB(sinkMBB);
+    BuildMI(llscMBB, TII->get(Alpha::BISr), reg_store)
+      .addReg(Alpha::R31).addReg(MI->getOperand(3).getReg());
+    break;
+  }
+  case Alpha::LAS32:
+  case Alpha::LAS64: {
+    BuildMI(llscMBB, TII->get(is32 ? Alpha::ADDLr : Alpha::ADDQr), reg_store)
+      .addReg(reg_res).addReg(reg_v2);
+    break;
+  }
+  case Alpha::SWAP32:
+  case Alpha::SWAP64: {
+    BuildMI(llscMBB, TII->get(Alpha::BISr), reg_store)
+      .addReg(reg_v2).addReg(reg_v2);
+    break;
+  }
+  }
+  BuildMI(llscMBB, TII->get(is32 ? Alpha::STL_C : Alpha::STQ_C), reg_store)
+    .addReg(reg_store).addImm(0).addReg(reg_ptr);
+  BuildMI(llscMBB, TII->get(Alpha::BEQ))
+    .addImm(0).addReg(reg_store).addMBB(llscMBB);
+  BuildMI(llscMBB, TII->get(Alpha::BR)).addMBB(sinkMBB);
+
+  thisMBB->addSuccessor(llscMBB);
+  llscMBB->addSuccessor(llscMBB);
+  llscMBB->addSuccessor(sinkMBB);
+  delete MI;   // The pseudo instruction is gone now.
+
+  return sinkMBB;
+}
index a118d99462f73239e587a2f28a72e14e62e67f05..41a4b54c5f9aa5b16e46f90d6beac47fc27eb9a5 100644 (file)
@@ -88,6 +88,9 @@ namespace llvm {
                                         MVT::ValueType VT) const;
 
     bool hasITOF() { return useITOF; }
                                         MVT::ValueType VT) const;
 
     bool hasITOF() { return useITOF; }
+
+    MachineBasicBlock *EmitInstrWithCustomInserter(MachineInstr *MI,
+                                                   MachineBasicBlock *BB);
   };
 }
 
   };
 }
 
index 6274a3ef72239ebe1fb5506c51c57a2e9ba4dea7..19a846054be34ac9f672f6f701deb920d6305ecc 100644 (file)
@@ -167,6 +167,23 @@ def MEMLABEL : PseudoInstAlpha<(outs), (ins s64imm:$i, s64imm:$j, s64imm:$k, s64
          "LSMARKER$$$i$$$j$$$k$$$m:", [], s_pseudo>;
 
 
          "LSMARKER$$$i$$$j$$$k$$$m:", [], s_pseudo>;
 
 
+let usesCustomDAGSchedInserter = 1 in {   // Expanded by the scheduler.
+def CAS32 : PseudoInstAlpha<(outs GPRC:$dst), (ins GPRC:$ptr, GPRC:$cmp, GPRC:$swp), "",
+        [(set GPRC:$dst, (atomic_lcs_32 GPRC:$ptr, GPRC:$cmp, GPRC:$swp))], s_pseudo>;
+def CAS64 : PseudoInstAlpha<(outs GPRC:$dst), (ins GPRC:$ptr, GPRC:$cmp, GPRC:$swp), "",
+        [(set GPRC:$dst, (atomic_lcs_64 GPRC:$ptr, GPRC:$cmp, GPRC:$swp))], s_pseudo>;
+
+def LAS32 : PseudoInstAlpha<(outs GPRC:$dst), (ins GPRC:$ptr, GPRC:$swp), "",
+        [(set GPRC:$dst, (atomic_las_32 GPRC:$ptr, GPRC:$swp))], s_pseudo>;
+def LAS64 :PseudoInstAlpha<(outs GPRC:$dst), (ins GPRC:$ptr, GPRC:$swp), "",
+        [(set GPRC:$dst, (atomic_las_64 GPRC:$ptr, GPRC:$swp))], s_pseudo>;
+
+def SWAP32 : PseudoInstAlpha<(outs GPRC:$dst), (ins GPRC:$ptr, GPRC:$swp), "",
+        [(set GPRC:$dst, (atomic_swap_32 GPRC:$ptr, GPRC:$swp))], s_pseudo>;
+def SWAP64 :PseudoInstAlpha<(outs GPRC:$dst), (ins GPRC:$ptr, GPRC:$swp), "",
+        [(set GPRC:$dst, (atomic_swap_64 GPRC:$ptr, GPRC:$swp))], s_pseudo>;
+}
+
 //***********************
 //Real instructions
 //***********************
 //***********************
 //Real instructions
 //***********************
@@ -568,6 +585,18 @@ def LDQl : MForm<0x29, 1, "ldq $RA,$DISP($RB)\t\t!literal",
 def : Pat<(Alpha_rellit texternalsym:$ext, GPRC:$RB),
           (LDQl texternalsym:$ext, GPRC:$RB)>;
 
 def : Pat<(Alpha_rellit texternalsym:$ext, GPRC:$RB),
           (LDQl texternalsym:$ext, GPRC:$RB)>;
 
+let OutOperandList = (outs GPRC:$RR),
+    InOperandList = (ins GPRC:$RA, s64imm:$DISP, GPRC:$RB),
+    Constraints = "$RA = $RR",
+    DisableEncoding = "$RR" in {
+def STQ_C : MForm<0x2F, 0, "stq_l $RA,$DISP($RB)", [], s_ist>;
+def STL_C : MForm<0x2E, 0, "stl_l $RA,$DISP($RB)", [], s_ist>;
+}
+let OutOperandList = (ops GPRC:$RA), InOperandList = (ops s64imm:$DISP, GPRC:$RB) in {
+def LDQ_L : MForm<0x2B, 1, "ldq_l $RA,$DISP($RB)", [], s_ild>;
+def LDL_L : MForm<0x2A, 1, "ldl_l $RA,$DISP($RB)", [], s_ild>;
+}
+
 def RPCC : MfcForm<0x18, 0xC000, "rpcc $RA", s_rpcc>; //Read process cycle counter
 def MB  : MfcPForm<0x18, 0x4000, "mb",  s_imisc>; //memory barrier
 def WMB : MfcPForm<0x18, 0x4400, "wmb", s_imisc>; //write memory barrier
 def RPCC : MfcForm<0x18, 0xC000, "rpcc $RA", s_rpcc>; //Read process cycle counter
 def MB  : MfcPForm<0x18, 0x4000, "mb",  s_imisc>; //memory barrier
 def WMB : MfcPForm<0x18, 0x4400, "wmb", s_imisc>; //write memory barrier
@@ -965,7 +994,6 @@ def : Pat<(brcond (setune F8RC:$RA, immFPZ), bb:$DISP),
 //S_floating : IEEE Single
 //T_floating : IEEE Double
 
 //S_floating : IEEE Single
 //T_floating : IEEE Double
 
-
 //Unused instructions
 //Mnemonic Format Opcode Description
 //CALL_PAL Pcd 00 Trap to PALcode
 //Unused instructions
 //Mnemonic Format Opcode Description
 //CALL_PAL Pcd 00 Trap to PALcode
@@ -973,12 +1001,8 @@ def : Pat<(brcond (setune F8RC:$RA, immFPZ), bb:$DISP),
 //EXCB Mfc 18.0400 Exception barrier
 //FETCH Mfc 18.8000 Prefetch data
 //FETCH_M Mfc 18.A000 Prefetch data, modify intent
 //EXCB Mfc 18.0400 Exception barrier
 //FETCH Mfc 18.8000 Prefetch data
 //FETCH_M Mfc 18.A000 Prefetch data, modify intent
-//LDL_L Mem 2A Load sign-extended longword locked
-//LDQ_L Mem 2B Load quadword locked
 //LDQ_U Mem 0B Load unaligned quadword
 //MB Mfc 18.4000 Memory barrier
 //LDQ_U Mem 0B Load unaligned quadword
 //MB Mfc 18.4000 Memory barrier
-//STL_C Mem 2E Store longword conditional
-//STQ_C Mem 2F Store quadword conditional
 //STQ_U Mem 0F Store unaligned quadword
 //TRAPB Mfc 18.0000 Trap barrier
 //WH64 Mfc 18.F800 Write hint \14 64 bytes
 //STQ_U Mem 0F Store unaligned quadword
 //TRAPB Mfc 18.0000 Trap barrier
 //WH64 Mfc 18.F800 Write hint \14 64 bytes
index eeed99429694f67b63d117e35bdcb53af43231bb..47d9ba48b7b66f51e4bd7cd557262b626fc986d1 100644 (file)
@@ -189,6 +189,12 @@ def STDMemBarrier : SDTypeProfile<0, 5, [
   SDTCisSameAs<0,1>,  SDTCisSameAs<0,2>,  SDTCisSameAs<0,3>, SDTCisSameAs<0,4>,
   SDTCisInt<0>
 ]>;
   SDTCisSameAs<0,1>,  SDTCisSameAs<0,2>,  SDTCisSameAs<0,3>, SDTCisSameAs<0,4>,
   SDTCisInt<0>
 ]>;
+def STDAtomic3 : SDTypeProfile<1, 3, [
+  SDTCisSameAs<0,2>,  SDTCisSameAs<0,3>, SDTCisInt<0>, SDTCisPtrTy<1>
+]>;
+def STDAtomic2 : SDTypeProfile<1, 2, [
+  SDTCisSameAs<0,2>, SDTCisInt<0>, SDTCisPtrTy<1>
+]>;
 
 class SDCallSeqStart<list<SDTypeConstraint> constraints> :
         SDTypeProfile<0, 1, constraints>;
 
 class SDCallSeqStart<list<SDTypeConstraint> constraints> :
         SDTypeProfile<0, 1, constraints>;
@@ -336,6 +342,13 @@ def trap       : SDNode<"ISD::TRAP"       , SDTNone,
                         [SDNPHasChain, SDNPSideEffect]>;
 def membarrier : SDNode<"ISD::MEMBARRIER"       , STDMemBarrier,
                         [SDNPHasChain, SDNPSideEffect]>;
                         [SDNPHasChain, SDNPSideEffect]>;
 def membarrier : SDNode<"ISD::MEMBARRIER"       , STDMemBarrier,
                         [SDNPHasChain, SDNPSideEffect]>;
+// Do not use atomic_* directly, use atomic_*_size (see below)
+def atomic_lcs : SDNode<"ISD::ATOMIC_LCS", STDAtomic3,
+                        [SDNPHasChain, SDNPMayStore, SDNPMayLoad]>;
+def atomic_las : SDNode<"ISD::ATOMIC_LAS", STDAtomic2,
+                        [SDNPHasChain, SDNPMayStore, SDNPMayLoad]>;
+def atomic_swap : SDNode<"ISD::ATOMIC_SWAP", STDAtomic2,
+                        [SDNPHasChain, SDNPMayStore, SDNPMayLoad]>;
 
 // Do not use ld, st directly. Use load, extload, sextload, zextload, store,
 // and truncst (see below).
 
 // Do not use ld, st directly. Use load, extload, sextload, zextload, store,
 // and truncst (see below).
@@ -722,6 +735,84 @@ def post_truncstf32 : PatFrag<(ops node:$val, node:$base, node:$offset),
   return false;
 }]>;
 
   return false;
 }]>;
 
+//Atomic patterns
+def atomic_lcs_8 : PatFrag<(ops node:$ptr, node:$cmp, node:$swp),
+                    (atomic_lcs node:$ptr, node:$cmp, node:$swp), [{
+  if (AtomicSDNode* V = dyn_cast<AtomicSDNode>(N))
+        return V->getVT() == MVT::i8;
+  return false;
+}]>;
+def atomic_lcs_16 : PatFrag<(ops node:$ptr, node:$cmp, node:$swp), 
+                    (atomic_lcs node:$ptr, node:$cmp, node:$swp), [{
+  if (AtomicSDNode* V = dyn_cast<AtomicSDNode>(N))
+        return V->getVT() == MVT::i16;
+  return false;
+}]>;
+def atomic_lcs_32 : PatFrag<(ops node:$ptr, node:$cmp, node:$swp), 
+                    (atomic_lcs node:$ptr, node:$cmp, node:$swp), [{
+  if (AtomicSDNode* V = dyn_cast<AtomicSDNode>(N))
+        return V->getVT() == MVT::i32;
+  return false;
+}]>;
+def atomic_lcs_64 : PatFrag<(ops node:$ptr, node:$cmp, node:$swp), 
+                    (atomic_lcs node:$ptr, node:$cmp, node:$swp), [{
+  if (AtomicSDNode* V = dyn_cast<AtomicSDNode>(N))
+        return V->getVT() == MVT::i64;
+  return false;
+}]>;
+
+def atomic_las_8 : PatFrag<(ops node:$ptr, node:$inc),
+                    (atomic_las node:$ptr, node:$inc), [{
+  if (AtomicSDNode* V = dyn_cast<AtomicSDNode>(N))
+        return V->getVT() == MVT::i8;
+  return false;
+}]>;
+def atomic_las_16 : PatFrag<(ops node:$ptr, node:$inc), 
+                    (atomic_las node:$ptr, node:$inc), [{
+  if (AtomicSDNode* V = dyn_cast<AtomicSDNode>(N))
+        return V->getVT() == MVT::i16;
+  return false;
+}]>;
+def atomic_las_32 : PatFrag<(ops node:$ptr, node:$inc), 
+                    (atomic_las node:$ptr, node:$inc), [{
+  if (AtomicSDNode* V = dyn_cast<AtomicSDNode>(N))
+        return V->getVT() == MVT::i32;
+  return false;
+}]>;
+def atomic_las_64 : PatFrag<(ops node:$ptr, node:$inc), 
+                    (atomic_las node:$ptr, node:$inc), [{
+  if (AtomicSDNode* V = dyn_cast<AtomicSDNode>(N))
+        return V->getVT() == MVT::i64;
+  return false;
+}]>;
+
+def atomic_swap_8 : PatFrag<(ops node:$ptr, node:$inc),
+                    (atomic_swap node:$ptr, node:$inc), [{
+  if (AtomicSDNode* V = dyn_cast<AtomicSDNode>(N))
+        return V->getVT() == MVT::i8;
+  return false;
+}]>;
+def atomic_swap_16 : PatFrag<(ops node:$ptr, node:$inc), 
+                    (atomic_swap node:$ptr, node:$inc), [{
+  if (AtomicSDNode* V = dyn_cast<AtomicSDNode>(N))
+        return V->getVT() == MVT::i16;
+  return false;
+}]>;
+def atomic_swap_32 : PatFrag<(ops node:$ptr, node:$inc), 
+                    (atomic_swap node:$ptr, node:$inc), [{
+  if (AtomicSDNode* V = dyn_cast<AtomicSDNode>(N))
+        return V->getVT() == MVT::i32;
+  return false;
+}]>;
+def atomic_swap_64 : PatFrag<(ops node:$ptr, node:$inc), 
+                    (atomic_swap node:$ptr, node:$inc), [{
+  if (AtomicSDNode* V = dyn_cast<AtomicSDNode>(N))
+        return V->getVT() == MVT::i64;
+  return false;
+}]>;
+
+
+
 // setcc convenience fragments.
 def setoeq : PatFrag<(ops node:$lhs, node:$rhs),
                      (setcc node:$lhs, node:$rhs, SETOEQ)>;
 // setcc convenience fragments.
 def setoeq : PatFrag<(ops node:$lhs, node:$rhs),
                      (setcc node:$lhs, node:$rhs, SETOEQ)>;
index 0071c00262e27a4e2d29802b3fa26b72d2dbd998..98c588525086a6805a7745f4f7defd4d71bb2347 100644 (file)
@@ -2535,6 +2535,15 @@ def EH_RETURN   : I<0xC3, RawFrm, (outs), (ins GR32:$addr),
 
 }
 
 
 }
 
+//===----------------------------------------------------------------------===//
+// Atomic support
+//
+let Defs = [EAX] in
+def LCMPXCHGL : I<0, Pseudo, (outs GR32:$dst), 
+                  (ins GR32:$ptr, GR32:$cmp, GR32:$swap),
+                  "movl $cmp, %eax ; lock cmpxchgl $swap,($ptr) ; movl %eax, $dst",
+                  [(set GR32:$dst, (atomic_lcs_32 GR32:$ptr, GR32:$cmp, GR32:$swap))]>;
+
 //===----------------------------------------------------------------------===//
 // Non-Instruction Patterns
 //===----------------------------------------------------------------------===//
 //===----------------------------------------------------------------------===//
 // Non-Instruction Patterns
 //===----------------------------------------------------------------------===//
@@ -2683,7 +2692,6 @@ def : Pat<(store (or (shl (loadi16 addr:$dst), CL:$amt),
                      (srl GR16:$src2, (sub 16, CL:$amt))), addr:$dst),
           (SHLD16mrCL addr:$dst, GR16:$src2)>;
 
                      (srl GR16:$src2, (sub 16, CL:$amt))), addr:$dst),
           (SHLD16mrCL addr:$dst, GR16:$src2)>;
 
-
 //===----------------------------------------------------------------------===//
 // Floating Point Stack Support
 //===----------------------------------------------------------------------===//
 //===----------------------------------------------------------------------===//
 // Floating Point Stack Support
 //===----------------------------------------------------------------------===//