forked from OSchip/llvm-project
[flang] fold real**int
Original-commit: flang-compiler/f18@2dc2c2a6a5 Reviewed-on: https://github.com/flang-compiler/f18/pull/162 Tree-same-pre-rewrite: false
This commit is contained in:
parent
b9631a5d74
commit
bd146ed3e8
|
@ -13,6 +13,7 @@
|
|||
// limitations under the License.
|
||||
|
||||
#include "expression.h"
|
||||
#include "int-power.h"
|
||||
#include "variable.h"
|
||||
#include "../common/idioms.h"
|
||||
#include "../parser/characters.h"
|
||||
|
@ -471,7 +472,13 @@ template<int KIND>
|
|||
auto RealExpr<KIND>::IntPower::FoldScalar(FoldingContext &context,
|
||||
const Scalar &a, const ScalarConstant<Category::Integer> &b)
|
||||
-> std::optional<Scalar> {
|
||||
return {}; // TODO
|
||||
return std::visit(
|
||||
[&](const auto &pow) -> std::optional<Scalar> {
|
||||
auto power{evaluate::IntPower(a, pow)};
|
||||
RealFlagWarnings(context, power.flags, "raising to integer power");
|
||||
return {std::move(power.value)};
|
||||
},
|
||||
b.u);
|
||||
}
|
||||
|
||||
template<int KIND>
|
||||
|
@ -504,7 +511,6 @@ auto RealExpr<KIND>::AIMAG::FoldScalar(
|
|||
return {z.AIMAG()};
|
||||
}
|
||||
|
||||
// TODO: generalize over Expr<A> rather than instantiating same for each
|
||||
template<int KIND>
|
||||
auto RealExpr<KIND>::Fold(FoldingContext &context) -> std::optional<Scalar> {
|
||||
return std::visit(
|
||||
|
@ -516,7 +522,11 @@ auto RealExpr<KIND>::Fold(FoldingContext &context) -> std::optional<Scalar> {
|
|||
if constexpr (evaluate::FoldableTrait<Ty>) {
|
||||
auto c{x.Fold(context)};
|
||||
if (c.has_value()) {
|
||||
u_ = *c;
|
||||
if (context.flushDenormalsToZero && c->IsDenormal()) {
|
||||
u_ = Scalar{};
|
||||
} else {
|
||||
u_ = *c;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@ CLASS_TRAIT(FoldableTrait);
|
|||
struct FoldingContext {
|
||||
parser::ContextualMessages &messages;
|
||||
Rounding rounding{Rounding::TiesToEven};
|
||||
bool flushDenormalsToZero{false};
|
||||
};
|
||||
|
||||
// Helper base classes for packaging subexpressions.
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
// Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef FORTRAN_EVALUATE_INT_POWER_H_
|
||||
#define FORTRAN_EVALUATE_INT_POWER_H_
|
||||
|
||||
// Computes an integer power of a real or complex value.
|
||||
|
||||
#include "common.h"
|
||||
|
||||
namespace Fortran::evaluate {
|
||||
|
||||
template<typename REAL, typename INT>
|
||||
ValueWithRealFlags<REAL> IntPower(const REAL &base, const INT &power,
|
||||
Rounding rounding = Rounding::TiesToEven) {
|
||||
REAL one{REAL::FromInteger(INT{1}).value};
|
||||
ValueWithRealFlags<REAL> result;
|
||||
result.value = one;
|
||||
if (base.IsNotANumber()) {
|
||||
result.value = REAL::NaN();
|
||||
if (base.IsSignalingNaN()) {
|
||||
result.flags.set(RealFlag::InvalidArgument);
|
||||
}
|
||||
} else if (power.IsZero()) {
|
||||
if (base.IsZero() || base.IsInfinite()) {
|
||||
result.flags.set(RealFlag::InvalidArgument);
|
||||
}
|
||||
} else {
|
||||
bool negativePower{power.IsNegative()};
|
||||
INT absPower{power.ABS().value};
|
||||
REAL shifted{base};
|
||||
int nbits{INT::bits - absPower.LEADZ()};
|
||||
for (int j{0}; j + 1 < nbits; ++j) {
|
||||
if (absPower.BTEST(j)) {
|
||||
result.value =
|
||||
result.value.Multiply(shifted).AccumulateFlags(result.flags);
|
||||
}
|
||||
shifted = shifted.Add(shifted).AccumulateFlags(result.flags);
|
||||
}
|
||||
result.value = result.value.Multiply(shifted).AccumulateFlags(result.flags);
|
||||
if (negativePower) {
|
||||
result.value = one.Divide(result.value).AccumulateFlags(result.flags);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace Fortran::evaluate
|
||||
#endif // FORTRAN_EVALUATE_INT_POWER_H_
|
|
@ -102,7 +102,7 @@ public:
|
|||
|
||||
struct PowerWithErrors {
|
||||
Integer power;
|
||||
bool divisionByZero, overflow, zeroToZero;
|
||||
bool divisionByZero{false}, overflow{false}, zeroToZero{false};
|
||||
};
|
||||
|
||||
// Constructors and value-generating static functions
|
||||
|
|
|
@ -60,7 +60,7 @@ ValueWithRealFlags<Real<W, P, IM>> Real<W, P, IM>::Add(
|
|||
const Real &y, Rounding rounding) const {
|
||||
ValueWithRealFlags<Real> result;
|
||||
if (IsNotANumber() || y.IsNotANumber()) {
|
||||
result.value.word_ = NaNWord(); // NaN + x -> NaN
|
||||
result.value = NaN(); // NaN + x -> NaN
|
||||
if (IsSignalingNaN() || y.IsSignalingNaN()) {
|
||||
result.flags.set(RealFlag::InvalidArgument);
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ ValueWithRealFlags<Real<W, P, IM>> Real<W, P, IM>::Add(
|
|||
if (isNegative == yIsNegative) {
|
||||
result.value = *this; // +/-Inf + +/-Inf -> +/-Inf
|
||||
} else {
|
||||
result.value.word_ = NaNWord(); // +/-Inf + -/+Inf -> NaN
|
||||
result.value = NaN(); // +/-Inf + -/+Inf -> NaN
|
||||
result.flags.set(RealFlag::InvalidArgument);
|
||||
}
|
||||
} else {
|
||||
|
@ -140,7 +140,7 @@ ValueWithRealFlags<Real<W, P, IM>> Real<W, P, IM>::Multiply(
|
|||
const Real &y, Rounding rounding) const {
|
||||
ValueWithRealFlags<Real> result;
|
||||
if (IsNotANumber() || y.IsNotANumber()) {
|
||||
result.value.word_ = NaNWord(); // NaN * x -> NaN
|
||||
result.value = NaN(); // NaN * x -> NaN
|
||||
if (IsSignalingNaN() || y.IsSignalingNaN()) {
|
||||
result.flags.set(RealFlag::InvalidArgument);
|
||||
}
|
||||
|
@ -148,10 +148,10 @@ ValueWithRealFlags<Real<W, P, IM>> Real<W, P, IM>::Multiply(
|
|||
bool isNegative{IsNegative() != y.IsNegative()};
|
||||
if (IsInfinite() || y.IsInfinite()) {
|
||||
if (IsZero() || y.IsZero()) {
|
||||
result.value.word_ = NaNWord(); // 0 * Inf -> NaN
|
||||
result.value = NaN(); // 0 * Inf -> NaN
|
||||
result.flags.set(RealFlag::InvalidArgument);
|
||||
} else {
|
||||
result.value.word_ = InfinityWord(isNegative);
|
||||
result.value = Infinity(isNegative);
|
||||
}
|
||||
} else {
|
||||
auto product{GetFraction().MultiplyUnsigned(y.GetFraction())};
|
||||
|
@ -200,7 +200,7 @@ ValueWithRealFlags<Real<W, P, IM>> Real<W, P, IM>::Divide(
|
|||
const Real &y, Rounding rounding) const {
|
||||
ValueWithRealFlags<Real> result;
|
||||
if (IsNotANumber() || y.IsNotANumber()) {
|
||||
result.value.word_ = NaNWord(); // NaN / x -> NaN, x / NaN -> NaN
|
||||
result.value = NaN(); // NaN / x -> NaN, x / NaN -> NaN
|
||||
if (IsSignalingNaN() || y.IsSignalingNaN()) {
|
||||
result.flags.set(RealFlag::InvalidArgument);
|
||||
}
|
||||
|
@ -208,17 +208,17 @@ ValueWithRealFlags<Real<W, P, IM>> Real<W, P, IM>::Divide(
|
|||
bool isNegative{IsNegative() != y.IsNegative()};
|
||||
if (IsInfinite()) {
|
||||
if (y.IsInfinite()) {
|
||||
result.value.word_ = NaNWord(); // Inf/Inf -> NaN
|
||||
result.value = NaN(); // Inf/Inf -> NaN
|
||||
result.flags.set(RealFlag::InvalidArgument);
|
||||
} else { // Inf/x -> Inf, Inf/0 -> Inf
|
||||
result.value.word_ = InfinityWord(isNegative);
|
||||
result.value = Infinity(isNegative);
|
||||
}
|
||||
} else if (y.IsZero()) {
|
||||
if (IsZero()) { // 0/0 -> NaN
|
||||
result.value.word_ = NaNWord();
|
||||
result.value = NaN();
|
||||
result.flags.set(RealFlag::InvalidArgument);
|
||||
} else { // x/0 -> Inf, Inf/0 -> Inf
|
||||
result.value.word_ = InfinityWord(isNegative);
|
||||
result.value = Infinity(isNegative);
|
||||
result.flags.set(RealFlag::DivideByZero);
|
||||
}
|
||||
} else if (IsZero() || y.IsInfinite()) { // 0/x, x/Inf -> 0
|
||||
|
|
|
@ -117,6 +117,23 @@ public:
|
|||
return epsilon;
|
||||
}
|
||||
|
||||
// TODO: Configurable NaN representations
|
||||
static constexpr Real NaN() {
|
||||
return {Word{maxExponent}
|
||||
.SHIFTL(significandBits)
|
||||
.IBSET(significandBits - 1)
|
||||
.IBSET(significandBits - 2)};
|
||||
}
|
||||
|
||||
static constexpr Real Infinity(bool negative) {
|
||||
Word infinity{maxExponent};
|
||||
infinity = infinity.SHIFTL(significandBits);
|
||||
if (negative) {
|
||||
infinity = infinity.IBSET(infinity.bits - 1);
|
||||
}
|
||||
return {infinity};
|
||||
}
|
||||
|
||||
template<typename INT>
|
||||
static ValueWithRealFlags<Real> FromInteger(
|
||||
const INT &n, Rounding rounding = Rounding::TiesToEven) {
|
||||
|
@ -285,23 +302,6 @@ private:
|
|||
return greaterOrEqual;
|
||||
}
|
||||
|
||||
// TODO: Configurable NaN representations
|
||||
static constexpr Word NaNWord() {
|
||||
return Word{maxExponent}
|
||||
.SHIFTL(significandBits)
|
||||
.IBSET(significandBits - 1)
|
||||
.IBSET(significandBits - 2);
|
||||
}
|
||||
|
||||
static constexpr Word InfinityWord(bool negative) {
|
||||
Word infinity{maxExponent};
|
||||
infinity = infinity.SHIFTL(significandBits);
|
||||
if (negative) {
|
||||
infinity = infinity.IBSET(infinity.bits - 1);
|
||||
}
|
||||
return infinity;
|
||||
}
|
||||
|
||||
// Normalizes and marshals the fields of a floating-point number in place.
|
||||
// The value is not a NaN, and a zero fraction means a zero value (i.e.,
|
||||
// a maximal exponent and zero fraction doesn't signify infinity, although
|
||||
|
|
Loading…
Reference in New Issue