Skip to content

Commit 59b6688

Browse files
committed
Representation of 'atomic load' and 'atomic store' in IR.
llvm-svn: 137170
1 parent e95fcf7 commit 59b6688

File tree

12 files changed

+388
-76
lines changed

12 files changed

+388
-76
lines changed

llvm/docs/Atomics.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
<html>
44
<head>
55
<title>LLVM Atomic Instructions and Concurrency Guide</title>
6+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
67
<link rel="stylesheet" href="llvm.css" type="text/css">
78
</head>
89
<body>

llvm/docs/LangRef.html

Lines changed: 34 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1583,20 +1583,18 @@ <h3>
15831583
<div class="doc_text">
15841584

15851585
<p>Atomic instructions (<a href="#i_cmpxchg"><code>cmpxchg</code></a>,
1586-
<a href="#i_atomicrmw"><code>atomicrmw</code></a>, and
1587-
<a href="#i_fence"><code>fence</code></a>) take an ordering parameter
1586+
<a href="#i_atomicrmw"><code>atomicrmw</code></a>,
1587+
<a href="#i_fence"><code>fence</code></a>,
1588+
<a href="#i_load"><code>atomic load</code></a>, and
1589+
<a href="#i_load"><code>atomic store</code></a>) take an ordering parameter
15881590
that determines which other atomic instructions on the same address they
15891591
<i>synchronize with</i>. These semantics are borrowed from Java and C++0x,
15901592
but are somewhat more colloquial. If these descriptions aren't precise enough,
15911593
check those specs. <a href="#i_fence"><code>fence</code></a> instructions
15921594
treat these orderings somewhat differently since they don't take an address.
15931595
See that instruction's documentation for details.</p>
15941596

1595-
<!-- FIXME Note atomic load+store here once those get added. -->
1596-
15971597
<dl>
1598-
<!-- FIXME: unordered is intended to be used for atomic load and store;
1599-
it isn't allowed for any instruction yet. -->
16001598
<dt><code>unordered</code></dt>
16011599
<dd>The set of values that can be read is governed by the happens-before
16021600
partial order. A value cannot be read unless some operation wrote it.
@@ -4572,8 +4570,8 @@ <h4>
45724570

45734571
<h5>Syntax:</h5>
45744572
<pre>
4575-
&lt;result&gt; = load &lt;ty&gt;* &lt;pointer&gt;[, align &lt;alignment&gt;][, !nontemporal !&lt;index&gt;]
4576-
&lt;result&gt; = volatile load &lt;ty&gt;* &lt;pointer&gt;[, align &lt;alignment&gt;][, !nontemporal !&lt;index&gt;]
4573+
&lt;result&gt; = [volatile] load &lt;ty&gt;* &lt;pointer&gt;[, align &lt;alignment&gt;][, !nontemporal !&lt;index&gt;]
4574+
&lt;result&gt; = atomic [volatile] load &lt;ty&gt;* &lt;pointer&gt; [singlethread] &lt;ordering&gt;, align &lt;alignment&gt;
45774575
!&lt;index&gt; = !{ i32 1 }
45784576
</pre>
45794577

@@ -4588,6 +4586,19 @@ <h5>Arguments:</h5>
45884586
number or order of execution of this <tt>load</tt> with other <a
45894587
href="#volatile">volatile operations</a>.</p>
45904588

4589+
<p>If the <code>load</code> is marked as <code>atomic</code>, it takes an extra
4590+
<a href="#ordering">ordering</a> and optional <code>singlethread</code>
4591+
argument. The <code>release</code> and <code>acq_rel</code> orderings are
4592+
not valid on <code>load</code> instructions. Atomic loads produce <a
4593+
href="#memorymodel">defined</a> results when they may see multiple atomic
4594+
stores. The type of the pointee must be an integer type whose bit width
4595+
is a power of two greater than or equal to eight and less than or equal
4596+
to a target-specific size limit. <code>align</code> must be explicitly
4597+
specified on atomic loads, and the load has undefined behavior if the
4598+
alignment is not set to a value which is at least the size in bytes of
4599+
the pointee. <code>!nontemporal</code> does not have any defined semantics
4600+
for atomic loads.</p>
4601+
45914602
<p>The optional constant <tt>align</tt> argument specifies the alignment of the
45924603
operation (that is, the alignment of the memory address). A value of 0 or an
45934604
omitted <tt>align</tt> argument means that the operation has the preferential
@@ -4631,8 +4642,8 @@ <h4>
46314642

46324643
<h5>Syntax:</h5>
46334644
<pre>
4634-
store &lt;ty&gt; &lt;value&gt;, &lt;ty&gt;* &lt;pointer&gt;[, align &lt;alignment&gt;][, !nontemporal !&lt;index&gt;] <i>; yields {void}</i>
4635-
volatile store &lt;ty&gt; &lt;value&gt;, &lt;ty&gt;* &lt;pointer&gt;[, align &lt;alignment&gt;][, !nontemporal !&lt;index&gt;] <i>; yields {void}</i>
4645+
[volatile] store &lt;ty&gt; &lt;value&gt;, &lt;ty&gt;* &lt;pointer&gt;[, align &lt;alignment&gt;][, !nontemporal !&lt;index&gt;] <i>; yields {void}</i>
4646+
atomic [volatile] store &lt;ty&gt; &lt;value&gt;, &lt;ty&gt;* &lt;pointer&gt; [singlethread] &lt;ordering&gt;, align &lt;alignment&gt; <i>; yields {void}</i>
46364647
</pre>
46374648

46384649
<h5>Overview:</h5>
@@ -4648,6 +4659,19 @@ <h5>Arguments:</h5>
46484659
order of execution of this <tt>store</tt> with other <a
46494660
href="#volatile">volatile operations</a>.</p>
46504661

4662+
<p>If the <code>store</code> is marked as <code>atomic</code>, it takes an extra
4663+
<a href="#ordering">ordering</a> and optional <code>singlethread</code>
4664+
argument. The <code>acquire</code> and <code>acq_rel</code> orderings aren't
4665+
valid on <code>store</code> instructions. Atomic loads produce <a
4666+
href="#memorymodel">defined</a> results when they may see multiple atomic
4667+
stores. The type of the pointee must be an integer type whose bit width
4668+
is a power of two greater than or equal to eight and less than or equal
4669+
to a target-specific size limit. <code>align</code> must be explicitly
4670+
specified on atomic stores, and the store has undefined behavior if the
4671+
alignment is not set to a value which is at least the size in bytes of
4672+
the pointee. <code>!nontemporal</code> does not have any defined semantics
4673+
for atomic stores.</p>
4674+
46514675
<p>The optional constant "align" argument specifies the alignment of the
46524676
operation (that is, the alignment of the memory address). A value of 0 or an
46534677
omitted "align" argument means that the operation has the preferential
@@ -4730,9 +4754,6 @@ <h5>Semantics:</h5>
47304754
specifies that the fence only synchronizes with other fences in the same
47314755
thread. (This is useful for interacting with signal handlers.)</p>
47324756

4733-
<p>FIXME: This instruction is a work in progress; until it is finished, use
4734-
llvm.memory.barrier.
4735-
47364757
<h5>Example:</h5>
47374758
<pre>
47384759
fence acquire <i>; yields {void}</i>

llvm/include/llvm/Bitcode/LLVMBitCodes.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,11 @@ namespace bitc {
307307
FUNC_CODE_INST_ATOMICRMW = 38, // ATOMICRMW: [ptrty,ptr,val, operation,
308308
// align, vol,
309309
// ordering, synchscope]
310-
FUNC_CODE_INST_RESUME = 39 // RESUME: [opval]
310+
FUNC_CODE_INST_RESUME = 39, // RESUME: [opval]
311+
FUNC_CODE_INST_LOADATOMIC = 40, // LOAD: [opty, op, align, vol,
312+
// ordering, synchscope]
313+
FUNC_CODE_INST_STOREATOMIC = 41 // STORE: [ptrty,ptr,val, align, vol
314+
// ordering, synchscope]
311315
};
312316
} // End bitc namespace
313317
} // End llvm namespace

llvm/include/llvm/Instructions.h

Lines changed: 100 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -142,12 +142,20 @@ class LoadInst : public UnaryInstruction {
142142
LoadInst(Value *Ptr, const Twine &NameStr, BasicBlock *InsertAtEnd);
143143
LoadInst(Value *Ptr, const Twine &NameStr, bool isVolatile = false,
144144
Instruction *InsertBefore = 0);
145-
LoadInst(Value *Ptr, const Twine &NameStr, bool isVolatile,
146-
unsigned Align, Instruction *InsertBefore = 0);
147145
LoadInst(Value *Ptr, const Twine &NameStr, bool isVolatile,
148146
BasicBlock *InsertAtEnd);
147+
LoadInst(Value *Ptr, const Twine &NameStr, bool isVolatile,
148+
unsigned Align, Instruction *InsertBefore = 0);
149149
LoadInst(Value *Ptr, const Twine &NameStr, bool isVolatile,
150150
unsigned Align, BasicBlock *InsertAtEnd);
151+
LoadInst(Value *Ptr, const Twine &NameStr, bool isVolatile,
152+
unsigned Align, AtomicOrdering Order,
153+
SynchronizationScope SynchScope = CrossThread,
154+
Instruction *InsertBefore = 0);
155+
LoadInst(Value *Ptr, const Twine &NameStr, bool isVolatile,
156+
unsigned Align, AtomicOrdering Order,
157+
SynchronizationScope SynchScope,
158+
BasicBlock *InsertAtEnd);
151159

152160
LoadInst(Value *Ptr, const char *NameStr, Instruction *InsertBefore);
153161
LoadInst(Value *Ptr, const char *NameStr, BasicBlock *InsertAtEnd);
@@ -171,11 +179,47 @@ class LoadInst : public UnaryInstruction {
171179
/// getAlignment - Return the alignment of the access that is being performed
172180
///
173181
unsigned getAlignment() const {
174-
return (1 << (getSubclassDataFromInstruction() >> 1)) >> 1;
182+
return (1 << ((getSubclassDataFromInstruction() >> 1) & 31)) >> 1;
175183
}
176184

177185
void setAlignment(unsigned Align);
178186

187+
/// Returns the ordering effect of this fence.
188+
AtomicOrdering getOrdering() const {
189+
return AtomicOrdering((getSubclassDataFromInstruction() >> 7) & 7);
190+
}
191+
192+
/// Set the ordering constraint on this load. May not be Release or
193+
/// AcquireRelease.
194+
void setOrdering(AtomicOrdering Ordering) {
195+
setInstructionSubclassData((getSubclassDataFromInstruction() & ~(7 << 7)) |
196+
(Ordering << 7));
197+
}
198+
199+
SynchronizationScope getSynchScope() const {
200+
return SynchronizationScope((getSubclassDataFromInstruction() >> 6) & 1);
201+
}
202+
203+
/// Specify whether this load is ordered with respect to all
204+
/// concurrently executing threads, or only with respect to signal handlers
205+
/// executing in the same thread.
206+
void setSynchScope(SynchronizationScope xthread) {
207+
setInstructionSubclassData((getSubclassDataFromInstruction() & ~(1 << 6)) |
208+
(xthread << 6));
209+
}
210+
211+
bool isAtomic() const { return getOrdering() != NotAtomic; }
212+
void setAtomic(AtomicOrdering Ordering,
213+
SynchronizationScope SynchScope = CrossThread) {
214+
setOrdering(Ordering);
215+
setSynchScope(SynchScope);
216+
}
217+
218+
bool isSimple() const { return !isAtomic() && !isVolatile(); }
219+
bool isUnordered() const {
220+
return getOrdering() <= Unordered && !isVolatile();
221+
}
222+
179223
Value *getPointerOperand() { return getOperand(0); }
180224
const Value *getPointerOperand() const { return getOperand(0); }
181225
static unsigned getPointerOperandIndex() { return 0U; }
@@ -222,19 +266,27 @@ class StoreInst : public Instruction {
222266
StoreInst(Value *Val, Value *Ptr, BasicBlock *InsertAtEnd);
223267
StoreInst(Value *Val, Value *Ptr, bool isVolatile = false,
224268
Instruction *InsertBefore = 0);
269+
StoreInst(Value *Val, Value *Ptr, bool isVolatile, BasicBlock *InsertAtEnd);
225270
StoreInst(Value *Val, Value *Ptr, bool isVolatile,
226271
unsigned Align, Instruction *InsertBefore = 0);
227-
StoreInst(Value *Val, Value *Ptr, bool isVolatile, BasicBlock *InsertAtEnd);
228272
StoreInst(Value *Val, Value *Ptr, bool isVolatile,
229273
unsigned Align, BasicBlock *InsertAtEnd);
274+
StoreInst(Value *Val, Value *Ptr, bool isVolatile,
275+
unsigned Align, AtomicOrdering Order,
276+
SynchronizationScope SynchScope = CrossThread,
277+
Instruction *InsertBefore = 0);
278+
StoreInst(Value *Val, Value *Ptr, bool isVolatile,
279+
unsigned Align, AtomicOrdering Order,
280+
SynchronizationScope SynchScope,
281+
BasicBlock *InsertAtEnd);
282+
230283

231-
232-
/// isVolatile - Return true if this is a load from a volatile memory
284+
/// isVolatile - Return true if this is a store to a volatile memory
233285
/// location.
234286
///
235287
bool isVolatile() const { return getSubclassDataFromInstruction() & 1; }
236288

237-
/// setVolatile - Specify whether this is a volatile load or not.
289+
/// setVolatile - Specify whether this is a volatile store or not.
238290
///
239291
void setVolatile(bool V) {
240292
setInstructionSubclassData((getSubclassDataFromInstruction() & ~1) |
@@ -247,11 +299,47 @@ class StoreInst : public Instruction {
247299
/// getAlignment - Return the alignment of the access that is being performed
248300
///
249301
unsigned getAlignment() const {
250-
return (1 << (getSubclassDataFromInstruction() >> 1)) >> 1;
302+
return (1 << ((getSubclassDataFromInstruction() >> 1) & 31)) >> 1;
251303
}
252304

253305
void setAlignment(unsigned Align);
254306

307+
/// Returns the ordering effect of this store.
308+
AtomicOrdering getOrdering() const {
309+
return AtomicOrdering((getSubclassDataFromInstruction() >> 7) & 7);
310+
}
311+
312+
/// Set the ordering constraint on this store. May not be Acquire or
313+
/// AcquireRelease.
314+
void setOrdering(AtomicOrdering Ordering) {
315+
setInstructionSubclassData((getSubclassDataFromInstruction() & ~(7 << 7)) |
316+
(Ordering << 7));
317+
}
318+
319+
SynchronizationScope getSynchScope() const {
320+
return SynchronizationScope((getSubclassDataFromInstruction() >> 6) & 1);
321+
}
322+
323+
/// Specify whether this store instruction is ordered with respect to all
324+
/// concurrently executing threads, or only with respect to signal handlers
325+
/// executing in the same thread.
326+
void setSynchScope(SynchronizationScope xthread) {
327+
setInstructionSubclassData((getSubclassDataFromInstruction() & ~(1 << 6)) |
328+
(xthread << 6));
329+
}
330+
331+
bool isAtomic() const { return getOrdering() != NotAtomic; }
332+
void setAtomic(AtomicOrdering Ordering,
333+
SynchronizationScope SynchScope = CrossThread) {
334+
setOrdering(Ordering);
335+
setSynchScope(SynchScope);
336+
}
337+
338+
bool isSimple() const { return !isAtomic() && !isVolatile(); }
339+
bool isUnordered() const {
340+
return getOrdering() <= Unordered && !isVolatile();
341+
}
342+
255343
Value *getValueOperand() { return getOperand(0); }
256344
const Value *getValueOperand() const { return getOperand(0); }
257345

@@ -319,18 +407,8 @@ class FenceInst : public Instruction {
319407
/// Set the ordering constraint on this fence. May only be Acquire, Release,
320408
/// AcquireRelease, or SequentiallyConsistent.
321409
void setOrdering(AtomicOrdering Ordering) {
322-
switch (Ordering) {
323-
case Acquire:
324-
case Release:
325-
case AcquireRelease:
326-
case SequentiallyConsistent:
327-
setInstructionSubclassData((getSubclassDataFromInstruction() & 1) |
328-
(Ordering << 1));
329-
return;
330-
default:
331-
llvm_unreachable("FenceInst ordering must be Acquire, Release,"
332-
" AcquireRelease, or SequentiallyConsistent");
333-
}
410+
setInstructionSubclassData((getSubclassDataFromInstruction() & 1) |
411+
(Ordering << 1));
334412
}
335413

336414
SynchronizationScope getSynchScope() const {
@@ -555,7 +633,7 @@ class AtomicRMWInst : public Instruction {
555633
void setOrdering(AtomicOrdering Ordering) {
556634
assert(Ordering != NotAtomic &&
557635
"atomicrmw instructions can only be atomic.");
558-
setInstructionSubclassData((getSubclassDataFromInstruction() & ~28) |
636+
setInstructionSubclassData((getSubclassDataFromInstruction() & ~(7 << 2)) |
559637
(Ordering << 2));
560638
}
561639

@@ -569,7 +647,7 @@ class AtomicRMWInst : public Instruction {
569647

570648
/// Returns the ordering constraint on this RMW.
571649
AtomicOrdering getOrdering() const {
572-
return AtomicOrdering((getSubclassDataFromInstruction() & 28) >> 2);
650+
return AtomicOrdering((getSubclassDataFromInstruction() >> 2) & 7);
573651
}
574652

575653
/// Returns whether this RMW is atomic between threads or only within a

0 commit comments

Comments
 (0)