Hacktoberfest 2026: le issue che i maintainer hanno segnato per ottobre, aperte e adatte ai principianti. Sfoglia le issue Hacktoberfest

O2 regression in optimize-instructions due to coalesceLocals

Aperta
#7,458 2 commenti 0 reazioni 0 assegnatari Vedi su GitHub

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
4/5
Tempo stimato
3-5 giorni
Idoneità per principianti
45/100
Tipo di issue
Bug
Chiarezza
Abbastanza chiara
Stato di attività
Ferma
Stack tecnologico
wasm
Ambito
compilers

Direzione di ricerca

Riproduci l’esempio WebAssembly con wasm-opt -all -O1 e -all -O2, quindi confronta l’output dopo precompute, coalesce-locals e optimize-instructions. Traccia in che modo local.tee 0 rispetto a local.tee 1 influisce sulla deduzione della condizione. Il lavoro è completato quando optimize-instructions riconosce la condizione come zero a O2 ed elimina il corpo morto di br_if senza modificare il comportamento.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

Given the following code:

(module
  (import "External" "external_function" (func $external_function))
  (func $_start
    (local $0 i32) (local $3 i32) (local $5 i32) (local $6 i32) (local $11 i32) (local $1 i32) (local $2 i32) (local $7 i32)
    loop ;; label = @1
      block ;; label = @2
        i32.const 0
        i32.load
        br_if 0 (;@2;)
        i32.const 0
        local.get $11
        i32.store
        i32.const 0
        local.set $5
        i32.const 1
        local.set $0
        i32.const 0
        local.get $0
        i32.store
        i32.const -346457217
        local.set $6
        block ;; label = @3
          local.get $0
          local.get $6
          i32.ne
          br_if 0 (;@3;)
          call $external_function
        end
        local.get $5
        i32.const 0
        i32.load
        i32.lt_s
        i32.const 0
        local.set $1
        local.get $1
        i32.shl
        drop
        local.get $1
        unreachable
      end
      i32.const 0
      i32.load
      local.set $2
      local.get $2
      local.set $3
      local.get $2
      local.get $3
      i32.store
      br 0 (;@1;)
    end)
  (memory $0 1)
  (export "_start" (func $_start)))

wasm-opt (16dbac1) can eliminate the dead br_if body by -all -O1 but cannot by -all -O2.

Analysis

The direct issue is that optimize-instructions cannot deduce the condition to zero in -all -O2 while it can in -all -O1. (further the dead if statement body will be eliminated by --vacuum)

Before optimize-instructions, that is precompute:

`-all -O1`, after `precompute`, going to `optimize-instructions`
(module
  (type (;0;) (func))
  (import "External" "external_functional" (func (;0;) (type 0)))
  (func (;1;) (type 0)
    (local i32 i32)
    loop  ;; label = @1
      i32.const 0
      i32.load
      i32.eqz
      if  ;; label = @2
        i32.const 0
        local.get 1
        i32.store
        i32.const 0
        i32.const 1
        local.tee 0
        i32.store
        local.get 0
        i32.const -346457217
        i32.eq
        if  ;; label = @3
          call 0
        end
        i32.const 0
        i32.load
        drop
        unreachable
      else
        i32.const 0
        i32.load
        local.tee 1 ;; Note this line: using variable 1, not affects condition
        local.get 1
        i32.store
        br 1 (;@1;)
      end
      unreachable
    end
    unreachable)
  (memory (;0;) 1)
  (export "_start" (func 1)))
`-all -O2`, after `precompute`, going to `optimize-instructions`
(module
  (type (;0;) (func))
  (import "External" "external_function" (func (;0;) (type 0)))
  (func (;1;) (type 0)
    (local i32 i32)
    loop  ;; label = @1
      i32.const 0
      i32.load
      i32.eqz
      if  ;; label = @2
        i32.const 0
        local.get 1
        i32.store
        i32.const 0
        i32.const 1
        local.tee 0
        i32.store
        local.get 0
        i32.const -346457217
        i32.eq
        if  ;; label = @3
          call 0
        end
        i32.const 0
        i32.load
        unreachable
      else
        i32.const 0
        i32.load
        local.tee 0 ;; Note this line: using variable 0 will affect condition deduction
        local.get 0
        i32.store
        br 1 (;@1;)
      end
      unreachable
    end
    unreachable)
  (memory (;0;) 1)
  (export "_start" (func 1)))

As you can see, the condition are the same:

(if
 (i32.eq
  (local.get $0) 
  (i32.const -346457217)
 )
 (then
  (call $external_functional)
 )
)

However, the statements in else statements are slightly different, but critical: -all -O1 uses local variable 1, while -all -O2 uses local variable 0 (local.tee 0), which I thinks maybe affect the deduction of the condition in optimize-instructions .

Continue to trace back and analyze in the optimized pipeline, the slightly but critical difference begins in coalesce-locals, which is the optimizations of Key "register allocation" pass. Does a live range analysis and then reuses locals in order to minimize their number, as well as to remove copies between them.

Although the coalesce-locals performs aggressive optimizations, I think there is missed optimization in the optimize-instructions, for it should have deduced the condition to be 0.

Lingua principale
WebAssembly
Stelle
8.6k
Fork
885
Merge medio
2g 4h
PR unite (30g)
77

Guida per i contributori

Apri la guida per i contributori

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di WebAssembly/binaryen

Tutte le issue di WebAssembly/binaryen

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.