Skip to content
Merged
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
24 changes: 3 additions & 21 deletions src/passes/MergeBlocks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -498,29 +498,11 @@ struct MergeBlocks
// )
// at which point the block is on the outside and potentially mergeable with
// an outer block
Block* optimize(Expression* curr,
Expression*& child,
Block* outer = nullptr,
Expression** dependency1 = nullptr,
Expression** dependency2 = nullptr) {
Block*
optimize(Expression* curr, Expression*& child, Block* outer = nullptr) {
if (!child) {
return outer;
}
if ((dependency1 && *dependency1) || (dependency2 && *dependency2)) {
// there are dependencies, things we must be reordered through. make sure
// no problems there
EffectAnalyzer childEffects(getPassOptions(), *getModule(), child);
if (dependency1 && *dependency1 &&
EffectAnalyzer(getPassOptions(), *getModule(), *dependency1)
.invalidates(childEffects)) {
return outer;
}
if (dependency2 && *dependency2 &&
EffectAnalyzer(getPassOptions(), *getModule(), *dependency2)
.invalidates(childEffects)) {
return outer;
}
}
if (auto* block = child->dynCast<Block>()) {
if (!block->name.is() && block->list.size() >= 2) {
auto* back = block->list.back();
Expand Down Expand Up @@ -665,7 +647,7 @@ struct MergeBlocks
EffectAnalyzer blockChildEffects(
getPassOptions(), *getModule(), blockChild);
for (auto& effects : childEffects) {
if (blockChildEffects.invalidates(effects)) {
if (effects.orderedBefore(blockChildEffects)) {
fail = true;
break;
}
Expand Down
83 changes: 83 additions & 0 deletions test/lit/passes/merge-blocks-atomics.wast
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited.
;; RUN: wasm-opt %s --merge-blocks -all -S -o - | 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)

;; CHECK: (func $foo (type $2) (param $0 i32) (param $1 i32)
;; CHECK-NEXT: )
(func $foo (param i32 i32))

;; CHECK: (func $disallowed (type $1) (param $x (ref $struct))
;; CHECK-NEXT: (call $foo
;; CHECK-NEXT: (block $label1 (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.atomic.load acqrel
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.get $struct 0
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $disallowed (param $x (ref $struct))
;; Test 1: Disallowed reordering (GC read NOT moved before acquire load).
(call $foo
;; This block is left behind because it is named.
(block $block (result i32)
(drop (i32.atomic.load acqrel (i32.const 0)))
(i32.const 0)
)
;; This block tries to move back past $block and out of $foo, but cannot.
(block (result i32)
(drop (struct.get $struct 0 (local.get $x)))
(i32.const 0)
)
)
)

;; CHECK: (func $allowed (type $1) (param $x (ref $struct))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.get $struct 0
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $foo
;; CHECK-NEXT: (block $label2 (result i32)
;; CHECK-NEXT: (i32.atomic.store acqrel
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $allowed (param $x (ref $struct))
;; Test 2: Allowed reordering (GC read moved before Wasm release store)
(call $foo
;; This block is left behind because it is named.
(block $block (result i32)
(i32.atomic.store acqrel (i32.const 0) (i32.const 42))
(i32.const 0)
)
;; This block can move back past $block and out of $foo.
(block (result i32)
(drop (struct.get $struct 0 (local.get $x)))
(i32.const 0)
)
)
)
)
Loading