Stream: git-wasmtime

Topic: wasmtime / issue #10941 Optimize control-flow-y condition...


view this post on Zulip Wasmtime GitHub notifications bot (Jun 05 2025 at 22:10):

fitzgen opened issue #10941:

Wasm does not have conditional trap instructions, just control flow and unconditional traps. CLIF does have conditional trap instructions, but we do not translate the control-flow-y Wasm equivalent into these single conditionally-trapping instructions. This is unfortunate because Cranelift's mid-end cannot currently turn control-flow-y conditional traps into single trap[n]z instructions either, but the single instructions allow the optimizer to do more and also ultimately get better codegen in the backend.

I'm sure that conditional traps show up frequently in real Wasm code. They additionally show up frequently in the fused adapters we generate when linking components together.

Might be worth identifying blocks that contain a single unconditional trap instruction and rewrite conditional branches to these blocks during egraph construction or something.

https://github.com/bytecodealliance/wasmtime/pull/10940 introduced the following disas tests that highlight the problem:

(module
  ;; This function body should ideally get compiled down into a single `trapz`
  ;; CLIF instruction.
  (func (export "trapnz") (param i32)
    local.get 0
    if
      unreachable
    end
  )

  ;; And this one into a single `trapnz` instruction.
  (func (export "trapz") (param i32)
    local.get 0
    i32.eqz
    if
      unreachable
    end
  )
)

;; function u0:0(i64 vmctx, i64, i32) tail {
;;     gv0 = vmctx
;;     gv1 = load.i64 notrap aligned readonly gv0+8
;;     gv2 = load.i64 notrap aligned gv1+16
;;     stack_limit = gv2
;;
;;                                 block0(v0: i64, v1: i64, v2: i32):
;; @002f                               brif v2, block2, block3
;;
;;                                 block2:
;; @0031                               trap user11
;;
;;                                 block3:
;; @0033                               jump block1
;;
;;                                 block1:
;; @0033                               return
;; }
;;
;; function u0:1(i64 vmctx, i64, i32) tail {
;;     gv0 = vmctx
;;     gv1 = load.i64 notrap aligned readonly gv0+8
;;     gv2 = load.i64 notrap aligned gv1+16
;;     stack_limit = gv2
;;
;;                                 block0(v0: i64, v1: i64, v2: i32):
;;                                     v5 = iconst.i32 0
;; @0038                               v3 = icmp eq v2, v5  ; v5 = 0
;; @0038                               v4 = uextend.i32 v3
;; @0039                               brif v4, block2, block3
;;
;;                                 block2:
;; @003b                               trap user11
;;
;;                                 block3:
;; @003d                               jump block1
;;
;;                                 block1:
;; @003d                               return
;; }

view this post on Zulip Wasmtime GitHub notifications bot (Jun 05 2025 at 22:11):

fitzgen added the cranelift:goal:optimize-speed label to Issue #10941.

view this post on Zulip Wasmtime GitHub notifications bot (Jun 05 2025 at 22:11):

fitzgen added the wasm-proposal:component-model label to Issue #10941.

view this post on Zulip Wasmtime GitHub notifications bot (Jun 06 2025 at 22:10):

fitzgen assigned fitzgen to issue #10941.

view this post on Zulip Wasmtime GitHub notifications bot (Jun 09 2025 at 20:37):

fitzgen closed issue #10941:

Wasm does not have conditional trap instructions, just control flow and unconditional traps. CLIF does have conditional trap instructions, but we do not translate the control-flow-y Wasm equivalent into these single conditionally-trapping instructions. This is unfortunate because Cranelift's mid-end cannot currently turn control-flow-y conditional traps into single trap[n]z instructions either, but the single instructions allow the optimizer to do more and also ultimately get better codegen in the backend.

I'm sure that conditional traps show up frequently in real Wasm code. They additionally show up frequently in the fused adapters we generate when linking components together.

Might be worth identifying blocks that contain a single unconditional trap instruction and rewrite conditional branches to these blocks during egraph construction or something.

https://github.com/bytecodealliance/wasmtime/pull/10940 introduced the following disas tests that highlight the problem:

(module
  ;; This function body should ideally get compiled down into a single `trapz`
  ;; CLIF instruction.
  (func (export "trapnz") (param i32)
    local.get 0
    if
      unreachable
    end
  )

  ;; And this one into a single `trapnz` instruction.
  (func (export "trapz") (param i32)
    local.get 0
    i32.eqz
    if
      unreachable
    end
  )
)

;; function u0:0(i64 vmctx, i64, i32) tail {
;;     gv0 = vmctx
;;     gv1 = load.i64 notrap aligned readonly gv0+8
;;     gv2 = load.i64 notrap aligned gv1+16
;;     stack_limit = gv2
;;
;;                                 block0(v0: i64, v1: i64, v2: i32):
;; @002f                               brif v2, block2, block3
;;
;;                                 block2:
;; @0031                               trap user11
;;
;;                                 block3:
;; @0033                               jump block1
;;
;;                                 block1:
;; @0033                               return
;; }
;;
;; function u0:1(i64 vmctx, i64, i32) tail {
;;     gv0 = vmctx
;;     gv1 = load.i64 notrap aligned readonly gv0+8
;;     gv2 = load.i64 notrap aligned gv1+16
;;     stack_limit = gv2
;;
;;                                 block0(v0: i64, v1: i64, v2: i32):
;;                                     v5 = iconst.i32 0
;; @0038                               v3 = icmp eq v2, v5  ; v5 = 0
;; @0038                               v4 = uextend.i32 v3
;; @0039                               brif v4, block2, block3
;;
;;                                 block2:
;; @003b                               trap user11
;;
;;                                 block3:
;; @003d                               jump block1
;;
;;                                 block1:
;; @003d                               return
;; }


Last updated: Dec 06 2025 at 07:03 UTC