Skip to content

s390x-linux miscompiles f32 std.math.hypot() #24221

Closed
@rootbeer

Description

@rootbeer

Zig Version

0.15.0-dev.847+850655f06

Steps to Reproduce and Observed Behavior

I run zig's tests locally with -fqemu and I've noticed some unusual and persistent failures on the s390x-linux target. I see failures in hypot, gamma and complex tests. I've only narrowed down the hypot one at this point, I can dig into the others if that's useful. From what I can see its just f32 floats that are failing the hypot test case, and its the "easy" test (not a boundary test case). The f16, f64, f80, and f128 floats pass. And the test passes on x86*, arm and mips at least.

// Isolated from "hypot.precise" test case in lib/std/math/hypot.zig
//
// $ zig run main.zig
// $ zig run --test-cmd qemu-s390x --test-cmd-bin -target s390x-linux main.zig

const std = @import("std");

pub fn main() !void {
    checkhypot(f16);
    checkhypot(f32);
    checkhypot(f64);
    checkhypot(f80);
    checkhypot(f128);
}

fn checkhypot(T: type) void {
    const a: T = 0.0;
    const b: T = -1.2;
    const expected: T = 1.2;
    const computed = @sqrt(a * a + b * b);

    // This is pulled from hypot.zig and should be how the 'f32' case is handled (But its fine here?)
    const computed64 = if (T == f80 or T == f128) 0 else @sqrt(@mulAdd(f64, a, a, @as(f64, b) * b));

    const actual = std.math.hypot(a, b);
    const tolerance = @sqrt(std.math.floatEps(T));
    if (! std.math.approxEqRel(T, expected, actual, tolerance)) {
        std.debug.print("FAIL: {any} a={} b={} actual={} expected={} computed={} computed64={}\n", .{
            T, a, b, actual, expected, computed, computed64
        });
    } else {
        std.debug.print("PASS: {any}\n", .{ T });
    }
}

If I run this locally (x86_64-linux) it passes:

$ zig run main.zig
PASS: f16
PASS: f32
PASS: f64
PASS: f80
PASS: f128

The s390x target just fails the f32 version:

$ zig run --test-cmd qemu-s390x --test-cmd-bin -target s390x-linux main.zig
PASS: f16
FAIL: f32 a=0e0 b=-1.2e0 actual=1.732051e-1 expected=1.2e0 computed=1.2e0 computed64=1.2000000476837158e0
PASS: f64
PASS: f80
PASS: f128

The "actual" value is very wrong compared to "expected", so its not just a floating-point tolerance issue.

This could be a qemu bug, but that seems unlikely at this point. If there are any more useful details I can squeeze out of Zig, let me know.

Expected Behavior

PASS: f32 on s390x-linux target.

Metadata

Metadata

Assignees

No one assigned

    Labels

    questionNo questions on the issue tracker, please.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions