Skip to content

Commit 4cdc19b

Browse files
authored
[flang] IEEE_NEXT_AFTER, IEEE_NEXT_DOWN, IEEE_NEXT_UP, NEAREST (#100782)
IEEE_ARITHMETIC intrinsic module procedures IEEE_NEXT_AFTER, IEEE_NEXT_DOWN, and IEEE_NEXT_UP, and intrinsic NEAREST return larger or smaller values adjacent to their primary REAL argument. The four procedures vary in how the direction is chosen, in how special cases are treated, and in what exceptions are generated. Implement the three IEEE_ARITHMETIC procedures. Update the NEAREST implementation to support all six REAL kinds 2,3,4,8,10,16, and fix several bugs. IEEE_NEXT_AFTER(X,Y) returns a NaN when Y is a NaN as that seems to be the universal choice of other compilers. Change the front end compile time implementation of these procedures to return normal (HUGE) values for infinities when applicable, rather than always returning the input infinity.
1 parent e6fa09f commit 4cdc19b

File tree

13 files changed

+949
-195
lines changed

13 files changed

+949
-195
lines changed

flang/include/flang/Optimizer/Builder/IntrinsicCall.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,8 @@ struct IntrinsicLibrary {
330330
mlir::Value genModulo(mlir::Type, llvm::ArrayRef<mlir::Value>);
331331
void genMoveAlloc(llvm::ArrayRef<fir::ExtendedValue>);
332332
void genMvbits(llvm::ArrayRef<fir::ExtendedValue>);
333+
enum class NearestProc { Nearest, NextAfter, NextDown, NextUp };
334+
template <NearestProc>
333335
mlir::Value genNearest(mlir::Type, llvm::ArrayRef<mlir::Value>);
334336
mlir::Value genNint(mlir::Type, llvm::ArrayRef<mlir::Value>);
335337
fir::ExtendedValue genNorm2(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
@@ -422,9 +424,12 @@ struct IntrinsicLibrary {
422424
mlir::Type resultType,
423425
llvm::ArrayRef<fir::ExtendedValue> args);
424426

425-
/// Generate code to raise \p except if \p cond is absent,
427+
/// Generate code to raise \p excepts if \p cond is absent,
426428
/// or present and true.
427-
void genRaiseExcept(int except, mlir::Value cond = {});
429+
void genRaiseExcept(int excepts, mlir::Value cond = {});
430+
431+
/// Generate a quiet NaN of a given floating point type.
432+
mlir::Value genQNan(mlir::Type resultType);
428433

429434
/// Define the different FIR generators that can be mapped to intrinsic to
430435
/// generate the related code.

flang/include/flang/Optimizer/Builder/Runtime/Exceptions.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@ class FirOpBuilder;
2121

2222
namespace fir::runtime {
2323

24-
/// Generate a runtime call to map an ieee_flag_type exception value to a
25-
/// libm fenv.h value.
26-
mlir::Value genMapException(fir::FirOpBuilder &builder, mlir::Location loc,
27-
mlir::Value except);
24+
/// Generate a runtime call to map a set of ieee_flag_type exceptions to a
25+
/// libm fenv.h excepts value.
26+
mlir::Value genMapExcept(fir::FirOpBuilder &builder, mlir::Location loc,
27+
mlir::Value excepts);
2828

2929
} // namespace fir::runtime
3030
#endif // FORTRAN_OPTIMIZER_BUILDER_RUNTIME_EXCEPTIONS_H

flang/include/flang/Runtime/exceptions.h

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
#define FORTRAN_RUNTIME_EXCEPTIONS_H_
1313

1414
#include "flang/Runtime/entry-names.h"
15-
#include "flang/Runtime/magic-numbers.h"
1615
#include <cinttypes>
1716

1817
namespace Fortran::runtime {
@@ -21,11 +20,9 @@ class Descriptor;
2120

2221
extern "C" {
2322

24-
// Map a (single) IEEE_FLAG_TYPE exception value to a libm fenv.h value.
25-
// This could be extended to handle sets of exceptions, but there is no
26-
// current use case for that. This mapping is done at runtime to support
27-
// cross compilation.
28-
std::int32_t RTNAME(MapException)(std::int32_t except);
23+
// Map a set of IEEE_FLAG_TYPE exception values to a libm fenv.h excepts value.
24+
// This mapping is done at runtime to support cross compilation.
25+
std::uint32_t RTNAME(MapException)(std::uint32_t excepts);
2926

3027
} // extern "C"
3128
} // namespace Fortran::runtime

flang/include/flang/Runtime/magic-numbers.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,10 @@ The denorm value is a nonstandard extension.
100100
#define _FORTRAN_RUNTIME_IEEE_OVERFLOW 8
101101
#define _FORTRAN_RUNTIME_IEEE_UNDERFLOW 16
102102
#define _FORTRAN_RUNTIME_IEEE_INEXACT 32
103+
#define _FORTRAN_RUNTIME_IEEE_ALL \
104+
_FORTRAN_RUNTIME_IEEE_INVALID | _FORTRAN_RUNTIME_IEEE_DENORM | \
105+
_FORTRAN_RUNTIME_IEEE_DIVIDE_BY_ZERO | _FORTRAN_RUNTIME_IEEE_OVERFLOW | \
106+
_FORTRAN_RUNTIME_IEEE_UNDERFLOW | _FORTRAN_RUNTIME_IEEE_INEXACT
103107

104108
#if 0
105109
ieee_round_type values

flang/lib/Evaluate/real.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -330,12 +330,12 @@ ValueWithRealFlags<Real<W, P>> Real<W, P>::SQRT(Rounding rounding) const {
330330
template <typename W, int P>
331331
ValueWithRealFlags<Real<W, P>> Real<W, P>::NEAREST(bool upward) const {
332332
ValueWithRealFlags<Real> result;
333+
bool isNegative{IsNegative()};
333334
if (IsFinite()) {
334335
Fraction fraction{GetFraction()};
335336
int expo{Exponent()};
336337
Fraction one{1};
337338
Fraction nearest;
338-
bool isNegative{IsNegative()};
339339
if (upward != isNegative) { // upward in magnitude
340340
auto next{fraction.AddUnsigned(one)};
341341
if (next.carry) {
@@ -359,6 +359,8 @@ ValueWithRealFlags<Real<W, P>> Real<W, P>::NEAREST(bool upward) const {
359359
}
360360
}
361361
result.flags = result.value.Normalize(isNegative, expo, nearest);
362+
} else if (IsInfinite() && upward == isNegative) {
363+
result.value = isNegative ? HUGE().Negate() : HUGE(); // largest mag finite
362364
} else {
363365
result.flags.set(RealFlag::InvalidArgument);
364366
result.value = *this;

0 commit comments

Comments
 (0)