Skip to content

Commit

Permalink
Handle unoptimized branches in CodeFolding (#7111)
Browse files Browse the repository at this point in the history
CodeFolding previously did not consider br_on_* instructions at all, so
it would happily merge tails even if there were br_on_* branches to the
same label with non-matching tails. Fix the bug by making any label
targeted by any instruction not explicitly handled by CodeFolding
unoptimizable. This will gracefully handle other branching instructions
like `resume` and `resume_throw` as well. Folding these branches
properly is left as future work.

Also rename the test file from code-folding_enable-threads.wast to just
code-folding.wast and enable all features instead of just threads. The
old name was left over from when the test was originally ported to lit,
and the new feature is necessary because the new test uses GC
instructions.
  • Loading branch information
tlively authored Nov 25, 2024
1 parent 3d39401 commit a2a8d2a
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 20 deletions.
22 changes: 14 additions & 8 deletions src/passes/CodeFolding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,9 @@ struct ExpressionMarker
void visitExpression(Expression* expr) { marked.insert(expr); }
};

struct CodeFolding : public WalkerPass<ControlFlowWalker<CodeFolding>> {
struct CodeFolding
: public WalkerPass<
ControlFlowWalker<CodeFolding, UnifiedExpressionVisitor<CodeFolding>>> {
bool isFunctionParallel() override { return true; }

std::unique_ptr<Pass> create() override {
Expand Down Expand Up @@ -138,6 +140,17 @@ struct CodeFolding : public WalkerPass<ControlFlowWalker<CodeFolding>> {

// walking

void visitExpression(Expression* curr) {
// For any branching instruction not explicitly handled by this pass, mark
// the labels it branches to unoptimizable.
// TODO: Handle folding br_on* instructions. br_on_null could be folded with
// other kinds of branches and br_on_non_null, br_on_cast, and
// br_on_cast_fail instructions could be folded with other copies of
// themselves.
BranchUtils::operateOnScopeNameUses(
curr, [&](Name label) { unoptimizables.insert(label); });
}

void visitBreak(Break* curr) {
if (curr->condition || curr->value) {
unoptimizables.insert(curr->name);
Expand All @@ -155,13 +168,6 @@ struct CodeFolding : public WalkerPass<ControlFlowWalker<CodeFolding>> {
}
}

void visitSwitch(Switch* curr) {
for (auto target : curr->targets) {
unoptimizables.insert(target);
}
unoptimizables.insert(curr->default_);
}

void visitUnreachable(Unreachable* curr) {
// we can only optimize if we are at the end of the parent block
if (!controlFlowStack.empty()) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited.
;; NOTE: This test was ported using port_passes_tests_to_lit.py and could be cleaned up.

;; RUN: foreach %s %t wasm-opt --code-folding --enable-threads -S -o - | filecheck %s
;; RUN: foreach %s %t wasm-opt -all --code-folding -S -o - | filecheck %s

(module
;; CHECK: (type $0 (func))
Expand All @@ -15,13 +15,13 @@
(memory $0 1 1)
;; CHECK: (table $0 282 282 funcref)

;; CHECK: (func $0
;; CHECK: (func $0 (type $0)
;; CHECK-NEXT: (block $label$1
;; CHECK-NEXT: (if
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: (then
;; CHECK-NEXT: (block $label$3
;; CHECK-NEXT: (call_indirect (type $13)
;; CHECK-NEXT: (call_indirect $0 (type $13)
;; CHECK-NEXT: (block $label$4
;; CHECK-NEXT: (br $label$3)
;; CHECK-NEXT: )
Expand Down Expand Up @@ -52,7 +52,7 @@
)
)
)
;; CHECK: (func $negative-zero (result f32)
;; CHECK: (func $negative-zero (type $1) (result f32)
;; CHECK-NEXT: (if (result f32)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: (then
Expand Down Expand Up @@ -82,7 +82,7 @@
)
)
)
;; CHECK: (func $negative-zero-b (result f32)
;; CHECK: (func $negative-zero-b (type $1) (result f32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
Expand All @@ -105,7 +105,7 @@
)
)
)
;; CHECK: (func $negative-zero-c (result f32)
;; CHECK: (func $negative-zero-c (type $1) (result f32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
Expand All @@ -128,7 +128,7 @@
)
)
)
;; CHECK: (func $break-target-outside-of-return-merged-code
;; CHECK: (func $break-target-outside-of-return-merged-code (type $0)
;; CHECK-NEXT: (block $label$A
;; CHECK-NEXT: (if
;; CHECK-NEXT: (unreachable)
Expand Down Expand Up @@ -202,7 +202,7 @@
)
)
)
;; CHECK: (func $break-target-inside-all-good
;; CHECK: (func $break-target-inside-all-good (type $0)
;; CHECK-NEXT: (block $folding-inner0
;; CHECK-NEXT: (block $label$A
;; CHECK-NEXT: (if
Expand Down Expand Up @@ -269,7 +269,7 @@
)
)
)
;; CHECK: (func $leave-inner-block-type
;; CHECK: (func $leave-inner-block-type (type $0)
;; CHECK-NEXT: (block $label$1
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block $label$2
Expand Down Expand Up @@ -312,7 +312,7 @@
(memory $0 1 1 shared)
;; CHECK: (export "func_2224" (func $0))
(export "func_2224" (func $0))
;; CHECK: (func $0 (result i32)
;; CHECK: (func $0 (type $0) (result i32)
;; CHECK-NEXT: (local $var$0 i32)
;; CHECK-NEXT: (if (result i32)
;; CHECK-NEXT: (i32.const 0)
Expand Down Expand Up @@ -352,7 +352,7 @@

;; CHECK: (global $global$0 (mut i32) (i32.const 10))
(global $global$0 (mut i32) (i32.const 10))
;; CHECK: (func $determinism
;; CHECK: (func $determinism (type $0)
;; CHECK-NEXT: (block $folding-inner0
;; CHECK-NEXT: (block
;; CHECK-NEXT: (block $label$1
Expand Down Expand Up @@ -439,7 +439,7 @@
)
(unreachable)
)
;; CHECK: (func $careful-of-the-switch (param $0 i32)
;; CHECK: (func $careful-of-the-switch (type $1) (param $0 i32)
;; CHECK-NEXT: (block $label$1
;; CHECK-NEXT: (block $label$3
;; CHECK-NEXT: (block $label$5
Expand Down Expand Up @@ -482,3 +482,42 @@
)
)
)

(module
;; CHECK: (type $0 (func))

;; CHECK: (func $br-on-null (type $0)
;; CHECK-NEXT: (block $block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (br_on_null $block
;; CHECK-NEXT: (ref.null none)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (call $br-on-null)
;; CHECK-NEXT: (br $block)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $br-on-null)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $br-on-null
(block $block
(drop
;; The other two tails are the same, but this br_on_null should inhibit code
;; folding.
(br_on_null $block
(ref.null none)
)
)
(drop
(block (result i32)
(call $br-on-null)
(br $block)
)
)
(call $br-on-null)
)
)
)

0 comments on commit a2a8d2a

Please sign in to comment.