WebAssembly / WebAssembly/binaryen

Aggressive optimization of `unreachable`s?

Open
#4,744 6 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

I have written a Binaryen pass that emits unreachables into the wasm tree. That produces something like this:

 (func $17 (param $0 i32) (param $1 i32)
  (block $label$1
   (br_if $label$1
    (i32.eqz
     (local.get $1)
    )
   )
   (br_if $label$1
    (call $26
     (local.get $1)
     (i32.load offset=32
      (i32.load
       (local.get $0)
      )
     )
    )
   )
   (drop
    (i32.load
     (i32.const 3308276)
    )
   )
   (unreachable)                 # Added by my pass
  )
 )

Since the end of the function $17 is unreachable, I'd like an optimizer to realize that all the preceding statements are then unreachable as well since the control unconditionally flows to that unreachable. So the function could be collapsed into a single

 (func $17 (param $0 i32) (param $1 i32)
   (unreachable)
  )

and then further inlined into its callers, and the unreachable propagated that way to their callers and their callers, as efficiently as is possible.

I was trying to run different optimization passes in wasm-opt, ranging from --dce, --inlining-optimizing, --O4 and -Oz and pretty much anything else that had a summary description that it might optimize something,

--inlining-optimizing --dce --coalesce-locals --code-folding --code-pushing --const-hoisting --dae-optimizing --duplicate-function-elimination --local-cse --once-reduction --optimize-for-js --optimize-instructions --optimize-stack-ir --post-emscripten --merge-blocks --merge-locals --merge-similar-functions --remove-unused-brs --remove-unused-names --remove-unused-module-elements --remove-unused-nonfunction-module-elements --reorder-locals --rse

to see if one of the existing passes would get aggressive with throwing code away when there is an unreachable on a potentially critical path. Reading the code in dead-code-elimination pass seems like it would do something like this, however I find it being unsuccessful with modifying func $17 above.

Is there a way with Binaryen to have func $17 get nuked from orbit altogether due to its unreachable, and everything that would ripple to?

Attached the .wasm file that contains func $17 if it is interesting to take a hands on peek: ozm.zip.

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 example with wasm-opt and the attached ozm.zip, then read the dead-code-elimination pass and the listed optimization passes. Determine whether an existing pass can collapse the function to unreachable and propagate that result through callers; done means documenting the supported behavior or defining the required optimizer change.

Written by the indexing model from the issue text.

Assessment

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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.