Hacktoberfest 2026: los issues que los mantenedores marcaron para octubre, abiertos y aptos para principiantes. Explorar issues de Hacktoberfest

O2 regression in optimize-instructions due to coalesceLocals

Abierto
#7,458 2 comentarios 0 reacciones 0 asignados Ver en GitHub

Nadie ha tomado este issue todavía.

Evaluación

Dificultad
4/5
Tiempo estimado
3-5 días
Aptitud para principiantes
45/100
Tipo de issue
Error
Claridad
Bastante claro
Estado de actividad
Estancado
Stack tecnológico
wasm
Área
compilers

Línea de trabajo

Reproduce el ejemplo de WebAssembly con wasm-opt -all -O1 y -all -O2, y luego compara la salida después de precompute, coalesce-locals y optimize-instructions. Rastrea cómo local.tee 0 frente a local.tee 1 afecta a la deducción de la condición. Se considera terminado cuando optimize-instructions reconoce la condición como cero en O2 y elimina el cuerpo muerto de br_if sin cambiar el comportamiento.

Escrito por el modelo de indexación a partir del texto del issue.

Descripción

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.

Lenguaje dominante
WebAssembly
Estrellas
8.6k
Forks
885
Merge medio
2 d 4 h
PR fusionados (30 d)
77

Guía de contribución

Abrir la guía de contribución

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Más de WebAssembly/binaryen

Todos los issues de WebAssembly/binaryen

Issues similares

Más issues de Compilers

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.