Stream: git-wasmtime

Topic: wasmtime / issue #14566 Cranelift: `(x >> k) << k` mid-en...


view this post on Zulip Wasmtime GitHub notifications bot (Oct 06 2026 at 15:00):

fitzgen commented on issue #14566:

<details><summary>Full LLM report</summary>

(x >> k) << k mid-end rule emits an iconst with a 64-bit vector type

Date 2026-10-05
Wasmtime commit 73b04cff3317d1e308866eb24359483ac6116669 (main)
Host macOS 15.8.1 (Darwin 24.6.0), aarch64-apple-darwin
Model Claude Opus 5.5 (claude-opus-5-5)
Component cranelift/codegen/src/opts/shifts.isle (mid-end, opt_level=speed)
Class Compiler panic on valid CLIF
Severity Low. Wasm has no 64-bit vector types, so Wasmtime cannot reach this; other Cranelift embedders and cranelift-fuzzgen can.

Summary

cranelift/codegen/src/opts/shifts.isle:27-36:

(rule (simplify (ishl (fits_in_64 ty)
                      (ushr ty x (iconst _ k))
                      (iconst _ k)))
      (let ((mask Imm64 (imm64_shl ty (imm64 0xFFFF_FFFF_FFFF_FFFF) k)))
        (band ty x (iconst ty mask))))
;; ... and the same for `sshr`

fits_in_64 only checks ty.bits() <= 64, so it also admits the 64-bit vector
types i8x8, i16x4 and i32x2. For those the rule builds
iconst.i32x2 <mask>, which is not valid CLIF: iconst is scalar-only.

What happens next depends on the verifier:

The mask would also be wrong for vectors. imm64_shl
(isle_prelude.rs:223) masks with ty.bits(), the vector's total width,
rather than the lane width.

The neighbouring rule at shifts.isle:41 gets this right. It uses
(fits_in_64 (ty_int ty)), and its comment says "this iconst mask only
works for scalar integers". These two rules date from b9a58148cf (2023).

Reproduction

All files are in this directory. Run them with the debug clif-util built from
the audited commit.

$ clif-util test repro-riscv64-none.clif     # opt_level=none, riscv64 has_v: passes
$ clif-util test repro-riscv64.clif          # same functions at opt_level=speed
thread 'worker #0' panicked at cranelift/codegen/src/verifier/mod.rs:1936:22:
internal error: entered unreachable code
$ clif-util test repro.clif                  # aarch64, speed: same verifier panic
$ clif-util test repro-noverify.clif         # aarch64, verifier off
panicked at .../isle_aarch64.rs:7859:5: internal error: entered unreachable code:
no rule matched for term imm at src/isa/aarch64/inst.isle line 3737; should it be partial?
$ clif-util test optimize.clif               # `; check: iconst.i32x2` passes
$ clif-util test interpret.clif              # reference semantics, passes:
#   i32x2 [0xffffffff 0x12345678] -> [0xfffffff8 0x12345678]
#   i16x4 [-1 5 7 0x7fff]         -> [-4 4 4 0x7ffc]

repro-riscv64.clif contains:

test compile
set opt_level=speed
target riscv64 has_v

function %f(i64) -> i64 {
block0(v0: i64):
    v1 = bitcast.i32x2 little v0
    v2 = iconst.i32 3
    v3 = ushr v1, v2
    v4 = ishl v3, v2
    v5 = bitcast.i64 little v4
    return v5
}

riscv64 gives the clean before/after comparison: it compiles this function at
opt_level=none and panics only at speed. aarch64 cannot lower 64-bit vector
shifts even at opt_level=none.

Several neighbouring cases do not fail:

Suggested fix

</summary>

view this post on Zulip Wasmtime GitHub notifications bot (Oct 06 2026 at 15:04):

fitzgen opened issue #14566:

The rules in opts/shifts.isle that rewrite (x >> k) << k into
band x, (iconst ty mask) are guarded by (fits_in_64 ty). That guard also
admits i8x8, i16x4 and i32x2, so the rewrite produces an ill-typed
iconst.i32x2. The verifier then hits unreachable!() in iconst_bounds
instead of reporting an error. With the verifier disabled, the backend
panics in ISLE.

.clif Test Case

test compile
set opt_level=speed
target riscv64 has_v

function %f(i64) -> i64 {
block0(v0: i64):
    v1 = bitcast.i32x2 little v0
    v2 = iconst.i32 3
    v3 = ushr v1, v2
    v4 = ishl v3, v2
    v5 = bitcast.i64 little v4
    return v5
}

Steps to Reproduce

clif-util test test.clif

Expected Results

The function compiles, as it does with opt_level=none.

Actual Results

thread 'worker #0' panicked at cranelift/codegen/src/verifier/mod.rs:1936:22:
internal error: entered unreachable code

Versions and Environment

Cranelift version or commit: 73b04cff33

Operating system: macOS 15.8.1

Architecture: aarch64 (host), riscv64 (target)

view this post on Zulip Wasmtime GitHub notifications bot (Oct 06 2026 at 15:04):

fitzgen added the bug label to Issue #14566.

view this post on Zulip Wasmtime GitHub notifications bot (Oct 06 2026 at 15:04):

fitzgen added the isle label to Issue #14566.

view this post on Zulip Wasmtime GitHub notifications bot (Oct 06 2026 at 15:04):

fitzgen added the cranelift:mid-end label to Issue #14566.

view this post on Zulip Wasmtime GitHub notifications bot (Oct 09 2026 at 21:56):

cfallin closed issue #14566:

The rules in opts/shifts.isle that rewrite (x >> k) << k into
band x, (iconst ty mask) are guarded by (fits_in_64 ty). That guard also
admits i8x8, i16x4 and i32x2, so the rewrite produces an ill-typed
iconst.i32x2. The verifier then hits unreachable!() in iconst_bounds
instead of reporting an error. With the verifier disabled, the backend
panics in ISLE.

.clif Test Case

test compile
set opt_level=speed
target riscv64 has_v

function %f(i64) -> i64 {
block0(v0: i64):
    v1 = bitcast.i32x2 little v0
    v2 = iconst.i32 3
    v3 = ushr v1, v2
    v4 = ishl v3, v2
    v5 = bitcast.i64 little v4
    return v5
}

Steps to Reproduce

clif-util test test.clif

Expected Results

The function compiles, as it does with opt_level=none.

Actual Results

thread 'worker #0' panicked at cranelift/codegen/src/verifier/mod.rs:1936:22:
internal error: entered unreachable code

Versions and Environment

Cranelift version or commit: 73b04cff33

Operating system: macOS 15.8.1

Architecture: aarch64 (host), riscv64 (target)


Last updated: Oct 11 2026 at 04:10 UTC