forked from OSchip/llvm-project
[flang] COMPLEX folding
Original-commit: flang-compiler/f18@6f1ef45b2f Reviewed-on: https://github.com/flang-compiler/f18/pull/162 Tree-same-pre-rewrite: false
This commit is contained in:
parent
bd146ed3e8
commit
b861018e3a
|
@ -82,6 +82,8 @@ template<typename A> struct ValueWithRealFlags {
|
|||
|
||||
ENUM_CLASS(Rounding, TiesToEven, ToZero, Down, Up, TiesAwayFromZero)
|
||||
|
||||
static constexpr Rounding defaultRounding{Rounding::TiesToEven};
|
||||
|
||||
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
constexpr bool IsHostLittleEndian{false};
|
||||
#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
|
|
|
@ -17,36 +17,40 @@
|
|||
namespace Fortran::evaluate::value {
|
||||
|
||||
template<typename R>
|
||||
ValueWithRealFlags<Complex<R>> Complex<R>::Add(const Complex &that) const {
|
||||
ValueWithRealFlags<Complex<R>> Complex<R>::Add(
|
||||
const Complex &that, Rounding rounding) const {
|
||||
RealFlags flags;
|
||||
Part reSum{re_.Add(that.re_).AccumulateFlags(flags)};
|
||||
Part imSum{im_.Add(that.im_).AccumulateFlags(flags)};
|
||||
Part reSum{re_.Add(that.re_, rounding).AccumulateFlags(flags)};
|
||||
Part imSum{im_.Add(that.im_, rounding).AccumulateFlags(flags)};
|
||||
return {Complex{reSum, imSum}, flags};
|
||||
}
|
||||
|
||||
template<typename R>
|
||||
ValueWithRealFlags<Complex<R>> Complex<R>::Subtract(const Complex &that) const {
|
||||
ValueWithRealFlags<Complex<R>> Complex<R>::Subtract(
|
||||
const Complex &that, Rounding rounding) const {
|
||||
RealFlags flags;
|
||||
Part reDiff{re_.Subtract(that.re_).AccumulateFlags(flags)};
|
||||
Part imDiff{im_.Subtract(that.im_).AccumulateFlags(flags)};
|
||||
Part reDiff{re_.Subtract(that.re_, rounding).AccumulateFlags(flags)};
|
||||
Part imDiff{im_.Subtract(that.im_, rounding).AccumulateFlags(flags)};
|
||||
return {Complex{reDiff, imDiff}, flags};
|
||||
}
|
||||
|
||||
template<typename R>
|
||||
ValueWithRealFlags<Complex<R>> Complex<R>::Multiply(const Complex &that) const {
|
||||
ValueWithRealFlags<Complex<R>> Complex<R>::Multiply(
|
||||
const Complex &that, Rounding rounding) const {
|
||||
// (a + ib)*(c + id) -> ac - bd + i(ad + bc)
|
||||
RealFlags flags;
|
||||
Part ac{re_.Multiply(that.re_).AccumulateFlags(flags)};
|
||||
Part bd{im_.Multiply(that.im_).AccumulateFlags(flags)};
|
||||
Part ad{re_.Multiply(that.im_).AccumulateFlags(flags)};
|
||||
Part bc{im_.Multiply(that.re_).AccumulateFlags(flags)};
|
||||
Part acbd{ac.Subtract(bd).AccumulateFlags(flags)};
|
||||
Part adbc{ad.Add(bc).AccumulateFlags(flags)};
|
||||
Part ac{re_.Multiply(that.re_, rounding).AccumulateFlags(flags)};
|
||||
Part bd{im_.Multiply(that.im_, rounding).AccumulateFlags(flags)};
|
||||
Part ad{re_.Multiply(that.im_, rounding).AccumulateFlags(flags)};
|
||||
Part bc{im_.Multiply(that.re_, rounding).AccumulateFlags(flags)};
|
||||
Part acbd{ac.Subtract(bd, rounding).AccumulateFlags(flags)};
|
||||
Part adbc{ad.Add(bc, rounding).AccumulateFlags(flags)};
|
||||
return {Complex{acbd, adbc}, flags};
|
||||
}
|
||||
|
||||
template<typename R>
|
||||
ValueWithRealFlags<Complex<R>> Complex<R>::Divide(const Complex &that) const {
|
||||
ValueWithRealFlags<Complex<R>> Complex<R>::Divide(
|
||||
const Complex &that, Rounding rounding) const {
|
||||
// (a + ib)/(c + id) -> [(a+ib)*(c-id)] / [(c+id)*(c-id)]
|
||||
// -> [ac+bd+i(bc-ad)] / (cc+dd)
|
||||
// -> ((ac+bd)/(cc+dd)) + i((bc-ad)/(cc+dd))
|
||||
|
@ -55,30 +59,30 @@ ValueWithRealFlags<Complex<R>> Complex<R>::Divide(const Complex &that) const {
|
|||
RealFlags flags;
|
||||
bool cGEd{that.re_.ABS().Compare(that.im_.ABS()) != Relation::Less};
|
||||
if (cGEd) {
|
||||
scale = that.im_.Divide(that.re_).AccumulateFlags(flags);
|
||||
scale = that.im_.Divide(that.re_, rounding).AccumulateFlags(flags);
|
||||
} else {
|
||||
scale = that.re_.Divide(that.im_).AccumulateFlags(flags);
|
||||
scale = that.re_.Divide(that.im_, rounding).AccumulateFlags(flags);
|
||||
}
|
||||
Part den;
|
||||
if (cGEd) {
|
||||
Part dS{scale.Multiply(that.im_).AccumulateFlags(flags)};
|
||||
den = dS.Add(that.re_).AccumulateFlags(flags);
|
||||
Part dS{scale.Multiply(that.im_, rounding).AccumulateFlags(flags)};
|
||||
den = dS.Add(that.re_, rounding).AccumulateFlags(flags);
|
||||
} else {
|
||||
Part cS{scale.Multiply(that.re_).AccumulateFlags(flags)};
|
||||
den = cS.Add(that.im_).AccumulateFlags(flags);
|
||||
Part cS{scale.Multiply(that.re_, rounding).AccumulateFlags(flags)};
|
||||
den = cS.Add(that.im_, rounding).AccumulateFlags(flags);
|
||||
}
|
||||
Part aS{scale.Multiply(re_).AccumulateFlags(flags)};
|
||||
Part bS{scale.Multiply(im_).AccumulateFlags(flags)};
|
||||
Part aS{scale.Multiply(re_, rounding).AccumulateFlags(flags)};
|
||||
Part bS{scale.Multiply(im_, rounding).AccumulateFlags(flags)};
|
||||
Part re1, im1;
|
||||
if (cGEd) {
|
||||
re1 = re_.Add(bS).AccumulateFlags(flags);
|
||||
im1 = im_.Subtract(aS).AccumulateFlags(flags);
|
||||
re1 = re_.Add(bS, rounding).AccumulateFlags(flags);
|
||||
im1 = im_.Subtract(aS, rounding).AccumulateFlags(flags);
|
||||
} else {
|
||||
re1 = aS.Add(im_).AccumulateFlags(flags);
|
||||
im1 = bS.Subtract(re_).AccumulateFlags(flags);
|
||||
re1 = aS.Add(im_, rounding).AccumulateFlags(flags);
|
||||
im1 = bS.Subtract(re_, rounding).AccumulateFlags(flags);
|
||||
}
|
||||
Part re{re1.Divide(den).AccumulateFlags(flags)};
|
||||
Part im{im1.Divide(den).AccumulateFlags(flags)};
|
||||
Part re{re1.Divide(den, rounding).AccumulateFlags(flags)};
|
||||
Part im{im1.Divide(den, rounding).AccumulateFlags(flags)};
|
||||
return {Complex{re, im}, flags};
|
||||
}
|
||||
|
||||
|
|
|
@ -29,6 +29,8 @@ public:
|
|||
constexpr Complex(const Complex &) = default;
|
||||
constexpr Complex(const Part &r, const Part &i) : re_{r}, im_{i} {}
|
||||
explicit constexpr Complex(const Part &r) : re_{r} {}
|
||||
constexpr Complex &operator=(const Complex &) = default;
|
||||
constexpr Complex &operator=(Complex &&) = default;
|
||||
|
||||
constexpr const Part &REAL() const { return re_; }
|
||||
constexpr const Part &AIMAG() const { return im_; }
|
||||
|
@ -40,10 +42,43 @@ public:
|
|||
im_.Compare(that.im_) == Relation::Equal;
|
||||
}
|
||||
|
||||
ValueWithRealFlags<Complex> Add(const Complex &) const;
|
||||
ValueWithRealFlags<Complex> Subtract(const Complex &) const;
|
||||
ValueWithRealFlags<Complex> Multiply(const Complex &) const;
|
||||
ValueWithRealFlags<Complex> Divide(const Complex &) const;
|
||||
constexpr bool IsZero() const { return re_.IsZero() || im_.IsZero(); }
|
||||
|
||||
constexpr bool IsInfinite() const {
|
||||
return re_.IsInfinite() || im_.IsInfinite();
|
||||
}
|
||||
|
||||
constexpr bool IsNotANumber() const {
|
||||
return re_.IsNotANumber() || im_.IsNotANumber();
|
||||
}
|
||||
|
||||
constexpr bool IsSignalingNaN() const {
|
||||
return re_.IsSignalingNaN() || im_.IsSignalingNaN();
|
||||
}
|
||||
|
||||
template<typename INT>
|
||||
static ValueWithRealFlags<Complex> FromInteger(
|
||||
const INT &n, Rounding rounding = defaultRounding) {
|
||||
ValueWithRealFlags<Complex> result;
|
||||
result.value.re_ =
|
||||
Part::FromInteger(n, rounding).AccumulateFlags(result.flags);
|
||||
return result;
|
||||
}
|
||||
|
||||
ValueWithRealFlags<Complex> Add(
|
||||
const Complex &, Rounding rounding = defaultRounding) const;
|
||||
ValueWithRealFlags<Complex> Subtract(
|
||||
const Complex &, Rounding rounding = defaultRounding) const;
|
||||
ValueWithRealFlags<Complex> Multiply(
|
||||
const Complex &, Rounding rounding = defaultRounding) const;
|
||||
ValueWithRealFlags<Complex> Divide(
|
||||
const Complex &, Rounding rounding = defaultRounding) const;
|
||||
|
||||
constexpr Complex FlushDenormalToZero() const {
|
||||
return {re_.FlushDenormalToZero(), im_.FlushDenormalToZero()};
|
||||
}
|
||||
|
||||
static constexpr Complex NaN() { return {Part::NaN(), Part::NaN()}; }
|
||||
|
||||
std::string DumpHexadecimal() const;
|
||||
// TODO: (C)ABS once Real::HYPOT is done
|
||||
|
|
|
@ -215,7 +215,7 @@ auto Unary<CRTP, RESULT, A>::Fold(FoldingContext &context)
|
|||
if (std::optional<OperandScalarConstant> c{operand_->Fold(context)}) {
|
||||
return static_cast<CRTP *>(this)->FoldScalar(context, *c);
|
||||
}
|
||||
return {};
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
template<typename CRTP, typename RESULT, typename A, typename B>
|
||||
|
@ -226,7 +226,7 @@ auto Binary<CRTP, RESULT, A, B>::Fold(FoldingContext &context)
|
|||
if (lc.has_value() && rc.has_value()) {
|
||||
return static_cast<CRTP *>(this)->FoldScalar(context, *lc, *rc);
|
||||
}
|
||||
return {};
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
template<int KIND>
|
||||
|
@ -237,7 +237,7 @@ auto IntegerExpr<KIND>::ConvertInteger::FoldScalar(FoldingContext &context,
|
|||
auto converted{Scalar::ConvertSigned(x)};
|
||||
if (converted.overflow) {
|
||||
context.messages.Say("integer conversion overflowed"_en_US);
|
||||
return {};
|
||||
return std::nullopt;
|
||||
}
|
||||
return {std::move(converted.value)};
|
||||
},
|
||||
|
@ -252,12 +252,12 @@ auto IntegerExpr<KIND>::ConvertReal::FoldScalar(FoldingContext &context,
|
|||
auto converted{x.template ToInteger<Scalar>()};
|
||||
if (converted.flags.test(RealFlag::Overflow)) {
|
||||
context.messages.Say("real->integer conversion overflowed"_en_US);
|
||||
return {};
|
||||
return std::nullopt;
|
||||
}
|
||||
if (converted.flags.test(RealFlag::InvalidArgument)) {
|
||||
context.messages.Say(
|
||||
"real->integer conversion: invalid argument"_en_US);
|
||||
return {};
|
||||
return std::nullopt;
|
||||
}
|
||||
return {std::move(converted.value)};
|
||||
},
|
||||
|
@ -270,7 +270,7 @@ auto IntegerExpr<KIND>::Negate::FoldScalar(
|
|||
auto negated{c.Negate()};
|
||||
if (negated.overflow) {
|
||||
context.messages.Say("integer negation overflowed"_en_US);
|
||||
return {};
|
||||
return std::nullopt;
|
||||
}
|
||||
return {std::move(negated.value)};
|
||||
}
|
||||
|
@ -281,7 +281,7 @@ auto IntegerExpr<KIND>::Add::FoldScalar(FoldingContext &context,
|
|||
auto sum{a.AddSigned(b)};
|
||||
if (sum.overflow) {
|
||||
context.messages.Say("integer addition overflowed"_en_US);
|
||||
return {};
|
||||
return std::nullopt;
|
||||
}
|
||||
return {std::move(sum.value)};
|
||||
}
|
||||
|
@ -292,7 +292,7 @@ auto IntegerExpr<KIND>::Subtract::FoldScalar(FoldingContext &context,
|
|||
auto diff{a.SubtractSigned(b)};
|
||||
if (diff.overflow) {
|
||||
context.messages.Say("integer subtraction overflowed"_en_US);
|
||||
return {};
|
||||
return std::nullopt;
|
||||
}
|
||||
return {std::move(diff.value)};
|
||||
}
|
||||
|
@ -303,7 +303,7 @@ auto IntegerExpr<KIND>::Multiply::FoldScalar(FoldingContext &context,
|
|||
auto product{a.MultiplySigned(b)};
|
||||
if (product.SignedMultiplicationOverflowed()) {
|
||||
context.messages.Say("integer multiplication overflowed"_en_US);
|
||||
return {};
|
||||
return std::nullopt;
|
||||
}
|
||||
return {std::move(product.lower)};
|
||||
}
|
||||
|
@ -314,11 +314,11 @@ auto IntegerExpr<KIND>::Divide::FoldScalar(FoldingContext &context,
|
|||
auto qr{a.DivideSigned(b)};
|
||||
if (qr.divisionByZero) {
|
||||
context.messages.Say("integer division by zero"_en_US);
|
||||
return {};
|
||||
return std::nullopt;
|
||||
}
|
||||
if (qr.overflow) {
|
||||
context.messages.Say("integer division overflowed"_en_US);
|
||||
return {};
|
||||
return std::nullopt;
|
||||
}
|
||||
return {std::move(qr.quotient)};
|
||||
}
|
||||
|
@ -329,15 +329,15 @@ auto IntegerExpr<KIND>::Power::FoldScalar(FoldingContext &context,
|
|||
typename Scalar::PowerWithErrors power{a.Power(b)};
|
||||
if (power.divisionByZero) {
|
||||
context.messages.Say("zero to negative power"_en_US);
|
||||
return {};
|
||||
return std::nullopt;
|
||||
}
|
||||
if (power.overflow) {
|
||||
context.messages.Say("integer power overflowed"_en_US);
|
||||
return {};
|
||||
return std::nullopt;
|
||||
}
|
||||
if (power.zeroToZero) {
|
||||
context.messages.Say("integer 0**0"_en_US);
|
||||
return {};
|
||||
return std::nullopt;
|
||||
}
|
||||
return {std::move(power.power)};
|
||||
}
|
||||
|
@ -375,7 +375,7 @@ auto IntegerExpr<KIND>::Fold(FoldingContext &context) -> std::optional<Scalar> {
|
|||
return c;
|
||||
}
|
||||
}
|
||||
return {};
|
||||
return std::nullopt;
|
||||
},
|
||||
u_);
|
||||
}
|
||||
|
@ -465,7 +465,7 @@ auto RealExpr<KIND>::Divide::FoldScalar(FoldingContext &context,
|
|||
template<int KIND>
|
||||
auto RealExpr<KIND>::Power::FoldScalar(FoldingContext &context, const Scalar &a,
|
||||
const Scalar &b) -> std::optional<Scalar> {
|
||||
return {}; // TODO
|
||||
return std::nullopt; // TODO
|
||||
}
|
||||
|
||||
template<int KIND>
|
||||
|
@ -522,28 +522,108 @@ auto RealExpr<KIND>::Fold(FoldingContext &context) -> std::optional<Scalar> {
|
|||
if constexpr (evaluate::FoldableTrait<Ty>) {
|
||||
auto c{x.Fold(context)};
|
||||
if (c.has_value()) {
|
||||
if (context.flushDenormalsToZero && c->IsDenormal()) {
|
||||
u_ = Scalar{};
|
||||
} else {
|
||||
u_ = *c;
|
||||
if (context.flushDenormalsToZero) {
|
||||
*c = c->FlushDenormalToZero();
|
||||
}
|
||||
u_ = *c;
|
||||
return c;
|
||||
}
|
||||
}
|
||||
return {};
|
||||
return std::nullopt;
|
||||
},
|
||||
u_);
|
||||
}
|
||||
|
||||
template<int KIND>
|
||||
auto ComplexExpr<KIND>::Negate::FoldScalar(
|
||||
FoldingContext &context, const Scalar &c) -> std::optional<Scalar> {
|
||||
return {c.Negate()};
|
||||
}
|
||||
|
||||
template<int KIND>
|
||||
auto ComplexExpr<KIND>::Add::FoldScalar(FoldingContext &context,
|
||||
const Scalar &a, const Scalar &b) -> std::optional<Scalar> {
|
||||
auto sum{a.Add(b, context.rounding)};
|
||||
RealFlagWarnings(context, sum.flags, "complex addition");
|
||||
return {std::move(sum.value)};
|
||||
}
|
||||
|
||||
template<int KIND>
|
||||
auto ComplexExpr<KIND>::Subtract::FoldScalar(FoldingContext &context,
|
||||
const Scalar &a, const Scalar &b) -> std::optional<Scalar> {
|
||||
auto difference{a.Subtract(b, context.rounding)};
|
||||
RealFlagWarnings(context, difference.flags, "complex subtraction");
|
||||
return {std::move(difference.value)};
|
||||
}
|
||||
|
||||
template<int KIND>
|
||||
auto ComplexExpr<KIND>::Multiply::FoldScalar(FoldingContext &context,
|
||||
const Scalar &a, const Scalar &b) -> std::optional<Scalar> {
|
||||
auto product{a.Multiply(b, context.rounding)};
|
||||
RealFlagWarnings(context, product.flags, "complex multiplication");
|
||||
return {std::move(product.value)};
|
||||
}
|
||||
|
||||
template<int KIND>
|
||||
auto ComplexExpr<KIND>::Divide::FoldScalar(FoldingContext &context,
|
||||
const Scalar &a, const Scalar &b) -> std::optional<Scalar> {
|
||||
auto quotient{a.Divide(b, context.rounding)};
|
||||
RealFlagWarnings(context, quotient.flags, "complex division");
|
||||
return {std::move(quotient.value)};
|
||||
}
|
||||
|
||||
template<int KIND>
|
||||
auto ComplexExpr<KIND>::Power::FoldScalar(FoldingContext &context,
|
||||
const Scalar &a, const Scalar &b) -> std::optional<Scalar> {
|
||||
return std::nullopt; // TODO
|
||||
}
|
||||
|
||||
template<int KIND>
|
||||
auto ComplexExpr<KIND>::IntPower::FoldScalar(FoldingContext &context,
|
||||
const Scalar &a, const ScalarConstant<Category::Integer> &b)
|
||||
-> std::optional<Scalar> {
|
||||
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>
|
||||
auto ComplexExpr<KIND>::CMPLX::FoldScalar(FoldingContext &context,
|
||||
const PartScalar &a, const PartScalar &b) -> std::optional<Scalar> {
|
||||
return {Scalar{a, b}};
|
||||
}
|
||||
|
||||
template<int KIND>
|
||||
auto ComplexExpr<KIND>::Fold(FoldingContext &context) -> std::optional<Scalar> {
|
||||
return {}; // TODO
|
||||
return std::visit(
|
||||
[&](auto &x) -> std::optional<Scalar> {
|
||||
using Ty = typename std::decay<decltype(x)>::type;
|
||||
if constexpr (std::is_same_v<Ty, Scalar>) {
|
||||
return {x};
|
||||
}
|
||||
if constexpr (evaluate::FoldableTrait<Ty>) {
|
||||
auto c{x.Fold(context)};
|
||||
if (c.has_value()) {
|
||||
if (context.flushDenormalsToZero) {
|
||||
*c = c->FlushDenormalToZero();
|
||||
}
|
||||
u_ = *c;
|
||||
return c;
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
},
|
||||
u_);
|
||||
}
|
||||
|
||||
template<int KIND>
|
||||
auto CharacterExpr<KIND>::Fold(FoldingContext &context)
|
||||
-> std::optional<Scalar> {
|
||||
return {}; // TODO
|
||||
return std::nullopt; // TODO
|
||||
}
|
||||
|
||||
template<typename A>
|
||||
|
@ -574,11 +654,11 @@ auto Comparison<A>::FoldScalar(FoldingContext &c,
|
|||
case Relation::Greater:
|
||||
return {opr == RelationalOperator::NE || opr == RelationalOperator::GE ||
|
||||
opr == RelationalOperator::GT};
|
||||
case Relation::Unordered: return {};
|
||||
case Relation::Unordered: return std::nullopt;
|
||||
}
|
||||
}
|
||||
// TODO complex and character comparisons
|
||||
return {};
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
template<int KIND>
|
||||
|
@ -626,7 +706,7 @@ auto LogicalExpr<KIND>::Fold(FoldingContext &context) -> std::optional<Scalar> {
|
|||
return c;
|
||||
}
|
||||
}
|
||||
return {};
|
||||
return std::nullopt;
|
||||
},
|
||||
u_);
|
||||
}
|
||||
|
@ -637,7 +717,7 @@ std::optional<GenericScalar> GenericExpr::ScalarValue() const {
|
|||
if (auto c{x.ScalarValue()}) {
|
||||
return {GenericScalar{std::move(*c)}};
|
||||
}
|
||||
return {};
|
||||
return std::nullopt;
|
||||
},
|
||||
u);
|
||||
}
|
||||
|
@ -649,9 +729,7 @@ auto Expr<AnyKindType<CAT>>::ScalarValue() const -> std::optional<Scalar> {
|
|||
if (auto c{x.ScalarValue()}) {
|
||||
return {Scalar{std::move(*c)}};
|
||||
}
|
||||
std::optional<Scalar> avoidBogusGCCWarning; // ... with return {};
|
||||
return avoidBogusGCCWarning;
|
||||
;
|
||||
return std::nullopt;
|
||||
},
|
||||
u);
|
||||
}
|
||||
|
@ -664,9 +742,7 @@ auto Expr<AnyKindType<CAT>>::Fold(FoldingContext &context)
|
|||
if (auto c{x.Fold(context)}) {
|
||||
return {Scalar{std::move(*c)}};
|
||||
}
|
||||
std::optional<Scalar> avoidBogusGCCWarning; // ... with return {};
|
||||
return avoidBogusGCCWarning;
|
||||
;
|
||||
return std::nullopt;
|
||||
},
|
||||
u);
|
||||
}
|
||||
|
@ -677,7 +753,7 @@ std::optional<GenericScalar> GenericExpr::Fold(FoldingContext &context) {
|
|||
if (auto c{x.Fold(context)}) {
|
||||
return {GenericScalar{std::move(*c)}};
|
||||
}
|
||||
return {};
|
||||
return std::nullopt;
|
||||
},
|
||||
u);
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ namespace Fortran::evaluate {
|
|||
CLASS_TRAIT(FoldableTrait);
|
||||
struct FoldingContext {
|
||||
parser::ContextualMessages &messages;
|
||||
Rounding rounding{Rounding::TiesToEven};
|
||||
Rounding rounding{defaultRounding};
|
||||
bool flushDenormalsToZero{false};
|
||||
};
|
||||
|
||||
|
@ -330,31 +330,52 @@ public:
|
|||
template<typename CRTP> using Bin = Binary<CRTP, Result>;
|
||||
struct Parentheses : public Un<Parentheses> {
|
||||
using Un<Parentheses>::Un;
|
||||
static std::optional<Scalar> FoldScalar(FoldingContext &, const Scalar &x) {
|
||||
return {x};
|
||||
}
|
||||
};
|
||||
struct Negate : public Un<Negate> {
|
||||
using Un<Negate>::Un;
|
||||
static std::optional<Scalar> FoldScalar(FoldingContext &, const Scalar &);
|
||||
};
|
||||
struct Add : public Bin<Add> {
|
||||
using Bin<Add>::Bin;
|
||||
static std::optional<Scalar> FoldScalar(
|
||||
FoldingContext &, const Scalar &, const Scalar &);
|
||||
};
|
||||
struct Subtract : public Bin<Subtract> {
|
||||
using Bin<Subtract>::Bin;
|
||||
static std::optional<Scalar> FoldScalar(
|
||||
FoldingContext &, const Scalar &, const Scalar &);
|
||||
};
|
||||
struct Multiply : public Bin<Multiply> {
|
||||
using Bin<Multiply>::Bin;
|
||||
static std::optional<Scalar> FoldScalar(
|
||||
FoldingContext &, const Scalar &, const Scalar &);
|
||||
};
|
||||
struct Divide : public Bin<Divide> {
|
||||
using Bin<Divide>::Bin;
|
||||
static std::optional<Scalar> FoldScalar(
|
||||
FoldingContext &, const Scalar &, const Scalar &);
|
||||
};
|
||||
struct Power : public Bin<Power> {
|
||||
using Bin<Power>::Bin;
|
||||
static std::optional<Scalar> FoldScalar(
|
||||
FoldingContext &, const Scalar &, const Scalar &);
|
||||
};
|
||||
struct IntPower
|
||||
: public Binary<IntPower, Result, AnyKindType<Category::Integer>> {
|
||||
using Binary<IntPower, Result, AnyKindType<Category::Integer>>::Binary;
|
||||
: public Binary<IntPower, Result, Result, AnyKindType<Category::Integer>> {
|
||||
using Binary<IntPower, Result, Result,
|
||||
AnyKindType<Category::Integer>>::Binary;
|
||||
static std::optional<Scalar> FoldScalar(FoldingContext &, const Scalar &,
|
||||
const ScalarConstant<Category::Integer> &);
|
||||
};
|
||||
struct CMPLX : public Binary<CMPLX, Result, Type<Category::Real, KIND>> {
|
||||
using Binary<CMPLX, Result, Type<Category::Real, KIND>>::Binary;
|
||||
using Part = Type<Category::Real, KIND>;
|
||||
using PartScalar = typename Part::Value;
|
||||
struct CMPLX : public Binary<CMPLX, Result, Part> {
|
||||
using Binary<CMPLX, Result, Part>::Binary;
|
||||
static std::optional<Scalar> FoldScalar(
|
||||
FoldingContext &, const PartScalar &, const PartScalar &);
|
||||
};
|
||||
|
||||
CLASS_BOILERPLATE(Expr)
|
||||
|
|
|
@ -22,8 +22,8 @@
|
|||
namespace Fortran::evaluate {
|
||||
|
||||
template<typename REAL, typename INT>
|
||||
ValueWithRealFlags<REAL> IntPower(const REAL &base, const INT &power,
|
||||
Rounding rounding = Rounding::TiesToEven) {
|
||||
ValueWithRealFlags<REAL> IntPower(
|
||||
const REAL &base, const INT &power, Rounding rounding = defaultRounding) {
|
||||
REAL one{REAL::FromInteger(INT{1}).value};
|
||||
ValueWithRealFlags<REAL> result;
|
||||
result.value = one;
|
||||
|
|
|
@ -50,6 +50,7 @@ public:
|
|||
constexpr Real(const Real &) = default;
|
||||
constexpr Real(const Word &bits) : word_{bits} {}
|
||||
constexpr Real &operator=(const Real &) = default;
|
||||
constexpr Real &operator=(Real &&) = default;
|
||||
|
||||
// TODO: facility to flush denormal results to zero
|
||||
// TODO AINT/ANINT, CEILING, FLOOR, DIM, MAX, MIN, DPROD, FRACTION
|
||||
|
@ -87,20 +88,20 @@ public:
|
|||
|
||||
Relation Compare(const Real &) const;
|
||||
ValueWithRealFlags<Real> Add(
|
||||
const Real &, Rounding rounding = Rounding::TiesToEven) const;
|
||||
const Real &, Rounding rounding = defaultRounding) const;
|
||||
ValueWithRealFlags<Real> Subtract(
|
||||
const Real &y, Rounding rounding = Rounding::TiesToEven) const {
|
||||
const Real &y, Rounding rounding = defaultRounding) const {
|
||||
return Add(y.Negate(), rounding);
|
||||
}
|
||||
ValueWithRealFlags<Real> Multiply(
|
||||
const Real &, Rounding rounding = Rounding::TiesToEven) const;
|
||||
const Real &, Rounding rounding = defaultRounding) const;
|
||||
ValueWithRealFlags<Real> Divide(
|
||||
const Real &, Rounding rounding = Rounding::TiesToEven) const;
|
||||
const Real &, Rounding rounding = defaultRounding) const;
|
||||
|
||||
// SQRT(x**2 + y**2) but computed so as to avoid spurious overflow
|
||||
// TODO: needed for CABS
|
||||
ValueWithRealFlags<Real> HYPOT(
|
||||
const Real &, Rounding rounding = Rounding::TiesToEven) const;
|
||||
const Real &, Rounding rounding = defaultRounding) const;
|
||||
|
||||
template<typename INT> constexpr INT EXPONENT() const {
|
||||
std::uint64_t exponent{Exponent()};
|
||||
|
@ -117,6 +118,13 @@ public:
|
|||
return epsilon;
|
||||
}
|
||||
|
||||
constexpr Real FlushDenormalToZero() const {
|
||||
if (IsDenormal()) {
|
||||
return Real{};
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// TODO: Configurable NaN representations
|
||||
static constexpr Real NaN() {
|
||||
return {Word{maxExponent}
|
||||
|
@ -136,7 +144,7 @@ public:
|
|||
|
||||
template<typename INT>
|
||||
static ValueWithRealFlags<Real> FromInteger(
|
||||
const INT &n, Rounding rounding = Rounding::TiesToEven) {
|
||||
const INT &n, Rounding rounding = defaultRounding) {
|
||||
bool isNegative{n.IsNegative()};
|
||||
INT absN{n};
|
||||
if (isNegative) {
|
||||
|
@ -224,7 +232,7 @@ public:
|
|||
|
||||
template<typename A>
|
||||
static ValueWithRealFlags<Real> Convert(
|
||||
const A &x, Rounding rounding = Rounding::TiesToEven) {
|
||||
const A &x, Rounding rounding = defaultRounding) {
|
||||
bool isNegative{x.IsNegative()};
|
||||
A absX{x};
|
||||
if (isNegative) {
|
||||
|
@ -307,7 +315,7 @@ private:
|
|||
// a maximal exponent and zero fraction doesn't signify infinity, although
|
||||
// this member function will detect overflow and encode infinities).
|
||||
RealFlags Normalize(bool negative, std::uint64_t exponent,
|
||||
const Fraction &fraction, Rounding rounding = Rounding::TiesToEven,
|
||||
const Fraction &fraction, Rounding rounding = defaultRounding,
|
||||
RoundingBits *roundingBits = nullptr);
|
||||
|
||||
// Rounds a result, if necessary, in place.
|
||||
|
|
|
@ -41,21 +41,21 @@ std::optional<SubscriptIntegerExpr> Triplet::lower() const {
|
|||
if (lower_) {
|
||||
return {**lower_};
|
||||
}
|
||||
return {};
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<SubscriptIntegerExpr> Triplet::upper() const {
|
||||
if (upper_) {
|
||||
return {**upper_};
|
||||
}
|
||||
return {};
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<SubscriptIntegerExpr> Triplet::stride() const {
|
||||
if (stride_) {
|
||||
return {**stride_};
|
||||
}
|
||||
return {};
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
CoarrayRef::CoarrayRef(std::vector<const Symbol *> &&c,
|
||||
|
|
Loading…
Reference in New Issue