forked from OSchip/llvm-project
[flang] COMPLEX
Original-commit: flang-compiler/f18@452d602fbb Reviewed-on: https://github.com/flang-compiler/f18/pull/101 Tree-same-pre-rewrite: false
This commit is contained in:
parent
ed71134af7
commit
2391eb8de9
|
@ -75,6 +75,10 @@ enum class RealFlag {
|
|||
using RealFlags = semantics::EnumSet<RealFlag, 5>;
|
||||
|
||||
template<typename A> struct ValueWithRealFlags {
|
||||
A AccumulateFlags(RealFlags &f) {
|
||||
f |= flags;
|
||||
return value;
|
||||
}
|
||||
A value;
|
||||
RealFlags flags;
|
||||
};
|
||||
|
|
|
@ -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<typename REAL_TYPE> 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<Complex> 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<Complex> 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<Complex> 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<Complex> 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<Real<Integer<16>, 11>>;
|
||||
extern template class Complex<Real<Integer<32>, 24>>;
|
||||
extern template class Complex<Real<Integer<64>, 53>>;
|
||||
extern template class Complex<Real<Integer<80>, 64, false>>;
|
||||
extern template class Complex<Real<Integer<128>, 112>>;
|
||||
} // namespace Fortran::evaluate::value
|
||||
#endif // FORTRAN_EVALUATE_COMPLEX_H_
|
|
@ -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<Integer<16>, 11>;
|
||||
|
@ -30,6 +32,12 @@ template class Real<Integer<64>, 53>;
|
|||
template class Real<Integer<80>, 64, false>;
|
||||
template class Real<Integer<128>, 112>;
|
||||
|
||||
template class Complex<Real<Integer<16>, 11>>;
|
||||
template class Complex<Real<Integer<32>, 24>>;
|
||||
template class Complex<Real<Integer<64>, 53>>;
|
||||
template class Complex<Real<Integer<80>, 64, false>>;
|
||||
template class Complex<Real<Integer<128>, 112>>;
|
||||
|
||||
template class Logical<8>;
|
||||
template class Logical<16>;
|
||||
template class Logical<32>;
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -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<value::Integer<16>, 11>;
|
||||
using ValueType = value::Real<typename Integer<kind>::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<value::Integer<32>, 24>;
|
||||
using ValueType = value::Real<typename Integer<kind>::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<value::Integer<64>, 53>;
|
||||
using ValueType = value::Real<typename Integer<kind>::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<value::Integer<128>, 112>;
|
||||
using ValueType = value::Real<typename Integer<kind>::ValueType, 112>;
|
||||
};
|
||||
|
||||
#if 0 // TODO
|
||||
template<int KIND> 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<typename Real<(8 * kind / 2)>::ValueType>;
|
||||
};
|
||||
#endif
|
||||
|
||||
template<int KIND> struct Logical {
|
||||
static constexpr Classification classification{Classification::Logical};
|
||||
|
@ -100,9 +99,7 @@ template<int KIND> struct Character {
|
|||
using DefaultReal = Real<4>;
|
||||
using DefaultInteger = Integer<DefaultReal::kind>;
|
||||
using IntrinsicTypeParameterType = DefaultInteger;
|
||||
#if 0 // TODO
|
||||
using DefaultComplex = Complex<2 * DefaultReal::kind>;
|
||||
#endif
|
||||
using DefaultLogical = Logical<DefaultReal::kind>;
|
||||
#if 0 // TODO
|
||||
using DefaultCharacter = Character<1>;
|
||||
|
|
|
@ -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 <cstdio>
|
||||
|
||||
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<typename R> void basicTests(int rm, Rounding rounding) {
|
||||
char desc[64];
|
||||
|
@ -105,14 +111,14 @@ template<typename R> void basicTests(int rm, Rounding rounding) {
|
|||
x <<= j;
|
||||
std::snprintf(ldesc, sizeof ldesc, "%s j=%d x=0x%llx rm=%d", desc,
|
||||
static_cast<int>(j), static_cast<unsigned long long>(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<Integer<64>>();
|
||||
auto ivf = vr.value.template ToInteger<Integer8>();
|
||||
if (j > (maxExponent / 2)) {
|
||||
TEST(vr.flags.test(RealFlag::Overflow))(ldesc);
|
||||
TEST(vr.value.IsInfinite())(ldesc);
|
||||
|
@ -134,7 +140,7 @@ template<typename R> 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<Integer<64>>();
|
||||
ivf = vr.value.template ToInteger<Integer8>();
|
||||
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<RealKind4> real;
|
||||
Integer8 ix{x};
|
||||
ValueWithRealFlags<Real4> 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<RealKind4> sum{x.Add(y, rounding)};
|
||||
ValueWithRealFlags<Real4> 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<RealKind4> diff{x.Subtract(y, rounding)};
|
||||
ValueWithRealFlags<Real4> 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<RealKind4> prod{x.Multiply(y, rounding)};
|
||||
ValueWithRealFlags<Real4> 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<RealKind4> quot{x.Divide(y, rounding)};
|
||||
ValueWithRealFlags<Real4> 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<RealKind2>(rm, rounding);
|
||||
basicTests<RealKind4>(rm, rounding);
|
||||
basicTests<RealKind8>(rm, rounding);
|
||||
basicTests<RealKind10>(rm, rounding);
|
||||
basicTests<RealKind16>(rm, rounding);
|
||||
basicTests<Real2>(rm, rounding);
|
||||
basicTests<Real4>(rm, rounding);
|
||||
basicTests<Real8>(rm, rounding);
|
||||
basicTests<Real10>(rm, rounding);
|
||||
basicTests<Real16>(rm, rounding);
|
||||
ScopedHostFloatingPointEnvironment::SetRounding(rounding);
|
||||
subset32bit(rm, rounding);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue