Skip to content

Commit 46135df

Browse files
authored
strengthen reference stores to give release/consume semantics (JuliaLang#45484)
Followup to JuliaLang#36507; see the discussion there. Also slightly weakens non-atomic pointer modification, since we generally don't need DRF swap guarantees at all (even monotonic), only the atomic-release property. This would correspond to atomic-unordered failure order in many cases, but the LLVM LangRef says that this case is "uninteresting", and thus declares it is invalid. n.b. this still does not cover embedded references inside inlined structs
1 parent f4d13cf commit 46135df

9 files changed

+28
-22
lines changed

Diff for: src/array.c

+4-4
Original file line numberDiff line numberDiff line change
@@ -617,7 +617,7 @@ JL_DLLEXPORT void jl_arrayset(jl_array_t *a JL_ROOTING_ARGUMENT, jl_value_t *rhs
617617
arrayassign_safe(hasptr, jl_array_owner(a), &((char*)a->data)[i * a->elsize], rhs, a->elsize);
618618
}
619619
else {
620-
jl_atomic_store_relaxed(((_Atomic(jl_value_t*)*)a->data) + i, rhs);
620+
jl_atomic_store_release(((_Atomic(jl_value_t*)*)a->data) + i, rhs);
621621
jl_gc_wb(jl_array_owner(a), rhs);
622622
}
623623
}
@@ -627,7 +627,7 @@ JL_DLLEXPORT void jl_arrayunset(jl_array_t *a, size_t i)
627627
if (i >= jl_array_len(a))
628628
jl_bounds_error_int((jl_value_t*)a, i + 1);
629629
if (a->flags.ptrarray)
630-
jl_atomic_store_relaxed(((_Atomic(jl_value_t*)*)a->data) + i, NULL);
630+
jl_atomic_store_release(((_Atomic(jl_value_t*)*)a->data) + i, NULL);
631631
else if (a->flags.hasptr) {
632632
size_t elsize = a->elsize;
633633
jl_assume(elsize >= sizeof(void*) && elsize % sizeof(void*) == 0);
@@ -1198,7 +1198,7 @@ static NOINLINE ssize_t jl_array_ptr_copy_forward(jl_value_t *owner,
11981198
_Atomic(void*) *dest_pa = (_Atomic(void*)*)dest_p;
11991199
for (ssize_t i = 0; i < n; i++) {
12001200
void *val = jl_atomic_load_relaxed(src_pa + i);
1201-
jl_atomic_store_relaxed(dest_pa + i, val);
1201+
jl_atomic_store_release(dest_pa + i, val);
12021202
// `val` is young or old-unmarked
12031203
if (val && !(jl_astaggedvalue(val)->bits.gc & GC_MARKED)) {
12041204
jl_gc_queue_root(owner);
@@ -1216,7 +1216,7 @@ static NOINLINE ssize_t jl_array_ptr_copy_backward(jl_value_t *owner,
12161216
_Atomic(void*) *dest_pa = (_Atomic(void*)*)dest_p;
12171217
for (ssize_t i = 0; i < n; i++) {
12181218
void *val = jl_atomic_load_relaxed(src_pa + n - i - 1);
1219-
jl_atomic_store_relaxed(dest_pa + n - i - 1, val);
1219+
jl_atomic_store_release(dest_pa + n - i - 1, val);
12201220
// `val` is young or old-unmarked
12211221
if (val && !(jl_astaggedvalue(val)->bits.gc & GC_MARKED)) {
12221222
jl_gc_queue_root(owner);

Diff for: src/cgutils.cpp

+9-3
Original file line numberDiff line numberDiff line change
@@ -1759,6 +1759,8 @@ static jl_cgval_t typed_store(jl_codectx_t &ctx,
17591759
if (issetfield || (Order == AtomicOrdering::NotAtomic && isswapfield)) {
17601760
if (isswapfield) {
17611761
auto *load = ctx.builder.CreateAlignedLoad(elty, ptr, Align(alignment));
1762+
if (isboxed)
1763+
load->setOrdering(AtomicOrdering::Unordered);
17621764
if (aliasscope)
17631765
load->setMetadata("noalias", aliasscope);
17641766
if (tbaa)
@@ -1767,7 +1769,7 @@ static jl_cgval_t typed_store(jl_codectx_t &ctx,
17671769
instr = load;
17681770
}
17691771
StoreInst *store = ctx.builder.CreateAlignedStore(r, ptr, Align(alignment));
1770-
store->setOrdering(Order);
1772+
store->setOrdering(Order == AtomicOrdering::NotAtomic && isboxed ? AtomicOrdering::Release : Order);
17711773
if (aliasscope)
17721774
store->setMetadata("noalias", aliasscope);
17731775
if (tbaa)
@@ -1807,7 +1809,7 @@ static jl_cgval_t typed_store(jl_codectx_t &ctx,
18071809
ctx.builder.CreateCondBr(SameType, BB, SkipBB);
18081810
ctx.builder.SetInsertPoint(SkipBB);
18091811
LoadInst *load = ctx.builder.CreateAlignedLoad(elty, ptr, Align(alignment));
1810-
load->setOrdering(FailOrder);
1812+
load->setOrdering(FailOrder == AtomicOrdering::NotAtomic && isboxed ? AtomicOrdering::Monotonic : FailOrder);
18111813
if (aliasscope)
18121814
load->setMetadata("noalias", aliasscope);
18131815
if (tbaa)
@@ -1838,7 +1840,7 @@ static jl_cgval_t typed_store(jl_codectx_t &ctx,
18381840
}
18391841
else { // swap or modify
18401842
LoadInst *Current = ctx.builder.CreateAlignedLoad(elty, ptr, Align(alignment));
1841-
Current->setOrdering(Order == AtomicOrdering::NotAtomic ? Order : AtomicOrdering::Monotonic);
1843+
Current->setOrdering(Order == AtomicOrdering::NotAtomic && !isboxed ? Order : AtomicOrdering::Monotonic);
18421844
if (aliasscope)
18431845
Current->setMetadata("noalias", aliasscope);
18441846
if (tbaa)
@@ -1893,6 +1895,8 @@ static jl_cgval_t typed_store(jl_codectx_t &ctx,
18931895
// modifyfield or replacefield
18941896
assert(elty == realelty && !intcast);
18951897
auto *load = ctx.builder.CreateAlignedLoad(elty, ptr, Align(alignment));
1898+
if (isboxed)
1899+
load->setOrdering(AtomicOrdering::Monotonic);
18961900
if (aliasscope)
18971901
load->setMetadata("noalias", aliasscope);
18981902
if (tbaa)
@@ -1921,6 +1925,8 @@ static jl_cgval_t typed_store(jl_codectx_t &ctx,
19211925
else {
19221926
if (Order == AtomicOrdering::Unordered)
19231927
Order = AtomicOrdering::Monotonic;
1928+
if (Order == AtomicOrdering::Monotonic && isboxed)
1929+
Order = AtomicOrdering::Release;
19241930
if (!isreplacefield)
19251931
FailOrder = AtomicOrdering::Monotonic;
19261932
else if (FailOrder == AtomicOrdering::Unordered)

Diff for: src/codegen.cpp

+6-6
Original file line numberDiff line numberDiff line change
@@ -2940,11 +2940,11 @@ static bool emit_f_opfield(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f,
29402940
else {
29412941
*ret = emit_setfield(ctx, uty, obj, idx, val, cmp, true,
29422942
(needlock || order <= jl_memory_order_notatomic)
2943-
? (isboxed ? AtomicOrdering::Unordered : AtomicOrdering::NotAtomic) // TODO: we should do this for anything with CountTrackedPointers(elty).count > 0
2944-
: get_llvm_atomic_order(order),
2943+
? AtomicOrdering::NotAtomic
2944+
: get_llvm_atomic_order(order),
29452945
(needlock || fail_order <= jl_memory_order_notatomic)
2946-
? (isboxed ? AtomicOrdering::Unordered : AtomicOrdering::NotAtomic) // TODO: we should do this for anything with CountTrackedPointers(elty).count > 0
2947-
: get_llvm_atomic_order(fail_order),
2946+
? AtomicOrdering::NotAtomic
2947+
: get_llvm_atomic_order(fail_order),
29482948
needlock, issetfield, isreplacefield, isswapfield, ismodifyfield,
29492949
modifyop, fname);
29502950
}
@@ -3279,8 +3279,8 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f,
32793279
ctx.aliasscope,
32803280
data_owner,
32813281
isboxed,
3282-
isboxed ? AtomicOrdering::Unordered : AtomicOrdering::NotAtomic, // TODO: we should do this for anything with CountTrackedPointers(elty).count > 0
3283-
isboxed ? AtomicOrdering::Unordered : AtomicOrdering::NotAtomic, // TODO: we should do this for anything with CountTrackedPointers(elty).count > 0
3282+
isboxed ? AtomicOrdering::Release : AtomicOrdering::NotAtomic, // TODO: we should do this for anything with CountTrackedPointers(elty).count > 0
3283+
/*FailOrder*/AtomicOrdering::NotAtomic, // TODO: we should do this for anything with CountTrackedPointers(elty).count > 0
32843284
0,
32853285
false,
32863286
true,

Diff for: src/datatype.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -1491,7 +1491,7 @@ void set_nth_field(jl_datatype_t *st, jl_value_t *v, size_t i, jl_value_t *rhs,
14911491
return;
14921492
}
14931493
if (jl_field_isptr(st, i)) {
1494-
jl_atomic_store_relaxed((_Atomic(jl_value_t*)*)((char*)v + offs), rhs);
1494+
jl_atomic_store_release((_Atomic(jl_value_t*)*)((char*)v + offs), rhs);
14951495
jl_gc_wb(v, rhs);
14961496
}
14971497
else {

Diff for: src/debuginfo.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -537,7 +537,7 @@ void JITDebugInfoRegistry::libc_frames_t::libc_register_frame(const char *Entry)
537537
auto libc_register_frame_ = jl_atomic_load_relaxed(&this->libc_register_frame_);
538538
if (!libc_register_frame_) {
539539
libc_register_frame_ = (void(*)(void*))dlsym(RTLD_NEXT, "__register_frame");
540-
jl_atomic_store_relaxed(&this->libc_register_frame_, libc_register_frame_);
540+
jl_atomic_store_release(&this->libc_register_frame_, libc_register_frame_);
541541
}
542542
assert(libc_register_frame_);
543543
jl_profile_atomic([&]() {
@@ -550,7 +550,7 @@ void JITDebugInfoRegistry::libc_frames_t::libc_deregister_frame(const char *Entr
550550
auto libc_deregister_frame_ = jl_atomic_load_relaxed(&this->libc_deregister_frame_);
551551
if (!libc_deregister_frame_) {
552552
libc_deregister_frame_ = (void(*)(void*))dlsym(RTLD_NEXT, "__deregister_frame");
553-
jl_atomic_store_relaxed(&this->libc_deregister_frame_, libc_deregister_frame_);
553+
jl_atomic_store_release(&this->libc_deregister_frame_, libc_deregister_frame_);
554554
}
555555
assert(libc_deregister_frame_);
556556
jl_profile_atomic([&]() {

Diff for: src/iddict.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,9 @@ static inline int jl_table_assign_bp(jl_array_t **pa, jl_value_t *key, jl_value_
8181
} while (iter <= maxprobe && index != orig);
8282

8383
if (empty_slot != -1) {
84-
jl_atomic_store_relaxed(&tab[empty_slot], key);
84+
jl_atomic_store_release(&tab[empty_slot], key);
8585
jl_gc_wb(a, key);
86-
jl_atomic_store_relaxed(&tab[empty_slot + 1], val);
86+
jl_atomic_store_release(&tab[empty_slot + 1], val);
8787
jl_gc_wb(a, val);
8888
return 1;
8989
}

Diff for: src/julia.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -1001,7 +1001,7 @@ STATIC_INLINE jl_value_t *jl_array_ptr_set(
10011001
{
10021002
assert(((jl_array_t*)a)->flags.ptrarray);
10031003
assert(i < jl_array_len(a));
1004-
jl_atomic_store_relaxed(((_Atomic(jl_value_t*)*)(jl_array_data(a))) + i, (jl_value_t*)x);
1004+
jl_atomic_store_release(((_Atomic(jl_value_t*)*)(jl_array_data(a))) + i, (jl_value_t*)x);
10051005
if (x) {
10061006
if (((jl_array_t*)a)->flags.how == 3) {
10071007
a = jl_array_data_owner(a);

Diff for: src/julia_internal.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -207,12 +207,12 @@ static inline void memmove_refs(void **dstp, void *const *srcp, size_t n) JL_NOT
207207
_Atomic(void*) *dstpa = (_Atomic(void*)*)dstp;
208208
if (dstp < srcp || dstp > srcp + n) {
209209
for (i = 0; i < n; i++) {
210-
jl_atomic_store_relaxed(dstpa + i, jl_atomic_load_relaxed(srcpa + i));
210+
jl_atomic_store_release(dstpa + i, jl_atomic_load_relaxed(srcpa + i));
211211
}
212212
}
213213
else {
214214
for (i = 0; i < n; i++) {
215-
jl_atomic_store_relaxed(dstpa + n - i - 1, jl_atomic_load_relaxed(srcpa + n - i - 1));
215+
jl_atomic_store_release(dstpa + n - i - 1, jl_atomic_load_relaxed(srcpa + n - i - 1));
216216
}
217217
}
218218
}

Diff for: src/module.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -830,7 +830,7 @@ JL_DLLEXPORT void jl_checked_assignment(jl_binding_t *b, jl_value_t *rhs)
830830
jl_safe_printf("WARNING: redefinition of constant %s. This may fail, cause incorrect answers, or produce other errors.\n",
831831
jl_symbol_name(b->name));
832832
}
833-
jl_atomic_store_relaxed(&b->value, rhs);
833+
jl_atomic_store_release(&b->value, rhs);
834834
jl_gc_wb_binding(b, rhs);
835835
}
836836

0 commit comments

Comments
 (0)