WebAssembly / WebAssembly/binaryen

Running `wasm-opt` with `-Os` leaves NOP / dead control flow behind

Open
#8,077 11 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
WebAssembly
Stars
8.6k
Forks
885
Avg merge
1d 19h
Merged PRs (30d)
69

Description

See attached flute.tar.gz

We start with an unoptimized flute.wasm file and run wasm-opt

% wasm-opt -g --enable-gc --enable-reference-types --enable-multivalue --enable-exception-handling --enable-nontrapping-float-to-int --enable-sign-ext --enable-bulk-memory --enable-threads '--no-inline=*<noInline>*' --traps-never-happen \
    -Os \
    flute.wasm \
    -o flute.Os.wasm

This -Os leaves NOP blocks behind:

 (func $_InterfaceType.toString ...
  ...
    block $label0 (result i32)
      local.get $var0
      ref.cast $_InterfaceType
      local.tee $var7
      struct.get $_InterfaceType $classId
      br $label0
    end $label0
  ...
)

It also doesn't prune branches with unreachable (some variants of this):

(func $_FunctionType.toString
  ...
            if (result (ref $JSStringImpl))
              local.get $var6
              unreachable
            else
              local.get $var6
              block $label5 (result (ref $JSStringImpl))
                local.get $var9
                i32.const 0
                global.get $"C8 DiagnosticLevel"
                ref.null none
                local.get $var9
                struct.get $_Type $field0
                i32.const 3066
                i32.add
                call_indirect (param (ref $#Top) i32 (ref $DiagnosticLevel) (ref null $TextTreeConfiguration)) (result (ref $JSStringImpl))
                br $label5
              end $label5
              call $JSStringImpl.+
            end
  ...  
)

If we run another -Os pass then those issues disappear

% wasm-opt -g --enable-gc --enable-reference-types --enable-multivalue --enable-exception-handling --enable-nontrapping-float-to-int --enable-sign-ext --enable-bulk-memory --enable-threads '--no-inline=*<noInline>*' --traps-never-happen \
    -Os \
    flute.Os.wasm \
    -o flute.Os.Os.wasm

From a users point of view, I wouldn't expect an -Os to leave these code patterns behind. We can of course run multiple -Os rounds, but that a) may do more work than needed and b) raises the question of how many -Os passes one may need to run to cleanup things left by previous -Os passes.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reproducing the report with the attached flute.wasm and the shown wasm-opt command, then inspect the first -Os output for the NOP blocks and unreachable branches shown in the issue. Compare it with a second -Os pass; done means one optimization pass removes these dead control-flow patterns without requiring repeated -Os runs.

Written by the indexing model from the issue text.

Assessment

Tech stack
wasm
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.