Skip to content

Commit 830ce3a

Browse files
authored
Implement volatile barrier APIs (#107843)
* Initial commit * Follow-up commit Now that I'm on the correct branch * jit-format * Implement Feedback - And fix missed file from jit-format * Fix typos & use appropriate barrier type in mono * Use optimised dmb on arm64 where possible on mini-mono runtime - And fix up some FIXMEs & comments re cpobj and cpblk * Update Memory-model.md * Address feedback * Fix compile error * Move BarrierKind into compiler.h * Fix build & jit-format * Update jiteeversionguid.h * Update jiteeversionguid.h
1 parent bf23102 commit 830ce3a

23 files changed

Lines changed: 129 additions & 84 deletions

File tree

docs/design/specs/Memory-model.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,14 +74,16 @@ The effects of ordinary reads and writes can be reordered as long as that preser
7474
- IL load instructions with `volatile.` prefix when instruction supports such prefix
7575
- `System.Threading.Volatile.Read`
7676
- `System.Thread.VolatileRead`
77-
- Acquiring a lock (`System.Threading.Monitor.Enter` or entering a synchronized method)
77+
- `System.Threading.Volatile.ReadBarrier` (applies to all prior reads)
78+
- Acquiring a lock (`System.Threading.Monitor.Enter` or entering a synchronized method, applies to all prior reads)
7879

7980
* **Volatile writes** have "release semantics" - the effects of a volatile write will not be observable before effects of all previous, in program order, reads and writes become observable.
8081
Operations with release semantics:
8182
- IL store instructions with `volatile.` prefix when such prefix is supported
8283
- `System.Threading.Volatile.Write`
8384
- `System.Thread.VolatileWrite`
84-
- Releasing a lock (`System.Threading.Monitor.Exit` or leaving a synchronized method)
85+
- `System.Threading.Volatile.WriteBarrier` (applies to all following writes)
86+
- Releasing a lock (`System.Threading.Monitor.Exit` or leaving a synchronized method, applies to all following writes)
8587

8688
* **volatile. initblk** has "release semantics" - the effects of `.volatile initblk` will not be observable earlier than the effects of preceeding reads and writes.
8789

src/coreclr/inc/jiteeversionguid.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,11 @@ typedef const GUID *LPCGUID;
4343
#define GUID_DEFINED
4444
#endif // !GUID_DEFINED
4545

46-
constexpr GUID JITEEVersionIdentifier = { /* 7a8070f8-2951-4394-b97b-3d7c9bd8c91f */
47-
0x7a8070f8,
48-
0x2951,
49-
0x4394,
50-
{0xb9, 0x7b, 0x3d, 0x7c, 0x9b, 0xd8, 0xc9, 0x1f}
46+
constexpr GUID JITEEVersionIdentifier = { /* ac04f79d-8d06-4a15-9692-1b4f59265825 */
47+
0xac04f79d,
48+
0x8d06,
49+
0x4a15,
50+
{0x96, 0x92, 0x1b, 0x4f, 0x59, 0x26, 0x58, 0x25}
5151
};
5252

5353
//////////////////////////////////////////////////////////////////////////////////////////////////////////

src/coreclr/jit/codegen.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1627,12 +1627,6 @@ class CodeGen final : public CodeGenInterface
16271627

16281628
void instGen_Return(unsigned stkArgSize);
16291629

1630-
enum BarrierKind
1631-
{
1632-
BARRIER_FULL, // full barrier
1633-
BARRIER_LOAD_ONLY, // load barier
1634-
};
1635-
16361630
void instGen_MemoryBarrier(BarrierKind barrierKind = BARRIER_FULL);
16371631

16381632
void instGen_Set_Reg_To_Zero(emitAttr size, regNumber reg, insFlags flags = INS_FLAGS_DONT_CARE);

src/coreclr/jit/codegenarm64.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3704,8 +3704,8 @@ void CodeGen::genCodeForCpObj(GenTreeBlk* cpObjNode)
37043704

37053705
if (cpObjNode->IsVolatile())
37063706
{
3707-
// issue a full memory barrier before a volatile CpObj operation
3708-
instGen_MemoryBarrier();
3707+
// issue a store barrier before a volatile CpObj operation
3708+
instGen_MemoryBarrier(BARRIER_STORE_ONLY);
37093709
}
37103710

37113711
emitter* emit = GetEmitter();
@@ -5755,6 +5755,10 @@ void CodeGen::instGen_MemoryBarrier(BarrierKind barrierKind)
57555755
}
57565756
#endif // DEBUG
57575757

5758+
// We cannot emit BARRIER_STORE_ONLY better than BARRIER_FULL on arm64 today
5759+
if (barrierKind == BARRIER_STORE_ONLY)
5760+
barrierKind = BARRIER_FULL;
5761+
57585762
// Avoid emitting redundant memory barriers on arm64 if they belong to the same IG
57595763
// and there were no memory accesses in-between them
57605764
emitter::instrDesc* lastMemBarrier = GetEmitter()->emitLastMemBarrier;

src/coreclr/jit/codegenarmarch.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -428,8 +428,10 @@ void CodeGen::genCodeForTreeNode(GenTree* treeNode)
428428

429429
case GT_MEMORYBARRIER:
430430
{
431-
CodeGen::BarrierKind barrierKind =
432-
treeNode->gtFlags & GTF_MEMORYBARRIER_LOAD ? BARRIER_LOAD_ONLY : BARRIER_FULL;
431+
BarrierKind barrierKind =
432+
treeNode->gtFlags & GTF_MEMORYBARRIER_LOAD
433+
? BARRIER_LOAD_ONLY
434+
: (treeNode->gtFlags & GTF_MEMORYBARRIER_STORE ? BARRIER_STORE_ONLY : BARRIER_FULL);
433435

434436
instGen_MemoryBarrier(barrierKind);
435437
break;
@@ -2800,8 +2802,8 @@ void CodeGen::genCodeForCpBlkUnroll(GenTreeBlk* node)
28002802

28012803
if (node->IsVolatile())
28022804
{
2803-
// issue a full memory barrier before a volatile CpBlk operation
2804-
instGen_MemoryBarrier();
2805+
// issue a store barrier before a volatile CpBlk operation
2806+
instGen_MemoryBarrier(BARRIER_STORE_ONLY);
28052807
}
28062808

28072809
emitter* emit = GetEmitter();
@@ -3225,8 +3227,8 @@ void CodeGen::genCodeForInitBlkLoop(GenTreeBlk* initBlkNode)
32253227

32263228
if (initBlkNode->IsVolatile())
32273229
{
3228-
// issue a full memory barrier before a volatile initBlock Operation
3229-
instGen_MemoryBarrier();
3230+
// issue a store barrier before a volatile initBlock Operation
3231+
instGen_MemoryBarrier(BARRIER_STORE_ONLY);
32303232
}
32313233

32323234
// str xzr, [dstReg]

src/coreclr/jit/codegenloongarch64.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4434,8 +4434,10 @@ void CodeGen::genCodeForTreeNode(GenTree* treeNode)
44344434

44354435
case GT_MEMORYBARRIER:
44364436
{
4437-
CodeGen::BarrierKind barrierKind =
4438-
treeNode->gtFlags & GTF_MEMORYBARRIER_LOAD ? BARRIER_LOAD_ONLY : BARRIER_FULL;
4437+
BarrierKind barrierKind =
4438+
treeNode->gtFlags & GTF_MEMORYBARRIER_LOAD
4439+
? BARRIER_LOAD_ONLY
4440+
: (treeNode->gtFlags & GTF_MEMORYBARRIER_STORE ? BARRIER_STORE_ONLY : BARRIER_FULL);
44394441

44404442
instGen_MemoryBarrier(barrierKind);
44414443
break;

src/coreclr/jit/codegenriscv64.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4491,8 +4491,10 @@ void CodeGen::genCodeForTreeNode(GenTree* treeNode)
44914491

44924492
case GT_MEMORYBARRIER:
44934493
{
4494-
CodeGen::BarrierKind barrierKind =
4495-
treeNode->gtFlags & GTF_MEMORYBARRIER_LOAD ? BARRIER_LOAD_ONLY : BARRIER_FULL;
4494+
BarrierKind barrierKind =
4495+
treeNode->gtFlags & GTF_MEMORYBARRIER_LOAD
4496+
? BARRIER_LOAD_ONLY
4497+
: (treeNode->gtFlags & GTF_MEMORYBARRIER_STORE ? BARRIER_STORE_ONLY : BARRIER_FULL);
44964498

44974499
instGen_MemoryBarrier(barrierKind);
44984500
break;

src/coreclr/jit/codegenxarch.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2144,8 +2144,10 @@ void CodeGen::genCodeForTreeNode(GenTree* treeNode)
21442144

21452145
case GT_MEMORYBARRIER:
21462146
{
2147-
CodeGen::BarrierKind barrierKind =
2148-
treeNode->gtFlags & GTF_MEMORYBARRIER_LOAD ? BARRIER_LOAD_ONLY : BARRIER_FULL;
2147+
BarrierKind barrierKind =
2148+
treeNode->gtFlags & GTF_MEMORYBARRIER_LOAD
2149+
? BARRIER_LOAD_ONLY
2150+
: (treeNode->gtFlags & GTF_MEMORYBARRIER_STORE ? BARRIER_STORE_ONLY : BARRIER_FULL);
21492151

21502152
instGen_MemoryBarrier(barrierKind);
21512153
break;
@@ -11075,7 +11077,7 @@ void CodeGen::genRestoreCalleeSavedFltRegs(unsigned lclFrameSize)
1107511077
// instGen_MemoryBarrier: Emit a MemoryBarrier instruction
1107611078
//
1107711079
// Arguments:
11078-
// barrierKind - kind of barrier to emit (Load-only is no-op on xarch)
11080+
// barrierKind - kind of barrier to emit (Load-only and Store-only are no-ops on xarch)
1107911081
//
1108011082
// Notes:
1108111083
// All MemoryBarriers instructions can be removed by DOTNET_JitNoMemoryBarriers=1

src/coreclr/jit/compiler.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,13 @@ struct VarScopeDsc
204204
#endif
205205
};
206206

207+
enum BarrierKind
208+
{
209+
BARRIER_FULL, // full barrier
210+
BARRIER_LOAD_ONLY, // load barrier
211+
BARRIER_STORE_ONLY, // store barrier
212+
};
213+
207214
// This class stores information associated with a LclVar SSA definition.
208215
class LclSsaVarDsc
209216
{
@@ -3455,7 +3462,7 @@ class Compiler
34553462
#endif
34563463
#endif // FEATURE_HW_INTRINSICS
34573464

3458-
GenTree* gtNewMemoryBarrier(bool loadOnly = false);
3465+
GenTree* gtNewMemoryBarrier(BarrierKind barrierKind);
34593466

34603467
GenTree* gtNewMustThrowException(unsigned helper, var_types type, CORINFO_CLASS_HANDLE clsHnd);
34613468

src/coreclr/jit/gentree.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8630,19 +8630,23 @@ GenTreeBlk* Compiler::gtNewBlkIndir(ClassLayout* layout, GenTree* addr, GenTreeF
86308630
// gtNewMemoryBarrier: Create a memory barrier node
86318631
//
86328632
// Arguments:
8633-
// loadOnly - relaxes the full memory barrier to be load-only
8633+
// barrierKind - the kind of barrer we are creating
86348634
//
86358635
// Return Value:
86368636
// The created GT_MEMORYBARRIER node.
86378637
//
8638-
GenTree* Compiler::gtNewMemoryBarrier(bool loadOnly)
8638+
GenTree* Compiler::gtNewMemoryBarrier(BarrierKind barrierKind)
86398639
{
86408640
GenTree* tree = new (this, GT_MEMORYBARRIER) GenTree(GT_MEMORYBARRIER, TYP_VOID);
86418641
tree->gtFlags |= GTF_GLOB_REF | GTF_ASG;
8642-
if (loadOnly)
8642+
if (barrierKind == BARRIER_LOAD_ONLY)
86438643
{
86448644
tree->gtFlags |= GTF_MEMORYBARRIER_LOAD;
86458645
}
8646+
else if (barrierKind == BARRIER_STORE_ONLY)
8647+
{
8648+
tree->gtFlags |= GTF_MEMORYBARRIER_STORE;
8649+
}
86468650
return tree;
86478651
}
86488652

0 commit comments

Comments
 (0)