[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:
peter klausler 2018-07-25 13:46:13 -07:00
parent b9631a5d74
commit bd146ed3e8
6 changed files with 102 additions and 31 deletions

View File

@ -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;
}
}

View File

@ -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.

View File

@ -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_

View File

@ -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

View File

@ -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

View File

@ -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