Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/passes/CodePushing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ class Pusher {
auto* pushable = isPushable(list[i]);
if (pushable) {
const auto& effects = getPushableEffects(pushable);
if (cumulativeEffects.invalidates(effects)) {
if (effects.orderedBefore(cumulativeEffects)) {
// we can't push this, so further pushables must pass it
cumulativeEffects.mergeIn(effects);
} else {
Expand Down Expand Up @@ -354,7 +354,7 @@ class Pusher {

const auto& effects = getPushableEffects(pushable);

if (cumulativeEffects.invalidates(effects)) {
if (effects.orderedBefore(cumulativeEffects)) {
// This can't be moved forward. Add it to the things that are not
// moving.
cumulativeEffects.walk(list[i]);
Expand Down
145 changes: 145 additions & 0 deletions test/lit/passes/code-pushing-atomics.wast
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited.
;; RUN: wasm-opt -all --code-pushing -S -o - %s | filecheck %s

(module
;; CHECK: (type $struct (shared (struct (field (mut i32)))))
(type $struct (shared (struct (field (mut i32)))))

;; CHECK: (memory $mem 1 1 shared)
(memory $mem 1 1 shared)

;; Test 1: Allowed reordering into If (GC read pushed past Wasm acquire load into If arm)
;; CHECK: (func $allowed (type $1) (param $x (ref $struct)) (param $cond i32)
;; CHECK-NEXT: (local $y i32)
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.atomic.load acqrel
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (if
;; CHECK-NEXT: (local.get $cond)
;; CHECK-NEXT: (then
;; CHECK-NEXT: (local.set $y
;; CHECK-NEXT: (struct.get $struct 0
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $y)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $allowed (param $x (ref $struct)) (param $cond i32)
(local $y i32)
(local.set $y (struct.get $struct 0 (local.get $x)))
(drop (i32.atomic.load acqrel (i32.const 0)))
(if (local.get $cond)
(then
(drop (local.get $y))
)
)
)

;; Test 2: Disallowed reordering into If (GC read NOT pushed past Wasm release store into If arm)
;; CHECK: (func $disallowed (type $1) (param $x (ref $struct)) (param $cond i32)
;; CHECK-NEXT: (local $y i32)
;; CHECK-NEXT: (local.set $y
;; CHECK-NEXT: (struct.get $struct 0
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.atomic.store acqrel
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: )
;; CHECK-NEXT: (if
;; CHECK-NEXT: (local.get $cond)
;; CHECK-NEXT: (then
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $y)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $disallowed (param $x (ref $struct)) (param $cond i32)
(local $y i32)
(local.set $y (struct.get $struct 0 (local.get $x)))
(i32.atomic.store acqrel (i32.const 0) (i32.const 42))
(if (local.get $cond)
(then
(drop (local.get $y))
)
)
)

;; Test 3: Allowed segment reordering (GC read pushed past Wasm acquire load AND target if block, as it is read after the if)
;; CHECK: (func $allowed_segment (type $1) (param $x (ref $struct)) (param $cond i32)
;; CHECK-NEXT: (local $y i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.atomic.load acqrel
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (if
;; CHECK-NEXT: (local.get $cond)
;; CHECK-NEXT: (then
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.set $y
;; CHECK-NEXT: (struct.get $struct 0
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $y)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $allowed_segment (param $x (ref $struct)) (param $cond i32)
(local $y i32)
(local.set $y (struct.get $struct 0 (local.get $x)))
(drop (i32.atomic.load acqrel (i32.const 0)))
(if (local.get $cond)
(then
(nop)
)
)
(drop (local.get $y))
)

;; Test 4: Disallowed segment reordering (GC read NOT pushed past Wasm release store, even if it is read after the if)
;; CHECK: (func $disallowed_segment (type $1) (param $x (ref $struct)) (param $cond i32)
;; CHECK-NEXT: (local $y i32)
;; CHECK-NEXT: (local.set $y
;; CHECK-NEXT: (struct.get $struct 0
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.atomic.store acqrel
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: )
;; CHECK-NEXT: (if
;; CHECK-NEXT: (local.get $cond)
;; CHECK-NEXT: (then
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $y)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $disallowed_segment (param $x (ref $struct)) (param $cond i32)
(local $y i32)
(local.set $y (struct.get $struct 0 (local.get $x)))
(i32.atomic.store acqrel (i32.const 0) (i32.const 42))
(if (local.get $cond)
(then
(nop)
)
)
(drop (local.get $y))
)
)