Skip to content

Optimize control-flow-y conditional traps into single CLIF trapnz instructions #10941

@fitzgen

Description

@fitzgen

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.

#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
;; }

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions