From 2391eb8de96a55754672c0301f72a661b0e47e2b Mon Sep 17 00:00:00 2001 From: peter klausler Date: Tue, 12 Jun 2018 15:14:18 -0700 Subject: [PATCH] [flang] COMPLEX Original-commit: flang-compiler/f18@452d602fbb5931e29f4e8450660705297c2672c5 Reviewed-on: https://github.com/flang-compiler/f18/pull/101 Tree-same-pre-rewrite: false --- flang/lib/evaluate/common.h | 4 ++ flang/lib/evaluate/complex.h | 116 ++++++++++++++++++++++++++++++++++++++++ flang/lib/evaluate/instances.cc | 8 +++ flang/lib/evaluate/integer.h | 1 + flang/lib/evaluate/type.h | 15 +++--- flang/test/evaluate/real.cc | 44 ++++++++------- 6 files changed, 160 insertions(+), 28 deletions(-) create mode 100644 flang/lib/evaluate/complex.h diff --git a/flang/lib/evaluate/common.h b/flang/lib/evaluate/common.h index 8b4bd40..fd91c25 100644 --- a/flang/lib/evaluate/common.h +++ b/flang/lib/evaluate/common.h @@ -75,6 +75,10 @@ enum class RealFlag { using RealFlags = semantics::EnumSet; template struct ValueWithRealFlags { + A AccumulateFlags(RealFlags &f) { + f |= flags; + return value; + } A value; RealFlags flags; }; diff --git a/flang/lib/evaluate/complex.h b/flang/lib/evaluate/complex.h new file mode 100644 index 0000000..f1fed7c --- /dev/null +++ b/flang/lib/evaluate/complex.h @@ -0,0 +1,116 @@ +// 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_COMPLEX_H_ +#define FORTRAN_EVALUATE_COMPLEX_H_ + +#include "real.h" + +namespace Fortran::evaluate::value { + +template class Complex { +public: + using Part = REAL_TYPE; + static constexpr int bits{2 * Part::bits}; + + constexpr Complex() {} // (+0.0, +0.0) + 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} {} + + // TODO: (C)ABS, unit testing + + constexpr const Part &REAL() const { return re_; } + constexpr const Part &AIMAG() const { return im_; } + constexpr Complex CONJG() const { return {re_, im_.Negate()}; } + constexpr Complex Negate() const { return {re_.Negate(), im_.Negate()}; } + + constexpr bool Equals(const Complex &that) const { + return re_.Compare(that.re_) == Relation::Equal && + im_.Compare(that.im_) == Relation::Equal; + } + + constexpr ValueWithRealFlags Add(const Complex &that) const { + RealFlags flags; + Part reSum{re_.Add(that.re_).AccumulateFlags(flags)}; + Part imSum{im_.Add(that.im_).AccumulateFlags(flags)}; + return {Complex{reSum, imSum}, flags}; + } + + constexpr ValueWithRealFlags Subtract(const Complex &that) const { + RealFlags flags; + Part reDiff{re_.Subtract(that.re_).AccumulateFlags(flags)}; + Part imDiff{im_.Subtract(that.im_).AccumulateFlags(flags)}; + return {Complex{reDiff, imDiff}, flags}; + } + + constexpr ValueWithRealFlags Multiply(const Complex &that) 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)}; + return {Complex{acbd, adbc}, flags}; + } + + constexpr ValueWithRealFlags Divide(const Complex &that) 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)) + // but to avoid overflows, scale by d/c if c>=d, else c/d + Part scale; // <= 1.0 + RealFlags flags; + bool cGEd{that.re_.ABS().Compare(that.im_.ABS()) != Relation::Less}; + if (cGEd) { + scale = that.im_.Divide(that.re_).AccumulateFlags(flags); + } else { + scale = that.re_.Divide(that.im_).AccumulateFlags(flags); + } + Part den; + if (cGEd) { + Part dS{scale.Multiply(that.im_).AccumulateFlags(flags)}; + den = dS.Add(that.re_).AccumulateFlags(flags); + } else { + Part cS{scale.Multiply(that.re_).AccumulateFlags(flags)}; + den = cS.Add(that.im_).AccumulateFlags(flags); + } + Part aS{scale.Multiply(re_).AccumulateFlags(flags)}; + Part bS{scale.Multiply(im_).AccumulateFlags(flags)}; + Part re1, im1; + if (cGEd) { + re1 = re_.Add(bS).AccumulateFlags(flags); + im1 = im_.Subtract(aS).AccumulateFlags(flags); + } else { + re1 = aS.Add(im_).AccumulateFlags(flags); + im1 = bS.Subtract(re_).AccumulateFlags(flags); + } + Part re{re1.Divide(den).AccumulateFlags(flags)}; + Part im{im1.Divide(den).AccumulateFlags(flags)}; + return {Complex{re, im}, flags}; + } + +private: + Part re_, im_; +}; + +extern template class Complex, 11>>; +extern template class Complex, 24>>; +extern template class Complex, 53>>; +extern template class Complex, 64, false>>; +extern template class Complex, 112>>; +} // namespace Fortran::evaluate::value +#endif // FORTRAN_EVALUATE_COMPLEX_H_ diff --git a/flang/lib/evaluate/instances.cc b/flang/lib/evaluate/instances.cc index 8d898ee..2aeffae 100644 --- a/flang/lib/evaluate/instances.cc +++ b/flang/lib/evaluate/instances.cc @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "complex.h" #include "integer.h" #include "logical.h" #include "real.h" @@ -22,6 +23,7 @@ template class Integer<8>; template class Integer<16>; template class Integer<32>; template class Integer<64>; +template class Integer<80>; template class Integer<128>; template class Real, 11>; @@ -30,6 +32,12 @@ template class Real, 53>; template class Real, 64, false>; template class Real, 112>; +template class Complex, 11>>; +template class Complex, 24>>; +template class Complex, 53>>; +template class Complex, 64, false>>; +template class Complex, 112>>; + template class Logical<8>; template class Logical<16>; template class Logical<32>; diff --git a/flang/lib/evaluate/integer.h b/flang/lib/evaluate/integer.h index edb1e2a..b525fb8 100644 --- a/flang/lib/evaluate/integer.h +++ b/flang/lib/evaluate/integer.h @@ -844,6 +844,7 @@ extern template class Integer<8>; extern template class Integer<16>; extern template class Integer<32>; extern template class Integer<64>; +extern template class Integer<80>; extern template class Integer<128>; } // namespace Fortran::evaluate::value #endif // FORTRAN_EVALUATE_INTEGER_H_ diff --git a/flang/lib/evaluate/type.h b/flang/lib/evaluate/type.h index a590d01..ad87e0f 100644 --- a/flang/lib/evaluate/type.h +++ b/flang/lib/evaluate/type.h @@ -19,6 +19,7 @@ // representation types in the evaluation library for ease of template // programming. +#include "complex.h" #include "integer.h" #include "logical.h" #include "real.h" @@ -39,19 +40,19 @@ template<> struct Real<2> { static constexpr Classification classification{Classification::Real}; static constexpr int kind{2}; static constexpr bool hasLen{false}; - using ValueType = value::Real, 11>; + using ValueType = value::Real::ValueType, 11>; }; template<> struct Real<4> { static constexpr Classification classification{Classification::Real}; static constexpr int kind{4}; static constexpr bool hasLen{false}; - using ValueType = value::Real, 24>; + using ValueType = value::Real::ValueType, 24>; }; template<> struct Real<8> { static constexpr Classification classification{Classification::Real}; static constexpr int kind{8}; static constexpr bool hasLen{false}; - using ValueType = value::Real, 53>; + using ValueType = value::Real::ValueType, 53>; }; template<> struct Real<10> { static constexpr Classification classification{Classification::Real}; @@ -63,17 +64,15 @@ template<> struct Real<16> { static constexpr Classification classification{Classification::Real}; static constexpr int kind{16}; static constexpr bool hasLen{false}; - using ValueType = value::Real, 112>; + using ValueType = value::Real::ValueType, 112>; }; -#if 0 // TODO template struct Complex { static constexpr Classification classification{Classification::Complex}; static constexpr int kind{KIND}; static constexpr bool hasLen{false}; - using ValueType = value::Complex<8 * kind>; + using ValueType = value::Complex::ValueType>; }; -#endif template struct Logical { static constexpr Classification classification{Classification::Logical}; @@ -100,9 +99,7 @@ template struct Character { using DefaultReal = Real<4>; using DefaultInteger = Integer; using IntrinsicTypeParameterType = DefaultInteger; -#if 0 // TODO using DefaultComplex = Complex<2 * DefaultReal::kind>; -#endif using DefaultLogical = Logical; #if 0 // TODO using DefaultCharacter = Character<1>; diff --git a/flang/test/evaluate/real.cc b/flang/test/evaluate/real.cc index 21e2af7..0dd7813 100644 --- a/flang/test/evaluate/real.cc +++ b/flang/test/evaluate/real.cc @@ -12,14 +12,20 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "../../lib/evaluate/real.h" #include "fp-testing.h" #include "testing.h" -#include "../../lib/evaluate/integer.h" +#include "../../lib/evaluate/type.h" #include using namespace Fortran::evaluate; -using namespace Fortran::evaluate::value; + +using Real2 = typename type::Real<2>::ValueType; +using Real4 = typename type::Real<4>::ValueType; +using Real8 = typename type::Real<8>::ValueType; +using Real10 = typename type::Real<10>::ValueType; +using Real16 = typename type::Real<16>::ValueType; +using Integer4 = typename type::Integer<4>::ValueType; +using Integer8 = typename type::Integer<8>::ValueType; template void basicTests(int rm, Rounding rounding) { char desc[64]; @@ -105,14 +111,14 @@ template void basicTests(int rm, Rounding rounding) { x <<= j; std::snprintf(ldesc, sizeof ldesc, "%s j=%d x=0x%llx rm=%d", desc, static_cast(j), static_cast(x), rm); - Integer<64> ix{x}; + Integer8 ix{x}; TEST(!ix.IsNegative())(ldesc); MATCH(x, ix.ToUInt64())(ldesc); vr = R::ConvertSigned(ix, rounding); TEST(!vr.value.IsNegative())(ldesc); TEST(!vr.value.IsNotANumber())(ldesc); TEST(!vr.value.IsZero())(ldesc); - auto ivf = vr.value.template ToInteger>(); + auto ivf = vr.value.template ToInteger(); if (j > (maxExponent / 2)) { TEST(vr.flags.test(RealFlag::Overflow))(ldesc); TEST(vr.value.IsInfinite())(ldesc); @@ -134,7 +140,7 @@ template void basicTests(int rm, Rounding rounding) { TEST(vr.value.IsNegative())(ldesc); TEST(!vr.value.IsNotANumber())(ldesc); TEST(!vr.value.IsZero())(ldesc); - ivf = vr.value.template ToInteger>(); + ivf = vr.value.template ToInteger(); if (j > (maxExponent / 2)) { TEST(vr.flags.test(RealFlag::Overflow))(ldesc); TEST(vr.value.IsInfinite())(ldesc); @@ -191,8 +197,8 @@ void inttest(std::int64_t x, int pass, Rounding rounding) { float f; } u; ScopedHostFloatingPointEnvironment fpenv; - Integer<64> ix{x}; - ValueWithRealFlags real; + Integer8 ix{x}; + ValueWithRealFlags real; real = real.value.ConvertSigned(ix, rounding); fpenv.ClearFlags(); float fcheck = x; // TODO unsigned too @@ -224,14 +230,14 @@ void subset32bit(int pass, Rounding rounding) { std::uint32_t rj{MakeReal(j)}; u.u32 = rj; float fj{u.f}; - RealKind4 x{Integer<32>{std::uint64_t{rj}}}; + Real4 x{Integer4{std::uint64_t{rj}}}; for (std::uint32_t k{0}; k < 8192; ++k) { std::uint32_t rk{MakeReal(k)}; u.u32 = rk; float fk{u.f}; - RealKind4 y{Integer<32>{std::uint64_t{rk}}}; + Real4 y{Integer4{std::uint64_t{rk}}}; { - ValueWithRealFlags sum{x.Add(y, rounding)}; + ValueWithRealFlags sum{x.Add(y, rounding)}; fpenv.ClearFlags(); float fcheck{fj + fk}; auto actualFlags{FlagsToBits(fpenv.CurrentFlags())}; @@ -243,7 +249,7 @@ void subset32bit(int pass, Rounding rounding) { ("%d 0x%x + 0x%x", pass, rj, rk); } { - ValueWithRealFlags diff{x.Subtract(y, rounding)}; + ValueWithRealFlags diff{x.Subtract(y, rounding)}; fpenv.ClearFlags(); float fcheck{fj - fk}; auto actualFlags{FlagsToBits(fpenv.CurrentFlags())}; @@ -255,7 +261,7 @@ void subset32bit(int pass, Rounding rounding) { ("%d 0x%x - 0x%x", pass, rj, rk); } { - ValueWithRealFlags prod{x.Multiply(y, rounding)}; + ValueWithRealFlags prod{x.Multiply(y, rounding)}; fpenv.ClearFlags(); float fcheck{fj * fk}; auto actualFlags{FlagsToBits(fpenv.CurrentFlags())}; @@ -267,7 +273,7 @@ void subset32bit(int pass, Rounding rounding) { ("%d 0x%x * 0x%x -> 0x%x", pass, rj, rk, rcheck); } { - ValueWithRealFlags quot{x.Divide(y, rounding)}; + ValueWithRealFlags quot{x.Divide(y, rounding)}; fpenv.ClearFlags(); float fcheck{fj / fk}; auto actualFlags{FlagsToBits(fpenv.CurrentFlags())}; @@ -283,11 +289,11 @@ void subset32bit(int pass, Rounding rounding) { } void roundTest(int rm, Rounding rounding) { - basicTests(rm, rounding); - basicTests(rm, rounding); - basicTests(rm, rounding); - basicTests(rm, rounding); - basicTests(rm, rounding); + basicTests(rm, rounding); + basicTests(rm, rounding); + basicTests(rm, rounding); + basicTests(rm, rounding); + basicTests(rm, rounding); ScopedHostFloatingPointEnvironment::SetRounding(rounding); subset32bit(rm, rounding); } -- 2.7.4