I'm trying to solve https://github.com/bytecodealliance/wasmtime/issues/6185
I can only reproduce the bug if umax is written as -1. If it is written in hexadecimal (0xFFFF_FFFF), the bug does not reproduce:
test optimize precise-output
set opt_level=speed
target x86_64
function %icmp_ule_umax(i32) -> i8 {
block0(v0: i32):
v1 = iconst.i32 0xFFFF_FFFF
v2 = icmp ule v0, v1
return v2
}
; function %icmp_ule_umax(i32) -> i8 fast {
; block0(v0: i32):
; v3 = iconst.i8 1
; return v3 ; v3 = 1
; }
function %icmp_ule_minus_1(i32) -> i8 {
block0(v0: i32):
v1 = iconst.i32 -1
v2 = icmp ule v0, v1
return v2
}
; function %icmp_ule_minus_1(i32) -> i8 fast {
; block0(v0: i32):
; v1 = iconst.i32 -1
; v2 = icmp ule v0, v1 ; v1 = -1
; return v2
; }
function %icmp_eq_umax_minus_1(i32) -> i8 {
block0(v0: i32):
v1 = iconst.i32 -1
v2 = iconst.i32 0xFFFF_FFFF
v3 = icmp eq v1, v2
return v3
}
; function %icmp_eq_umax_minus_1(i32) -> i8 fast {
; block0(v0: i32):
; v4 = iconst.i8 1
; return v4 ; v4 = 1
; }
function %foo(i32) -> i32, i32 {
block0(v0: i32):
v1 = iconst.i32 -1
v2 = iconst.i32 0xFFFF_FFFF
return v1, v2
}
; function %foo(i32) -> i32, i32 fast {
; block0(v0: i32):
; v1 = iconst.i32 -1
; v2 = iconst.i32 0xffff_ffff
; return v1, v2 ; v1 = -1, v2 = 0xffff_ffff
; }
Are integer constants sign extended during parsing or something?
Yeah, that's due to a different issue that we need to clean up :sweat_smile:
Specifically, https://github.com/bytecodealliance/wasmtime/issues/5700 and https://github.com/bytecodealliance/wasmtime/issues/3059
What I find extra confusing is that both constants are considered equal by GVN/cprop (icmp_eq_umax_minus_1) but not by the ISLE pattern matcher (icmp_ule_minus_1)
I haven't looked closely at those cases. What leads you to think that GVN behaves differently than ISLE on the same constants?
This function:
function %icmp_eq_umax_minus_1(i32) -> i8 {
block0(v0: i32):
v1 = iconst.i32 -1
v2 = iconst.i32 0xFFFF_FFFF
v3 = icmp eq v1, v2
return v3
}
is optimized to return 1. Either by GVN recognising that v1 and v2 are the same, and then a rewrite rule for icmp eq x x => 1. Or by cprop
Ah, got it. I think that's due to cprop, where I believe the rules specifically zero-extend all constants.
So the problem is that -1 and 0xFFFF_FFFF are represented differently in Imm64?
Yeah. They shouldn't be, but they are.
The parser reads both numbers as an i64 (more or less) and stuffs the result into Imm64, without any consideration for the type it's supposed to be constructing.
There are several fixes we want to make around this issue:
Imm64 according to the type of the iconst instruction.iconst instruction's type. The calling rule needs to specify whether it's expecting a signed or unsigned number since we don't distinguish between those in the CLIF type system.Nobody has started working on any of those fixes though; there are always plenty of other things to work on…
zero-extending in the parser seems like the simplest solution
It's good, yeah, but not a complete fix. Still, I'd definitely take that in a PR even without the other fixes.
I'll see what I can do
hmm...Maybe remove Imm64 and replace all uses with UImm64 and explicit sign-extensions where necessary?
That's definitely worth considering. I think fitzgen's suggestion at https://github.com/bytecodealliance/wasmtime/issues/5700#issuecomment-1421260557 is a more comprehensive version of that approach.
Last updated: Jan 10 2026 at 02:36 UTC