Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 10 additions & 7 deletions ir/instr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -728,18 +728,20 @@ static expr any_fp_zero(State &s, expr v) {
return expr::mkIf(var && is_zero, v.fneg(), v);
}

static expr handle_subnormal(State &s, FPDenormalAttrs::Type attr, expr &&v) {
static expr handle_subnormal(State &s, FPDenormalAttrs::Type attr, expr &&v,
bool mandatory) {
auto nondet = [&]() { return s.getFreshNondetVar("subnormal", true); };
auto flush = [&]() { return mandatory ? expr(true) : nondet(); };
expr subnormal = v.isFPSubNormal();

switch (attr) {
case FPDenormalAttrs::IEEE:
break;
case FPDenormalAttrs::PositiveZero:
v = expr::mkIf(subnormal && nondet(), expr::mkNumber("0", v), v);
v = expr::mkIf(subnormal && flush(), expr::mkNumber("0", v), v);
break;
case FPDenormalAttrs::PreserveSign:
v = expr::mkIf(subnormal && nondet(),
v = expr::mkIf(subnormal && flush(),
expr::mkIf(v.isFPNegative(),
expr::mkNumber("-0", v),
expr::mkNumber("0", v)),
Expand Down Expand Up @@ -816,11 +818,11 @@ static StateValue fm_poison(State &s, expr a, const expr &ap, expr b,

if (!bitwise) {
auto fpdenormal = s.getFn().getFnAttrs().getFPDenormal(from_ty).input;
fp_a = handle_subnormal(s, fpdenormal, std::move(fp_a));
fp_a = handle_subnormal(s, fpdenormal, std::move(fp_a), /*mandatory=*/true);
if (nary >= 2)
fp_b = handle_subnormal(s, fpdenormal, std::move(fp_b));
fp_b = handle_subnormal(s, fpdenormal, std::move(fp_b), /*mandatory=*/true);
if (nary >= 3)
fp_c = handle_subnormal(s, fpdenormal, std::move(fp_c));
fp_c = handle_subnormal(s, fpdenormal, std::move(fp_c), /*mandatory=*/true);
}

function<expr(const expr&)> fn_rm
Expand Down Expand Up @@ -869,7 +871,8 @@ static StateValue fm_poison(State &s, expr a, const expr &ap, expr b,
// differ for casts between floating-point types
val = handle_subnormal(s,
s.getFn().getFnAttrs().getFPDenormal(ty).output,
std::move(val));
std::move(val),
/*mandatory=*/false);
val = ty.fromFloat(s, val, fpty, nary, a, b, c);
}

Expand Down
12 changes: 12 additions & 0 deletions tests/alive-tv/fp/denormal-input-flush-preservesign.srctgt.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
; As denormal-input-flush.srctgt.ll, but preservesign keeps the sign of the
; flushed input, so the result is -inf rather than +inf.

define float @src() denormal_fpenv(ieee|preservesign) {
ret float 0xFFF0000000000000
}

define float @tgt() denormal_fpenv(ieee|preservesign) {
; 0xB800000000000000 is -0x1p-127, a negative subnormal float
%v = fdiv float 1.000000e+00, 0xB800000000000000
ret float %v
}
14 changes: 14 additions & 0 deletions tests/alive-tv/fp/denormal-input-flush.srctgt.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
; LangRef, denormal_fpenv: "If the input mode is preservesign, or
; positivezero, a floating-point operation must treat any input denormal
; value as zero." Unlike output flushing, input flushing is mandatory, so
; the fdiv below definitely sees +0.0 and definitely returns +inf.

define float @src() denormal_fpenv(ieee|positivezero) {
ret float 0x7FF0000000000000
}

define float @tgt() denormal_fpenv(ieee|positivezero) {
; 0xB800000000000000 is -0x1p-127, a negative subnormal float
%v = fdiv float 1.000000e+00, 0xB800000000000000
ret float %v
}
17 changes: 17 additions & 0 deletions tests/alive-tv/fp/denormal-output-flush-not-mandated.srctgt.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
; ERROR: Value mismatch

; The mirror image of denormal-input-flush.srctgt.ll: LangRef says of the
; output mode that "It is not mandated that flushing to zero occurs", so a
; denormal result may or may not be flushed. The target may return a subnormal,
; so it is not a refinement of the source, which always returns zero.

define float @src() denormal_fpenv(positivezero|ieee) {
ret float 0.000000e+00
}

define float @tgt() denormal_fpenv(positivezero|ieee) {
; 0x3810000000000000 is 0x1p-126, the smallest normal float; halving it
; produces a subnormal result
%v = fdiv float 0x3810000000000000, 2.000000e+00
ret float %v
}
18 changes: 18 additions & 0 deletions tests/alive-tv/fp/is_fpclass-denormal-dapz.srctgt.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
; llvm/test/Transforms/InstCombine/is_fpclass.ll,
; @test_class_is_p0_n0_psub_nsub_f32_dapz
;
; Under an input denormal mode of positivezero, a subnormal operand of the
; fcmp is treated as +0.0, so "x is zero or subnormal" is exactly "x == 0".
; llvm.is.fpclass itself classifies the unflushed value.

define i1 @src(float %x) denormal_fpenv(ieee|positivezero) {
%val = call i1 @llvm.is.fpclass.f32(float %x, i32 240)
ret i1 %val
}

define i1 @tgt(float %x) denormal_fpenv(ieee|positivezero) {
%val = fcmp oeq float %x, 0.000000e+00
ret i1 %val
}

declare i1 @llvm.is.fpclass.f32(float, i32 immarg)
Loading