[llvm-commits] Patch for LangRef.html as part of Atomic Operations

Reid Spencer rspencer at reidspencer.com
Thu Jul 19 21:47:45 PDT 2007


Chandler,

Some feedback ..

On Thu, 2007-07-19 at 16:55 -0700, Chandler Carruth wrote:
> Hello,
> 
> This is a patch for review of proposed changes to 'docs/LangRef.html'.
> This would provide a preview of the Atomic intrinsic functions on
> their way into the IR. Comments are more than welcome, especially on
> the typos that I am sure wormed their way in while converting to more
> closely match the syntax of overloaded intrinsics.
> 
> -Chandler Carruth

> Index: docs/LangRef.html
> ===================================================================
> --- docs/LangRef.html   (revision 40071)
> +++ docs/LangRef.html   (working copy)
> @@ -191,6 +191,15 @@
>        </li>
>        <li><a href="#int_debugger">Debugger intrinsics</a></li>
>        <li><a href="#int_eh">Exception Handling intrinsics</a></li>
> +      <li><a href="#atomic_ops">Atomic Operations and Synchronization
> Intrinsics</a>
> +        <ol>
> +          <li><a href="#atomic_cas">'<tt>llvm.atomic.cas.*</tt>'
> Intrinsic</a></li>
> +          <li><a href="#atomic_swap">'<tt>llvm.atomic.swap.*</tt>'
> Intrinsic</a></li>
> +          <li><a href="#atomic_las">'<tt>llvm.atomic.las.*</tt>'
> Intrinsic</a></li>
> +          <li><a href="#atomic_lss">'<tt>llvm.atomic.lss.*</tt>'
> Intrinsic</a></li>
> +          <li><a
> href="#atomic_membarrier">'<tt>llvm.atomic.membarrier</tt>'
> Intrinsic</a></li>
> +        </ol>
> +      </li>
>        <li><a href="#int_general">General intrinsics</a></li>
>          <ol>
>            <li><a
> href="#int_var_annotation">'<tt>llvm.var.annotation</tt>' 
> @@ -4822,6 +4831,292 @@
>  
>  <!--
> ======================================================================= -->
>  <div class="doc_subsection">
> +  <a name="atomic_ops">Atomic Operations and Synchronization
> Intrinsics</a>
> +</div>
> +
> +<div class="doc_text">
> +<p>
> +  LLVM provides intrinsics for atomic operations as well as memory 
> +  synchronization on supporting hardware. All of these start with
> the 
> +  '<tt>llvm.atomic.</tt>' 

drop the ' as the type face highlights sufficiently.

And elsewhere in this patch.

> prefix to distinguish them. These allow threading 
> +  libraries to represent their atomic operations and synchronization 
> +  constructs natively in LLVM, without dropping to inline assembly.

consider "resorting to" instead of "dropping to"

> +</p>
> +</div>

I think you need to provide a little more context in this preamble.
Specifically, you need to state the purpose for these intrinsics is to
make construction of libraries that need atomic operations and memory
barriers easier. The purpose is not to model in a generic fashion all
possible permutations of hardware support for these types of things. If
someone needs that, they can always resort to inline assembly.

> +
> +<!--
> _______________________________________________________________________ -->
> +<div class="doc_subsubsection">
> +  <a name="atomic_cas">'<tt>llvm.atomic.cas.*</tt>' Intrinsic</a>
> +</div>
> +<div class="doc_text">
> +<h5>Syntax:</h5>
> +<p>
> +<pre>
> +declare i8 @llvm.atomic.cas.i8( i8* <ptr>, i8 <cmp>, i8
> <swap> )
> +declare i16 @llvm.atomic.cas.i16( i16* <ptr>, i16 <cmp>,
> i16 <swap> )
> +declare i32 @llvm.atomic.cas.i32( i32* <ptr>, i32 <cmp>,
> i32 <swap> )
> +declare i64 @llvm.atomic.cas.i64( i64* <ptr>, i64 <cmp>,
> i64 <swap> )

I thought we had decided to make the overloaded on any bit width? The
various targets would then determine what they can support or promote up
to a supported size. If so, please document these like the other
overloaded ones, by stating:

This is an overloaded intrinsic. You can use llvm.atomic.cas on any
integer bit width.

at the beginning of the Syntax section.

> +</pre>
> +</p>
> +<h5>Overview:</h5>
> +<p>
> +  This compares a value in shared memory to a given value. If they
> are 
> +  equal, the value in the shared memory is swapped with some value.

some -> another

> +</p>
> +<h5>Arguments:</h5>
> +<p>
> +  The '<tt>llvm.atomic.cas</tt>' intrinsic takes three arguments. The
> result as 
> +  well as both '<tt>cmp</tt>' and '<tt>swap</tt>' must be integer
> values with 
> +  the same bit width.  The '<tt>ptr</tt>' argument must be a pointer
> to 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
> compares the value 
> +  in shared memory pointed to by '<tt>ptr</tt>' with the value
> '<tt>cmp</tt>'. 
> +  If they are equal, the value in memory is replaced with the value
> of 
> +  '<tt>swap</tt>', else the value in memory remains the same.  The
> value 
> +  originally stored in memory is yielded in either case.
> +</p>
> +<p>
> +  This operation does not perform a true swap due to the semantics of
> SSA.  
> +  Rather, it yields the value that would be swapped into
> '<tt>swap</tt>'.  
> +  It yields this value in all cases, even when the change to memory
> was not 
> +  performed, allowing a quick check against '<tt>cmp</tt>' to
> determine 
> +  success or failure of the swap, and immediately have the actual
> memory 
> +  value available.
> +</p>

I find this whole paragraph confusing. I think the problem is that we're
trying to specify a "compare-and-swap" intrinsics that really isn't
doing a swap. That is, the contents of of a register and a memory
location are not swapped by this intrinsic.  Instead, what we're
implementing here is "compare-and-maybe-store-but-always-fetch" :) So,
perhaps we just need to rename this intrinsic to something that
identifies its operation and then we don't have to talk about swapping
any more but just document the semantics in a straight forward manner.

I should have noted this earlier .. sorry. I think we lost track of this
when the conversion from instructions to intrinsics happened. The
intrinsics don't need short names like "cas"


> +<h5>Examples:</h5>
> +<pre>
> +%ptr      = malloc i32
> +        store i32 4, %ptr
> +
> +%val1     = add i32 4, 4
> +%result1  = call i32 @llvm.atomic.cas( i32* %ptr, i32 4, %val1 )
> +                                      <i>; yields {i32}:result1 =
> 4</i>
> +%swapped1 = icmp eq i32 %result1, 4       <i>; yields {i1}:swapped1 =
> true</i>
> +%memval1  = load i32* %ptr                <i>; yields {i32}:memval1 =
> 8</i>
> +
> +%val2     = add i32 1, 1
> +%result2  = call i32 @llvm.atomic.cas( i32* %ptr, i32 5, %val2 )
> +                                      <i>; yields {i32}:result2 =
> 8</i>
> +%swapped2 = icmp eq i32 %result2, 5       <i>; yields {i1}:swapped2 =
> false</i>
> +%memval2  = load i32* %ptr                <i>; yields {i32}:memval2 =
> 8</i>
> +</pre>
> +</div>
> +
> +<!--
> _______________________________________________________________________ -->
> +<div class="doc_subsubsection">
> +  <a name="atomic_swap">'<tt>llvm.atomic.swap.*</tt>' Intrinsic</a>
> +</div>
> +<div class="doc_text">
> +<h5>Syntax:</h5>
> +<p>
> +<pre>
> +declare i8 @llvm.atomic.swap.i8( i8* <ptr>, i8 <swap> )
> +declare i16 @llvm.atomic.swap.i16( i16* <ptr>, i16
> <swap> )
> +declare i32 @llvm.atomic.swap.i32( i32* <ptr>, i32
> <swap> )
> +declare i64 @llvm.atomic.swap.i64( i64* <ptr>, i64
> <swap> )
> +</pre>
> +</p>
> +<h5>Overview:</h5>
> +<p>
> +  This intrinsic swaps the value stored in shared memory at
> '<tt>ptr</tt>' 
> +  with '<tt>swap</tt>' and yields the value from memory.
> +</p>
> +<h5>Arguments:</h5>
> +<p>
> +  The '<tt>llvm.atomic.swap</tt>' intrinsic takes two arguments. Both
> the 
> +  '<tt>swap</tt>' argument and the result must be integers of the
> same bit 
> +  width.  The first argument, '<tt>ptr</tt>', must be a pointer to
> 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>', and
> stores 
> +  '<tt>swap</tt>' back into it atomically. Due to SSA rules, the
> value from 
> +  memory is yielded rather than stored in '<tt>swap</tt>'.

Again, this isn't really a swap so perhaps we should consider naming it
something that is more indicative of its "store-and-fetch" semantics.
If we named this correctly and then didn't try to dance around the fact
that a swap isn't actually happening, this will read much better.

I wouldn't be opposed to llvm.atomic.load.store

> +</p>
> +<h5>Examples:</h5>
> +<pre>
> +%ptr      = malloc i32
> +        store i32 4, %ptr
> +
> +%val1     = add i32 4, 4
> +%result1  = call i32 @llvm.atomic.swap( i32* %ptr, i32 %val1 )
> +                                    <i>; yields {i32}:result1 = 4</i>
> +%swapped1 = icmp eq i32 %result1, 4     <i>; yields {i1}:swapped1 =
> true</i>
> +%memval1  = load i32* %ptr              <i>; yields {i32}:memval1 =
> 8</i>
> +
> +%val2     = add i32 1, 1
> +%result2  = call i32 @llvm.atomic.swap( i32* %ptr, i32 %val2 )
> +                                    <i>; yields {i32}:result2 = 8</i>
> +%swapped2 = icmp eq i32 %result2, 8     <i>; yields {i1}:swapped2 =
> true</i>
> +%memval2  = load i32* %ptr              <i>; yields {i32}:memval2 =
> 2</i>
> +</pre>
> + </div>
> +
> +<!--
> _______________________________________________________________________ -->
> +<div class="doc_subsubsection">
> +  <a name="atomic_las">'<tt>llvm.atomic.las.*</tt>' Intrinsic</a>

Consider naming this llvm.atomic.load.add.store ?

> +</div>
> +<div class="doc_text">
> +<h5>Syntax:</h5>
> +<p>
> +<pre>
> +declare i8 @llvm.atomic.las.i8( i8* <ptr>, i8 <delta> )
> +declare i16 @llvm.atomic.las.i16( i16* <ptr>, i16
> <delta> )
> +declare i32 @llvm.atomic.las.i32( i32* <ptr>, i32
> <delta> )
> +declare i64 @llvm.atomic.las.i64( i64* <ptr>, i64
> <delta> )
> +</pre>
> +</p>
> +<h5>Overview:</h5>
> +<p>
> +  This intrinsic adds '<tt>delta</tt>' to the value stored in shared
> 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 type 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* %ptr, i32 4 )
> +                                <i>; yields {i32}:result1 = 4</i>
> +%result2  = call i32 @llvm.atomic.las( i32* %ptr, i32 2 )
> +                                <i>; yields {i32}:result2 = 8</i>
> +%result3  = call i32 @llvm.atomic.las( i32* %ptr, i32 5 )
> +                                <i>; yields {i32}:result3 = 10</i>
> +%memval   = load i32* %ptr          <i>; yields {i32}:memval1 =
> 15</i>
> +%swapped  = icmp eq i32 %memval, 15 <i>; yields {i1}:swapped  =
> true</i>
> +</pre>
> +</div>
> +
> +<!--
> _______________________________________________________________________ -->
> +<div class="doc_subsubsection">
> +  <a name="atomic_lss">'<tt>llvm.atomic.lss.*</tt>' Intrinsic</a>

Consider naming this llvm.atomic.load.sub.store ?

> +</div>
> +<div class="doc_text">
> +<h5>Syntax:</h5>
> +<p>
> +<pre>
> +declare i8 @llvm.atomic.lss.i8( i8* <ptr>, i8 <delta> )
> +declare i16 @llvm.atomic.lss.i16( i16* <ptr>, i16
> <delta> )
> +declare i32 @llvm.atomic.lss.i32( i32* <ptr>, i32
> <delta> )
> +declare i64 @llvm.atomic.lss.i64( i64* <ptr>, i64
> <delta> )
> +</pre>
> +</p>
> +<h5>Overview:</h5>
> +<p>
> +  This intrinsic subtracts '<tt>delta</tt>' from the value stored in
> shared 
> +  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 type 

pointer to integer value .. you can't point to an integer type :)

> 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 subtracts
> '<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 32, %ptr
> +%result1  = call i32 @llvm.atomic.lss( i32* %ptr, i32 4 )
> +                                <i>; yields {i32}:result1 = 32</i>
> +%result2  = call i32 @llvm.atomic.lss( i32* %ptr, i32 2 )
> +                                <i>; yields {i32}:result2 = 28</i>
> +%result3  = call i32 @llvm.atomic.lss( i32* %ptr, i32 5 )
> +                                <i>; yields {i32}:result3 = 26</i>
> +%memval   = load i32* %ptr          <i>; yields {i32}:memval1 =
> 21</i>
> +%swapped  = icmp eq i32 %memval, 21 <i>; yields {i1}:swapped  =
> true</i>
> +</pre>
> + </div>
> +
> +<!--
> _______________________________________________________________________ -->
> +<div class="doc_subsubsection">
> +  <a name="atomic_membarrier">'<tt>llvm.atomic.membarrier</tt>'
> Intrinsic</a>

Consider naming this llvm.atomic.memory.barrier ?

> +</div>
> +<div class="doc_text">
> +<h5>Syntax:</h5>
> +<p>
> +<pre>
> +declare void @llvm.atomic.membarrier( i1 <ll>, i1 <ls>,
> i1 <sl>, i1 <ss> )
> +</pre>
> +</p>
> +<h5>Overview:</h5>
> +<p>
> +  The '<tt>llvm.atomic.membarrier</tt>' intrinsic guarantees ordering
> between 
> +  specific pairs of memory access types.
> +</p>
> +<h5>Arguments:</h5>
> +<p>
> +  The '<tt>llvm.atomic.membarrier</tt>' intrinsic requires four
> boolean 
> +  arguments. Each argument enables a specific barrier as listed
> below.
> +  <ul>
> +    <li><tt>ll</tt>: load-load barrier</li>
> +    <li><tt>ls</tt>: load-store barrier</li>
> +    <li><tt>sl</tt>: store-load barrier</li>
> +    <li><tt>ss</tt>: store-store barrier</li>
> +  </ul>
> +</p>
> +<h5>Semantics:</h5>
> +<p>
> +  This intrinsic causes the system to enforce some ordering
> constraints 
> +  upon the loads and stores of the program. This barrier does not
> indicate 
> +  <em>when</em> any events will occur, it only enforces an
> <em>order</em> 
> +  in which they occur. For any of the specified pairs of load and
> store 
> +  operations (f.ex.  load-load, or store-load), all of the first
> operations 
> +  preceding the barrier will complete before any of the second
> operations 
> +  succeeding the barrier begin. Specifically the semantics for each
> pairing 
> +  is as follows:
> +  <ul>
> +    <li><tt>ll</tt>: All loads before the barrier must complete
> before any 
> +    load after the barrier begins.</li>
> +    <li><tt>ls</tt>: All loads before the barrier must complete
> before any 
> +    store after the barrier begins.</li>
> +    <li><tt>ss</tt>: All stores before the barrier must complete
> before any 
> +    store after the barrier begins.</li>
> +    <li><tt>sl</tt>: All stores before the barrier must complete
> before any 
> +    load after the barrier begins.</li>
> +  </ul>
> +  These semantics are applied with a logical "and" behavior when more
> than  
> +  one is enabled in a single memory barrier intrinsic.
> +</p>
> +<h5>Example:</h5>
> +<pre>
> +%ptr      = malloc i32
> +        store i32 4, %ptr
> +
> +%result1  = load i32* %ptr      <i>; yields {i32}:result1 = 4</i>
> +        call void @llvm.atomic.membarrier( i1 false, i1 true, i1
> false, i1 false )
> +                            <i>; guarantee the above finishes</i>
> +        store i32 8, %ptr   <i>; before this begins</i>
> +</pre>
> +</div>
> +
> +<!--
> ======================================================================= -->
> +<div class="doc_subsection">
>    <a name="int_general">General Intrinsics</a>
>  </div>

Nice job. Please make the corrections above and then commit this. It is
*much* easier to review online in HTML format. 

Thanks,

Reid.

>  
> 




More information about the llvm-commits mailing list