Stream: git-wasmtime

Topic: wasmtime / issue #14660 Cranelift: x86_64 lowering `i8` m...


view this post on Zulip Wasmtime GitHub notifications bot (Oct 11 2026 at 19:05):

Takashiidobe opened issue #14660:

Feature

On x86-64, imul.i8 x, <const> lowers to mulb,. i16, i32 and i64 use the three-operand immediate form (imul $c, x, dst). i8 should use it too.

For example, rustc_codegen_cranelift with this rust:

#[unsafe(no_mangle)]
pub fn mul_i8_3(x: i8) -> i8 {
    x.wrapping_mul(3)
}

emits this optimized clif:

function u0:0(i8) -> i8 system_v {
block0(v0: i8):
    v2 = iconst.i8 3
    v3 = imul.i8 v0, v2
    return v3
}

which lowers to:

mov    %rdi, %rax
mulb   0xa(%rip)        ; constant 3 in the constant pool, after `ret`

in comparison, LLVM uses lea:

lea    (%rdi,%rdi,2), %eax

Given #13325, and https://github.com/bytecodealliance/wasmtime/pull/14015#issuecomment-5196211320, and some of my own exp in llvm, where lea is cognitively demanding to remember the subtargets for (slow lea, fast lea subtargets, having to maintain the subtargets and also benchmarking them), I assume cranelift would prefer a non lea lowering, which should be an imul?

So that would be:

imul $3, %edit, %eax

Benefit

llvm-mca says this would be:

instructions Skylake cycles Zen4 cycles
Cranelift now 2 11 10
w/o lea 1 6 6
llvm's lea 1 4 5

Implementation

I think this should require a base rule in isa/x64/lower.isle that turns i8 times constant into the imul form, which i'm guessing is the case because of line 1093 which has the same rules but flipped right above?

Something like this?

(rule -2 (lower (imul $I8 x (i32_from_iconst y)))
         (x64_imul_imm $I32 x y))
(rule 2 (lower (imul $I8 (i32_from_iconst x) y))
         (x64_imul_imm $I32 y x))

I do find it a bit odd though to have to special case this just for i8 when the ty_int_ref_16_to_64 case handles this, and I'm not keen on having to write the same rule but mirrored, so maybe having a different rule, ty_int_ref_8_to_64 would make the diff in lower.isle smaller.

diff --git a/cranelift/codegen/src/isa/x64/lower.isle b/cranelift/codegen/src/isa/x64/lower.isle
index dc5c3169cc..4272851de3 100644
--- a/cranelift/codegen/src/isa/x64/lower.isle
+++ b/cranelift/codegen/src/isa/x64/lower.isle
@@ -1090,9 +1090,9 @@
          (x64_imul ty y x))

 ;; Lift out constants to use 3-operand form.
-(rule -4 (lower (imul (ty_int_ref_16_to_64 ty) x (i32_from_iconst y)))
+(rule -4 (lower (imul (ty_int_ref_8_to_64 ty) x (i32_from_iconst y)))
          (x64_imul_imm ty x y))
-(rule -3 (lower (imul (ty_int_ref_16_to_64 ty) (i32_from_iconst x) y))
+(rule -3 (lower (imul (ty_int_ref_8_to_64 ty) (i32_from_iconst x) y))
          (x64_imul_imm ty y x))

 ;; Special case widening multiplication from 8-to-16-bits with a single

I'm assuming it's also fair to change the rule to fits_in_64 (ty_int ty)??

Alternatives

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

alexcrichton added the enhancement label to Issue #14660.

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

alexcrichton added the cranelift:area:x64 label to Issue #14660.


Last updated: Oct 31 2026 at 23:03 UTC