[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:
peter klausler 2018-06-19 14:16:01 -07:00
parent cc13dbdde1
commit ca1b8d80f6
8 changed files with 296 additions and 72 deletions

View File

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

View File

@ -18,3 +18,7 @@ add_library(FortranEvaluate
logical.cc
real.cc
)
target_link_libraries(FortranEvaluate
FortranCommon
)

View File

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

View File

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

View File

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

View File

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

View File

@ -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());

View File

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