From: peter klausler Date: Tue, 19 Jun 2018 21:16:01 +0000 (-0700) Subject: [flang] first cut at expressions X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=ca1b8d80f66be66cf794be66f8b1c51ae2e6e8f7;p=platform%2Fupstream%2Fllvm.git [flang] first cut at expressions Original-commit: flang-compiler/f18@b06c5486e4d80e017a9c697c79ac588a88498547 Reviewed-on: https://github.com/flang-compiler/f18/pull/111 Tree-same-pre-rewrite: false --- diff --git a/flang/lib/common/indirection.h b/flang/lib/common/indirection.h index 72b3967..1a78f30 100644 --- a/flang/lib/common/indirection.h +++ b/flang/lib/common/indirection.h @@ -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 Indirection(ARGS &&... args) : p_{new A(std::forward(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; diff --git a/flang/lib/evaluate/CMakeLists.txt b/flang/lib/evaluate/CMakeLists.txt index f7b388c..73d5c82 100644 --- a/flang/lib/evaluate/CMakeLists.txt +++ b/flang/lib/evaluate/CMakeLists.txt @@ -18,3 +18,7 @@ add_library(FortranEvaluate logical.cc real.cc ) + +target_link_libraries(FortranEvaluate + FortranCommon +) diff --git a/flang/lib/evaluate/expression.h b/flang/lib/evaluate/expression.h index a64a97a..589e17d 100644 --- a/flang/lib/evaluate/expression.h +++ b/flang/lib/evaluate/expression.h @@ -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 namespace Fortran::evaluate { -template struct Expression; +template struct Expression; -template struct Expression { - static constexpr Classification classification{Classification::Integer}; +template struct ExprOperand { + template ExprOperand(const ARGS &...args) : v{args...} {} + template ExprOperand(ARGS &&...args) : v{std::forward(args)...} {} + common::Indirection> v; +}; + +struct IntegerOperand { + std::variant< + ExprOperand>, + ExprOperand>, + ExprOperand>, + ExprOperand>, + ExprOperand>> u; +}; +struct RealOperand { + std::variant< + ExprOperand>, + ExprOperand>, + ExprOperand>, + ExprOperand>, + ExprOperand>> u; +}; +struct ComplexOperand { + std::variant< + ExprOperand>, + ExprOperand>, + ExprOperand>, + ExprOperand>, + ExprOperand>> u; +}; +struct CharacterOperand { + std::variant>> u; +}; + +struct FloatingOperand { + std::variant u; +}; +struct NumericOperand { + std::variant u; +}; + +template struct NumericBase { + static constexpr Category category{C}; static constexpr int kind{KIND}; + using Result = Type; + using Operand = ExprOperand; + 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; + }; }; -using IntegerExpression = Expression; -using RealExpression = Expression; +template struct Expression> : public NumericBase { + using Base = NumericBase; + 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 u; +}; + +template struct FloatingBase : public NumericBase { + using Result = typename NumericBase::Result; + struct IntegerPower { + Result x; + IntegerOperand y; + }; +}; +template struct Expression> : public FloatingBase { + using Base = FloatingBase; + 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 u; +}; + +template struct Expression> : public FloatingBase { + using Base = FloatingBase; + 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 u; +}; + +template<> struct Expression> { + // 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; + using Operand = ExprOperand; + 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 + struct Comparison { + ComparisonOperator op; + ExprOperand x, y; + }; + + enum class EqualityOperator { EQ, NE }; + template + struct ComplexComparison { + EqualityOperator op; + ExprOperand> 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 + Expression(ComparisonOperator o, Expression &&a, Expression &&b) : u{Comparison{o, std::move(a), std::move(b)}} {} + template + Expression(EqualityOperator o, Expression> &&a, Expression> &&b) : u{ComplexComparison{o, std::move(a), std::move(b)}} {} + std::variant>, + Comparison>, + Comparison>, + Comparison>, + Comparison>, + Comparison>, + Comparison>, + Comparison>, + Comparison>, + Comparison>, + Comparison>, + ComplexComparison<2>, + ComplexComparison<4>, + ComplexComparison<8>, + ComplexComparison<10>, + ComplexComparison<16>> u; +}; + +template struct Expression> { + static constexpr Category category{Category::Character}; + static constexpr int kind{KIND}; + using Result = Type; + using Constant = typename Result::Value; + struct Concat { + ExprOperand 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 u; + // TODO: length +}; } // namespace Fortran::evaluate #endif // FORTRAN_EVALUATE_EXPRESSION_H_ diff --git a/flang/lib/evaluate/type.h b/flang/lib/evaluate/type.h index 926c5ec..67bfb23 100644 --- a/flang/lib/evaluate/type.h +++ b/flang/lib/evaluate/type.h @@ -26,69 +26,64 @@ #include "real.h" #include -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 struct Integer { - static constexpr Classification classification{Classification::Integer}; +template struct TypeBase { + static constexpr Category category{C}; static constexpr int kind{KIND}; static constexpr bool hasLen{false}; - using ValueType = value::Integer<8 * kind>; }; -template 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::ValueType, 11>; +template struct Type; + +template struct Type + : public TypeBase { + 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::ValueType, 24>; + +template<> struct Type + : public TypeBase { + using Value = value::Real::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::ValueType, 53>; + +template<> struct Type + : public TypeBase { + using Value = value::Real::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, 64, false>; + +template<> struct Type + : public TypeBase { + using Value = value::Real::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::ValueType, 112>; + +template<> struct Type + : public TypeBase { + using Value = value::Real, 64, false>; +}; + +template<> struct Type + : public TypeBase { + using Value = value::Real::Value, 112>; }; // The KIND type parameter on COMPLEX is the kind of each of its components. -template struct Complex { - static constexpr Classification classification{Classification::Complex}; - static constexpr int kind{KIND}; - static constexpr bool hasLen{false}; - using ValueType = value::Complex::ValueType>; +template struct Type + : public TypeBase { + using Value = value::Complex::Value>; }; -template 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 struct Type + : public TypeBase { + using Value = value::Logical<8 * KIND>; }; -template struct Character { - static constexpr Classification classification{Classification::Character}; +template struct Type { + 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 struct Character { // storage unit, so their kinds are also forced. Default COMPLEX occupies // two numeric storage units. -using DefaultReal = Real<4>; -using DefaultInteger = Integer; +using DefaultReal = Type; +using DefaultInteger = Type; using IntrinsicTypeParameterType = DefaultInteger; -using DefaultComplex = Complex; -using DefaultLogical = Logical; -using DefaultCharacter = Character<1>; - +using DefaultComplex = Type; +using DefaultLogical = Type; +using DefaultCharacter = Type; } // namespace Fortran::evaluate::type #endif // FORTRAN_EVALUATE_TYPE_H_ diff --git a/flang/test/evaluate/CMakeLists.txt b/flang/test/evaluate/CMakeLists.txt index d676418..58afb2c 100644 --- a/flang/test/evaluate/CMakeLists.txt +++ b/flang/test/evaluate/CMakeLists.txt @@ -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) diff --git a/flang/test/evaluate/expression.cc b/flang/test/evaluate/expression.cc new file mode 100644 index 0000000..03501e6 --- /dev/null +++ b/flang/test/evaluate/expression.cc @@ -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 +#include + +using namespace Fortran::evaluate; + +int main() { + using Int4 = Type; + using IntEx4 = Expression; + 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>; + auto two = IntEx4{value::Integer<32>(2)}; + auto cmp = Log{Log::ComparisonOperator::EQ, std::move(incr), std::move(two)}; + return testing::Complete(); +} diff --git a/flang/test/evaluate/logical.cc b/flang/test/evaluate/logical.cc index 926e7ca..f8124dc 100644 --- a/flang/test/evaluate/logical.cc +++ b/flang/test/evaluate/logical.cc @@ -16,14 +16,12 @@ #include "../../lib/evaluate/type.h" #include -using namespace Fortran::evaluate::type; - template void testKind() { - using Type = Logical; - TEST(Type::classification == Classification::Logical); + using Type = Fortran::evaluate::Type; + 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()); diff --git a/flang/test/evaluate/real.cc b/flang/test/evaluate/real.cc index a6e24e1..fbb9a60 100644 --- a/flang/test/evaluate/real.cc +++ b/flang/test/evaluate/real.cc @@ -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::Value; +using Real4 = typename Type::Value; +using Real8 = typename Type::Value; +using Real10 = typename Type::Value; +using Real16 = typename Type::Value; +using Integer4 = typename Type::Value; +using Integer8 = typename Type::Value; template 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(); }