Skip to content

Commit

Permalink
[builtins] Divide shouldn't underflow if rounded result would be normal.
Browse files Browse the repository at this point in the history
We were treating certain edge cases that are actually normal as denormal
results, and flushing them to zero; we shouldn't do that. Not sure this
is the cleanest way to implement this edge case, but I wanted to avoid
adding any code on the common path.

Differential Revision: https://reviews.llvm.org/D59070

llvm-svn: 356529
  • Loading branch information
efriedma-quic committed Mar 19, 2019
1 parent 4d03bbb commit d674d96
Show file tree
Hide file tree
Showing 6 changed files with 133 additions and 2 deletions.
12 changes: 12 additions & 0 deletions compiler-rt/lib/builtins/divdf3.c
Expand Up @@ -162,6 +162,18 @@ __divdf3(fp_t a, fp_t b) {
}

else if (writtenExponent < 1) {
if (writtenExponent == 0) {
// Check whether the rounded result is normal.
const bool round = (residual << 1) > bSignificand;
// Clear the implicit bit.
rep_t absResult = quotient & significandMask;
// Round.
absResult += round;
if (absResult & ~significandMask) {
// The rounded result is normal; return it.
return fromRep(absResult | quotientSign);
}
}
// Flush denormals to zero. In the future, it would be nice to add
// code to round them correctly.
return fromRep(quotientSign);
Expand Down
12 changes: 12 additions & 0 deletions compiler-rt/lib/builtins/divsf3.c
Expand Up @@ -147,6 +147,18 @@ __divsf3(fp_t a, fp_t b) {
}

else if (writtenExponent < 1) {
if (writtenExponent == 0) {
// Check whether the rounded result is normal.
const bool round = (residual << 1) > bSignificand;
// Clear the implicit bit.
rep_t absResult = quotient & significandMask;
// Round.
absResult += round;
if (absResult & ~significandMask) {
// The rounded result is normal; return it.
return fromRep(absResult | quotientSign);
}
}
// Flush denormals to zero. In the future, it would be nice to add
// code to round them correctly.
return fromRep(quotientSign);
Expand Down
12 changes: 12 additions & 0 deletions compiler-rt/lib/builtins/divtf3.c
Expand Up @@ -181,6 +181,18 @@ COMPILER_RT_ABI fp_t __divtf3(fp_t a, fp_t b) {
return fromRep(infRep | quotientSign);
}
else if (writtenExponent < 1) {
if (writtenExponent == 0) {
// Check whether the rounded result is normal.
const bool round = (residual << 1) > bSignificand;
// Clear the implicit bit.
rep_t absResult = quotient & significandMask;
// Round.
absResult += round;
if (absResult & ~significandMask) {
// The rounded result is normal; return it.
return fromRep(absResult | quotientSign);
}
}
// Flush denormals to zero. In the future, it would be nice to add
// code to round them correctly.
return fromRep(quotientSign);
Expand Down
45 changes: 45 additions & 0 deletions compiler-rt/test/builtins/Unit/divdf3_test.c
@@ -0,0 +1,45 @@
// RUN: %clang_builtins %s %librt -o %t && %run %t
//===--------------- divdf3_test.c - Test __divdf3 ------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file tests __divdf3 for the compiler_rt library.
//
//===----------------------------------------------------------------------===//

#include "int_lib.h"
#include <stdio.h>

#include "fp_test.h"

// Returns: a / b
COMPILER_RT_ABI double __divdf3(double a, double b);

int test__divdf3(double a, double b, uint64_t expected)
{
double x = __divdf3(a, b);
int ret = compareResultD(x, expected);

if (ret){
printf("error in test__divdf3(%.20e, %.20e) = %.20e, "
"expected %.20e\n", a, b, x,
fromRep64(expected));
}
return ret;
}

int main()
{
// 1/3
if (test__divdf3(1., 3., 0x3fd5555555555555ULL))
return 1;
// smallest normal result
if (test__divdf3(4.450147717014403e-308, 2., 0x10000000000000ULL))
return 1;

return 0;
}
45 changes: 45 additions & 0 deletions compiler-rt/test/builtins/Unit/divsf3_test.c
@@ -0,0 +1,45 @@
// RUN: %clang_builtins %s %librt -o %t && %run %t
//===--------------- divsf3_test.c - Test __divsf3 ------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file tests __divsf3 for the compiler_rt library.
//
//===----------------------------------------------------------------------===//

#include "int_lib.h"
#include <stdio.h>

#include "fp_test.h"

// Returns: a / b
COMPILER_RT_ABI float __divsf3(float a, float b);

int test__divsf3(float a, float b, uint32_t expected)
{
float x = __divsf3(a, b);
int ret = compareResultF(x, expected);

if (ret){
printf("error in test__divsf3(%.20e, %.20e) = %.20e, "
"expected %.20e\n", a, b, x,
fromRep32(expected));
}
return ret;
}

int main()
{
// 1/3
if (test__divsf3(1.f, 3.f, 0x3EAAAAABU))
return 1;
// smallest normal result
if (test__divsf3(2.3509887e-38, 2., 0x00800000U))
return 1;

return 0;
}
9 changes: 7 additions & 2 deletions compiler-rt/test/builtins/Unit/divtf3_test.c
Expand Up @@ -28,8 +28,8 @@ int test__divtf3(long double a, long double b,
int ret = compareResultLD(x, expectedHi, expectedLo);

if (ret){
printf("error in test__divtf3(%.20Lf, %.20Lf) = %.20Lf, "
"expected %.20Lf\n", a, b, x,
printf("error in test__divtf3(%.20Le, %.20Le) = %.20Le, "
"expected %.20Le\n", a, b, x,
fromRep128(expectedHi, expectedLo));
}
return ret;
Expand Down Expand Up @@ -86,6 +86,11 @@ int main()
UINT64_C(0x50bf2e02f0798d36),
UINT64_C(0x5e6fcb6b60044078)))
return 1;
if (test__divtf3(6.72420628622418701252535563464350521E-4932L,
2.L,
UINT64_C(0x0001000000000000),
UINT64_C(0)))
return 1;

#else
printf("skipped\n");
Expand Down

0 comments on commit d674d96

Please sign in to comment.