[flang] first cut at expressions
Original-commit: flang-compiler/f18@b06c5486e4 Reviewed-on: https://github.com/flang-compiler/f18/pull/111 Tree-same-pre-rewrite: false
This commit is contained in:
parent
cc13dbdde1
commit
ca1b8d80f6
|
|
@ -33,12 +33,12 @@ public:
|
|||
CHECK(p_ && "assigning null pointer to Indirection");
|
||||
p = nullptr;
|
||||
}
|
||||
Indirection(const A &x) : p_{new A(x)} {}
|
||||
Indirection(A &&p) : p_{new A(std::move(p))} {}
|
||||
template<typename... ARGS>
|
||||
Indirection(ARGS &&... args) : p_{new A(std::forward<ARGS>(args)...)} {}
|
||||
Indirection(Indirection &&that) {
|
||||
CHECK(that.p_ && "constructing Indirection from null Indirection");
|
||||
p_ = that.p_;
|
||||
Indirection(Indirection &&that) : p_{that.p_} {
|
||||
CHECK(p_ && "move construction of Indirection from null Indirection");
|
||||
that.p_ = nullptr;
|
||||
}
|
||||
~Indirection() {
|
||||
|
|
@ -46,7 +46,7 @@ public:
|
|||
p_ = nullptr;
|
||||
}
|
||||
Indirection &operator=(Indirection &&that) {
|
||||
CHECK(that.p_ && "assigning null Indirection to Indirection");
|
||||
CHECK(that.p_ && "move assignment of null Indirection to Indirection");
|
||||
auto tmp = p_;
|
||||
p_ = that.p_;
|
||||
that.p_ = tmp;
|
||||
|
|
|
|||
|
|
@ -18,3 +18,7 @@ add_library(FortranEvaluate
|
|||
logical.cc
|
||||
real.cc
|
||||
)
|
||||
|
||||
target_link_libraries(FortranEvaluate
|
||||
FortranCommon
|
||||
)
|
||||
|
|
|
|||
|
|
@ -15,21 +15,206 @@
|
|||
#ifndef FORTRAN_EVALUATE_EXPRESSION_H_
|
||||
#define FORTRAN_EVALUATE_EXPRESSION_H_
|
||||
|
||||
#include "common.h"
|
||||
#include "type.h"
|
||||
#include "../common/indirection.h"
|
||||
#include <variant>
|
||||
|
||||
namespace Fortran::evaluate {
|
||||
|
||||
template<Classification C, int KIND> struct Expression;
|
||||
template<typename T> struct Expression;
|
||||
|
||||
template<int KIND> struct Expression<Classification::Integer> {
|
||||
static constexpr Classification classification{Classification::Integer};
|
||||
static constexpr int kind{KIND};
|
||||
template<typename T> struct ExprOperand {
|
||||
template<typename... ARGS> ExprOperand(const ARGS &...args) : v{args...} {}
|
||||
template<typename... ARGS> ExprOperand(ARGS &&...args) : v{std::forward<ARGS>(args)...} {}
|
||||
common::Indirection<Expression<T>> v;
|
||||
};
|
||||
|
||||
using<int KIND> IntegerExpression = Expression<Classification::Integer, KIND>;
|
||||
using<int KIND> RealExpression = Expression<Classification::Real, KIND>;
|
||||
struct IntegerOperand {
|
||||
std::variant<
|
||||
ExprOperand<Type<Category::Integer, 1>>,
|
||||
ExprOperand<Type<Category::Integer, 2>>,
|
||||
ExprOperand<Type<Category::Integer, 4>>,
|
||||
ExprOperand<Type<Category::Integer, 8>>,
|
||||
ExprOperand<Type<Category::Integer, 16>>> u;
|
||||
};
|
||||
struct RealOperand {
|
||||
std::variant<
|
||||
ExprOperand<Type<Category::Real, 2>>,
|
||||
ExprOperand<Type<Category::Real, 4>>,
|
||||
ExprOperand<Type<Category::Real, 8>>,
|
||||
ExprOperand<Type<Category::Real, 10>>,
|
||||
ExprOperand<Type<Category::Real, 16>>> u;
|
||||
};
|
||||
struct ComplexOperand {
|
||||
std::variant<
|
||||
ExprOperand<Type<Category::Complex, 2>>,
|
||||
ExprOperand<Type<Category::Complex, 4>>,
|
||||
ExprOperand<Type<Category::Complex, 8>>,
|
||||
ExprOperand<Type<Category::Complex, 10>>,
|
||||
ExprOperand<Type<Category::Complex, 16>>> u;
|
||||
};
|
||||
struct CharacterOperand {
|
||||
std::variant<ExprOperand<Type<Category::Character, 1>>> u;
|
||||
};
|
||||
|
||||
struct FloatingOperand {
|
||||
std::variant<RealOperand, ComplexOperand> u;
|
||||
};
|
||||
struct NumericOperand {
|
||||
std::variant<IntegerOperand, FloatingOperand> u;
|
||||
};
|
||||
|
||||
template<Category C, int KIND> struct NumericBase {
|
||||
static constexpr Category category{C};
|
||||
static constexpr int kind{KIND};
|
||||
using Result = Type<category, kind>;
|
||||
using Operand = ExprOperand<Result>;
|
||||
using Constant = typename Result::Value;
|
||||
struct Unary {
|
||||
enum class Operator { Parentheses, Negate } op;
|
||||
Operand x;
|
||||
};
|
||||
struct Binary {
|
||||
enum class Operator { Add, Subtract, Multiply, Divide, Power } op;
|
||||
Operand x, y;
|
||||
};
|
||||
struct Convert {
|
||||
NumericOperand x;
|
||||
};
|
||||
};
|
||||
|
||||
template<int KIND> struct Expression<Type<Category::Integer, KIND>> : public NumericBase<Category::Integer, KIND> {
|
||||
using Base = NumericBase<Category::Integer, KIND>;
|
||||
using Result = typename Base::Result;
|
||||
using Constant = typename Base::Constant;
|
||||
using Convert = typename Base::Convert;
|
||||
using Unary = typename Base::Unary;
|
||||
using Binary = typename Base::Binary;
|
||||
Expression() = delete;
|
||||
Expression(Expression &&) = default;
|
||||
Expression(const Constant &x) : u{x} {}
|
||||
Expression(Convert &&x) : u{std::move(x)} {}
|
||||
Expression(typename Unary::Operator o, Expression &&a) : u{Unary{o, std::move(a)}} {}
|
||||
Expression(typename Binary::Operator o, Expression &&a, Expression &&b) : u{Binary{o, std::move(a), std::move(b)}} {}
|
||||
std::variant<Constant, Convert, Unary, Binary> u;
|
||||
};
|
||||
|
||||
template<Category C, int KIND> struct FloatingBase : public NumericBase<C, KIND> {
|
||||
using Result = typename NumericBase<C, KIND>::Result;
|
||||
struct IntegerPower {
|
||||
Result x;
|
||||
IntegerOperand y;
|
||||
};
|
||||
};
|
||||
|
||||
template<int KIND> struct Expression<Type<Category::Real, KIND>> : public FloatingBase<Category::Real, KIND> {
|
||||
using Base = FloatingBase<Category::Real, KIND>;
|
||||
using Result = typename Base::Result;
|
||||
using Constant = typename Base::Constant;
|
||||
using Convert = typename Base::Convert;
|
||||
using Unary = typename Base::Unary;
|
||||
using Binary = typename Base::Binary;
|
||||
using IntegerPower = typename Base::IntegerPower;
|
||||
Expression() = delete;
|
||||
Expression(Expression &&) = default;
|
||||
Expression(const Constant &x) : u{x} {}
|
||||
Expression(Convert &&x) : u{std::move(x)} {}
|
||||
Expression(typename Unary::Operator o, Expression &&a) : u{Unary{o, std::move(a)}} {}
|
||||
Expression(typename Binary::Operator o, Expression &&a, Expression &&b) : u{Binary{o, std::move(a), std::move(b)}} {}
|
||||
std::variant<Constant, Convert, Unary, Binary, IntegerPower> u;
|
||||
};
|
||||
|
||||
template<int KIND> struct Expression<Type<Category::Complex, KIND>> : public FloatingBase<Category::Complex, KIND> {
|
||||
using Base = FloatingBase<Category::Complex, KIND>;
|
||||
using Result = typename Base::Result;
|
||||
using Constant = typename Base::Constant;
|
||||
using Convert = typename Base::Convert;
|
||||
using Unary = typename Base::Unary;
|
||||
using Binary = typename Base::Binary;
|
||||
using IntegerPower = typename Base::IntegerPower;
|
||||
Expression() = delete;
|
||||
Expression(Expression &&) = default;
|
||||
Expression(const Constant &x) : u{x} {}
|
||||
Expression(Convert &&x) : u{std::move(x)} {}
|
||||
Expression(typename Unary::Operator o, Expression &&a) : u{Unary{o, std::move(a)}} {}
|
||||
Expression(typename Binary::Operator o, Expression &&a, Expression &&b) : u{Binary{o, std::move(a), std::move(b)}} {}
|
||||
std::variant<Constant, Convert, Unary, Binary, IntegerPower> u;
|
||||
};
|
||||
|
||||
template<> struct Expression<Type<Category::Logical, 1>> {
|
||||
// No need to distinguish the various kinds of LOGICAL in expressions.
|
||||
static constexpr Category category{Category::Logical};
|
||||
static constexpr int kind{1};
|
||||
using Result = Type<category, kind>;
|
||||
using Operand = ExprOperand<Result>;
|
||||
using Constant = typename Result::Value;
|
||||
|
||||
struct Unary {
|
||||
enum class Operator { Not } op;
|
||||
Operand x;
|
||||
};
|
||||
struct Binary {
|
||||
enum class Operator { And, Or, Eqv, Neqv } op;
|
||||
Operand x, y;
|
||||
};
|
||||
|
||||
enum class ComparisonOperator { LT, LE, EQ, NE, GE, GT }; // TODO: .UN.?
|
||||
template<typename T>
|
||||
struct Comparison {
|
||||
ComparisonOperator op;
|
||||
ExprOperand<T> x, y;
|
||||
};
|
||||
|
||||
enum class EqualityOperator { EQ, NE };
|
||||
template<int KIND>
|
||||
struct ComplexComparison {
|
||||
EqualityOperator op;
|
||||
ExprOperand<Type<Category::Complex, KIND>> x, y;
|
||||
};
|
||||
|
||||
Expression() = delete;
|
||||
Expression(Expression &&) = default;
|
||||
Expression(const Constant &x) : u{x} {}
|
||||
Expression(typename Unary::Operator o, Expression &&a) : u{Unary{o, std::move(a)}} {}
|
||||
Expression(typename Binary::Operator o, Expression &&a, Expression &&b) : u{Binary{o, std::move(a), std::move(b)}} {}
|
||||
template<typename T>
|
||||
Expression(ComparisonOperator o, Expression<T> &&a, Expression<T> &&b) : u{Comparison<T>{o, std::move(a), std::move(b)}} {}
|
||||
template<int KIND>
|
||||
Expression(EqualityOperator o, Expression<Type<Category::Complex, KIND>> &&a, Expression<Type<Category::Complex, KIND>> &&b) : u{ComplexComparison<KIND>{o, std::move(a), std::move(b)}} {}
|
||||
std::variant<Constant, Unary, Binary,
|
||||
Comparison<Type<Category::Integer, 1>>,
|
||||
Comparison<Type<Category::Integer, 2>>,
|
||||
Comparison<Type<Category::Integer, 4>>,
|
||||
Comparison<Type<Category::Integer, 8>>,
|
||||
Comparison<Type<Category::Integer, 16>>,
|
||||
Comparison<Type<Category::Character, 1>>,
|
||||
Comparison<Type<Category::Real, 2>>,
|
||||
Comparison<Type<Category::Real, 4>>,
|
||||
Comparison<Type<Category::Real, 8>>,
|
||||
Comparison<Type<Category::Real, 10>>,
|
||||
Comparison<Type<Category::Real, 16>>,
|
||||
ComplexComparison<2>,
|
||||
ComplexComparison<4>,
|
||||
ComplexComparison<8>,
|
||||
ComplexComparison<10>,
|
||||
ComplexComparison<16>> u;
|
||||
};
|
||||
|
||||
template<int KIND> struct Expression<Type<Category::Character, KIND>> {
|
||||
static constexpr Category category{Category::Character};
|
||||
static constexpr int kind{KIND};
|
||||
using Result = Type<category, kind>;
|
||||
using Constant = typename Result::Value;
|
||||
struct Concat {
|
||||
ExprOperand<Result> x, y;
|
||||
};
|
||||
Expression() = delete;
|
||||
Expression(Expression &&) = default;
|
||||
Expression(const Constant &x) : u{x} {}
|
||||
Expression(Expression &&a, Expression &&b) : u{Concat{std::move(a), std::move(b)}} {}
|
||||
std::variant<Constant, Concat> u;
|
||||
// TODO: length
|
||||
};
|
||||
} // namespace Fortran::evaluate
|
||||
#endif // FORTRAN_EVALUATE_EXPRESSION_H_
|
||||
|
|
|
|||
|
|
@ -26,69 +26,64 @@
|
|||
#include "real.h"
|
||||
#include <string>
|
||||
|
||||
namespace Fortran::evaluate::type {
|
||||
namespace Fortran::evaluate {
|
||||
|
||||
enum class Classification { Integer, Real, Complex, Character, Logical };
|
||||
enum class Category { Integer, Real, Complex, Character, Logical, Derived };
|
||||
|
||||
template<int KIND> struct Integer {
|
||||
static constexpr Classification classification{Classification::Integer};
|
||||
template<Category C, int KIND> struct TypeBase {
|
||||
static constexpr Category category{C};
|
||||
static constexpr int kind{KIND};
|
||||
static constexpr bool hasLen{false};
|
||||
using ValueType = value::Integer<8 * kind>;
|
||||
};
|
||||
|
||||
template<int KIND> struct Real;
|
||||
template<> struct Real<2> {
|
||||
static constexpr Classification classification{Classification::Real};
|
||||
static constexpr int kind{2};
|
||||
static constexpr bool hasLen{false};
|
||||
using ValueType = value::Real<typename Integer<kind>::ValueType, 11>;
|
||||
template<Category C, int KIND> struct Type;
|
||||
|
||||
template<int KIND> struct Type<Category::Integer, KIND>
|
||||
: public TypeBase<Category::Integer, KIND> {
|
||||
using Value = value::Integer<8 * KIND>;
|
||||
};
|
||||
template<> struct Real<4> {
|
||||
static constexpr Classification classification{Classification::Real};
|
||||
static constexpr int kind{4};
|
||||
static constexpr bool hasLen{false};
|
||||
using ValueType = value::Real<typename Integer<kind>::ValueType, 24>;
|
||||
|
||||
template<> struct Type<Category::Real, 2>
|
||||
: public TypeBase<Category::Real, 2> {
|
||||
using Value = value::Real<typename Type<Category::Integer, 2>::Value, 11>;
|
||||
};
|
||||
template<> struct Real<8> {
|
||||
static constexpr Classification classification{Classification::Real};
|
||||
static constexpr int kind{8};
|
||||
static constexpr bool hasLen{false};
|
||||
using ValueType = value::Real<typename Integer<kind>::ValueType, 53>;
|
||||
|
||||
template<> struct Type<Category::Real, 4>
|
||||
: public TypeBase<Category::Real, 4> {
|
||||
using Value = value::Real<typename Type<Category::Integer, 4>::Value, 24>;
|
||||
};
|
||||
template<> struct Real<10> {
|
||||
static constexpr Classification classification{Classification::Real};
|
||||
static constexpr int kind{10};
|
||||
static constexpr bool hasLen{false};
|
||||
using ValueType = value::Real<value::Integer<80>, 64, false>;
|
||||
|
||||
template<> struct Type<Category::Real, 8>
|
||||
: public TypeBase<Category::Real, 8> {
|
||||
using Value = value::Real<typename Type<Category::Integer, 8>::Value, 53>;
|
||||
};
|
||||
template<> struct Real<16> {
|
||||
static constexpr Classification classification{Classification::Real};
|
||||
static constexpr int kind{16};
|
||||
static constexpr bool hasLen{false};
|
||||
using ValueType = value::Real<typename Integer<kind>::ValueType, 112>;
|
||||
|
||||
template<> struct Type<Category::Real, 10>
|
||||
: public TypeBase<Category::Real, 10> {
|
||||
using Value = value::Real<value::Integer<80>, 64, false>;
|
||||
};
|
||||
|
||||
template<> struct Type<Category::Real, 16>
|
||||
: public TypeBase<Category::Real, 16> {
|
||||
using Value = value::Real<typename Type<Category::Integer, 16>::Value, 112>;
|
||||
};
|
||||
|
||||
// The KIND type parameter on COMPLEX is the kind of each of its components.
|
||||
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<typename Real<kind>::ValueType>;
|
||||
template<int KIND> struct Type<Category::Complex, KIND>
|
||||
: public TypeBase<Category::Complex, KIND> {
|
||||
using Value = value::Complex<typename Type<Category::Real, KIND>::Value>;
|
||||
};
|
||||
|
||||
template<int KIND> struct Logical {
|
||||
static constexpr Classification classification{Classification::Logical};
|
||||
static constexpr int kind{KIND};
|
||||
static constexpr bool hasLen{false};
|
||||
using ValueType = value::Logical<8 * kind>;
|
||||
template<int KIND> struct Type<Category::Logical, KIND>
|
||||
: public TypeBase<Category::Logical, KIND> {
|
||||
using Value = value::Logical<8 * KIND>;
|
||||
};
|
||||
|
||||
template<int KIND> struct Character {
|
||||
static constexpr Classification classification{Classification::Character};
|
||||
template<int KIND> struct Type<Category::Character, KIND> {
|
||||
static constexpr Category category{Category::Character};
|
||||
static constexpr int kind{KIND};
|
||||
static constexpr bool hasLen{true};
|
||||
using ValueType = std::string;
|
||||
using Value = std::string;
|
||||
};
|
||||
|
||||
// Default REAL just simply has to be IEEE-754 single precision today.
|
||||
|
|
@ -97,12 +92,11 @@ template<int KIND> struct Character {
|
|||
// storage unit, so their kinds are also forced. Default COMPLEX occupies
|
||||
// two numeric storage units.
|
||||
|
||||
using DefaultReal = Real<4>;
|
||||
using DefaultInteger = Integer<DefaultReal::kind>;
|
||||
using DefaultReal = Type<Category::Real, 4>;
|
||||
using DefaultInteger = Type<Category::Integer, DefaultReal::kind>;
|
||||
using IntrinsicTypeParameterType = DefaultInteger;
|
||||
using DefaultComplex = Complex<DefaultReal::kind>;
|
||||
using DefaultLogical = Logical<DefaultReal::kind>;
|
||||
using DefaultCharacter = Character<1>;
|
||||
|
||||
using DefaultComplex = Type<Category::Complex, DefaultReal::kind>;
|
||||
using DefaultLogical = Type<Category::Logical, DefaultReal::kind>;
|
||||
using DefaultCharacter = Type<Category::Character, 1>;
|
||||
} // namespace Fortran::evaluate::type
|
||||
#endif // FORTRAN_EVALUATE_TYPE_H_
|
||||
|
|
|
|||
|
|
@ -63,6 +63,16 @@ target_link_libraries(real-test
|
|||
m
|
||||
)
|
||||
|
||||
add_executable(expression-test
|
||||
expression.cc
|
||||
)
|
||||
|
||||
target_link_libraries(expression-test
|
||||
FortranEvaluate
|
||||
FortranEvaluateTesting
|
||||
)
|
||||
|
||||
add_test(NAME Expression COMMAND expression-test)
|
||||
add_test(NAME Leadz COMMAND leading-zero-bit-count-test)
|
||||
add_test(NAME PopPar COMMAND bit-population-count-test)
|
||||
add_test(NAME Integer COMMAND integer-test)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,32 @@
|
|||
// 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.
|
||||
|
||||
#include "testing.h"
|
||||
#include "../../lib/evaluate/expression.h"
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
|
||||
using namespace Fortran::evaluate;
|
||||
|
||||
int main() {
|
||||
using Int4 = Type<Category::Integer, 4>;
|
||||
using IntEx4 = Expression<Int4>;
|
||||
auto ie = IntEx4{value::Integer<32>(666)};
|
||||
auto one = IntEx4{value::Integer<32>(1)};
|
||||
auto incr = IntEx4{IntEx4::Binary::Operator::Add, std::move(ie), std::move(one)};
|
||||
using Log = Expression<Type<Category::Logical, 1>>;
|
||||
auto two = IntEx4{value::Integer<32>(2)};
|
||||
auto cmp = Log{Log::ComparisonOperator::EQ, std::move(incr), std::move(two)};
|
||||
return testing::Complete();
|
||||
}
|
||||
|
|
@ -16,14 +16,12 @@
|
|||
#include "../../lib/evaluate/type.h"
|
||||
#include <cstdio>
|
||||
|
||||
using namespace Fortran::evaluate::type;
|
||||
|
||||
template<int KIND> void testKind() {
|
||||
using Type = Logical<KIND>;
|
||||
TEST(Type::classification == Classification::Logical);
|
||||
using Type = Fortran::evaluate::Type<Fortran::evaluate::Category::Logical, KIND>;
|
||||
TEST(Type::category == Fortran::evaluate::Category::Logical);
|
||||
TEST(Type::kind == KIND);
|
||||
TEST(!Type::hasLen);
|
||||
using Value = typename Type::ValueType;
|
||||
using Value = typename Type::Value;
|
||||
MATCH(8 * KIND, Value::bits);
|
||||
TEST(!Value{}.IsTrue());
|
||||
TEST(!Value{false}.IsTrue());
|
||||
|
|
|
|||
|
|
@ -20,13 +20,13 @@
|
|||
|
||||
using namespace Fortran::evaluate;
|
||||
|
||||
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;
|
||||
using Real2 = typename Type<Category::Real, 2>::Value;
|
||||
using Real4 = typename Type<Category::Real, 4>::Value;
|
||||
using Real8 = typename Type<Category::Real, 8>::Value;
|
||||
using Real10 = typename Type<Category::Real, 10>::Value;
|
||||
using Real16 = typename Type<Category::Real, 16>::Value;
|
||||
using Integer4 = typename Type<Category::Integer, 4>::Value;
|
||||
using Integer8 = typename Type<Category::Integer, 8>::Value;
|
||||
|
||||
template<typename R> void basicTests(int rm, Rounding rounding) {
|
||||
char desc[64];
|
||||
|
|
@ -361,4 +361,5 @@ int main() {
|
|||
roundTest(2, Rounding::Up, opds);
|
||||
roundTest(3, Rounding::Down, opds);
|
||||
// TODO: how to test Rounding::TiesAwayFromZero on x86?
|
||||
return testing::Complete();
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue