Skip to content

On wasm32, half operation results aren't correctly rounded between each operation #96437

Open
@beetrees

Description

@beetrees

The following IR (compiler explorer):

target triple = "wasm32-unknown-wasi"

define half @f(half %x) {
start:
  %y = fmul half %x, 0xH4000 ; 0xH4000 == 2.0
  %z = fdiv half %y, 0xH4000 ; 0xH4000 == 2.0
  ret half %z
}

define half @callf() {
    %res = call half @f(half 0xH7BFF)  ; 0xH7BFF = maximum finite `f16`
    ret half %res
}

Is compiled into the following WASM:

f:                                      # @f
        local.get       0
        call    __truncsfhf2
        call    __extendhfsf2
        local.tee       0
        local.get       0
        f32.add 
        f32.const       0x1p-1
        f32.mul 
        end_function
callf:                                  # @callf
        f32.const       0x1.ffcp15
        call    f
        end_function

callf should return positive infinity (0xH7C00), but on WASM it will return 0xH7BFF due to the extra range of the f32 used to store the intermediate result.

This Rust program, when compiled with rustc 1.81.0-nightly (3cb521a43 2024-06-22) with rustc --target wasm32-wasip1 code.rs and run with wasmtime, demonstrates the issue.

#![feature(f16)]

fn f(x: f16) -> f16 {
	x * 2.0 / 2.0
}

fn main() {
	assert_eq!(f(f16::MAX), 1.0 / 0.0);
}

The assertion should succeed, but on WASM it fails.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions