From e77b5aa007d0f956417982491c3284e0d1767622 Mon Sep 17 00:00:00 2001 From: John Regehr Date: Mon, 14 Sep 2026 10:18:07 -0600 Subject: [PATCH] fix --- ir/instr.cpp | 7 +++++-- .../fp/denormal-fptrunc-result-type-2.srctgt.ll | 13 +++++++++++++ .../fp/denormal-fptrunc-result-type-3.srctgt.ll | 14 ++++++++++++++ .../fp/denormal-fptrunc-result-type.srctgt.ll | 14 ++++++++++++++ 4 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 tests/alive-tv/fp/denormal-fptrunc-result-type-2.srctgt.ll create mode 100644 tests/alive-tv/fp/denormal-fptrunc-result-type-3.srctgt.ll create mode 100644 tests/alive-tv/fp/denormal-fptrunc-result-type.srctgt.ll diff --git a/ir/instr.cpp b/ir/instr.cpp index 20613c968..bc39bb267 100644 --- a/ir/instr.cpp +++ b/ir/instr.cpp @@ -849,10 +849,13 @@ static StateValue fm_poison(State &s, expr a, const expr &ap, expr b, } if (!bitwise && val.isFloat()) { + const FloatType &ty = to_ty ? *to_ty->getAsFloatType() : fpty; + // the denormal mode is per-type, so the flushing of the result is governed + // by the mode of the result's type rather than that of the operands; these + // differ for casts between floating-point types val = handle_subnormal(s, - s.getFn().getFnAttrs().getFPDenormal(from_ty).output, + s.getFn().getFnAttrs().getFPDenormal(ty).output, std::move(val)); - const FloatType &ty = to_ty ? *to_ty->getAsFloatType() : fpty; val = ty.fromFloat(s, val, fpty, nary, a, b, c); } diff --git a/tests/alive-tv/fp/denormal-fptrunc-result-type-2.srctgt.ll b/tests/alive-tv/fp/denormal-fptrunc-result-type-2.srctgt.ll new file mode 100644 index 000000000..78ebf3214 --- /dev/null +++ b/tests/alive-tv/fp/denormal-fptrunc-result-type-2.srctgt.ll @@ -0,0 +1,13 @@ +; Converse of denormal-fptrunc-result-type.srctgt.ll: the f32 result of this +; fptrunc is governed by the "float:" override even though the operand is f64, +; so the subnormal result may be flushed to +0.0. + +define float @src() denormal_fpenv(float: positivezero) { +; 0x3730000000000000 is 0x1p-140: a normal double, and a subnormal float + %v = fptrunc double 0x3730000000000000 to float + ret float %v +} + +define float @tgt() denormal_fpenv(float: positivezero) { + ret float 0.000000e+00 +} diff --git a/tests/alive-tv/fp/denormal-fptrunc-result-type-3.srctgt.ll b/tests/alive-tv/fp/denormal-fptrunc-result-type-3.srctgt.ll new file mode 100644 index 000000000..c405347a3 --- /dev/null +++ b/tests/alive-tv/fp/denormal-fptrunc-result-type-3.srctgt.ll @@ -0,0 +1,14 @@ +; ERROR: Value mismatch + +; As denormal-fptrunc-result-type-2.srctgt.ll, but "float: ieee" overrides the +; base positivezero for the f32 result type, so the result is not flushed. + +define float @src() denormal_fpenv(positivezero, float: ieee) { +; 0x3730000000000000 is 0x1p-140: a normal double, and a subnormal float + %v = fptrunc double 0x3730000000000000 to float + ret float %v +} + +define float @tgt() denormal_fpenv(positivezero, float: ieee) { + ret float 0.000000e+00 +} diff --git a/tests/alive-tv/fp/denormal-fptrunc-result-type.srctgt.ll b/tests/alive-tv/fp/denormal-fptrunc-result-type.srctgt.ll new file mode 100644 index 000000000..4be187789 --- /dev/null +++ b/tests/alive-tv/fp/denormal-fptrunc-result-type.srctgt.ll @@ -0,0 +1,14 @@ +; The denormal mode is per-type, and the flushing of an operation's result is +; governed by the mode of the *result* type, not of its operands. Here the +; "float:" override applies only to f32, so the f16 result of this fptrunc +; follows the base ieee mode and must not be flushed. + +define half @src() denormal_fpenv(float: preservesign) { + ret half 0xH0001 +} + +define half @tgt() denormal_fpenv(float: preservesign) { +; 0x3E70000000000000 is 0x1p-24: a normal float, and the smallest subnormal half + %v = fptrunc float 0x3E70000000000000 to half + ret half %v +}