Skip to content

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

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.

Activity

  1. llvmbot commented on Jun 23, 2024

    @llvmbot
    Member

    @llvm/issue-subscribers-backend-webassembly

    Author: None (beetrees)

    Details The following IR ([compiler explorer](https://godbolt.org/z/TbKnj8n4e)):
    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) -&gt; 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.

  2. tlively commented on Jun 27, 2024

    @tlively
    Contributor

    cc @brendandahl, this seems potentially related to your recent fp16 work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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