1 //===-- include/flang/Evaluate/constant.h -----------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #ifndef FORTRAN_EVALUATE_CONSTANT_H_ 10 #define FORTRAN_EVALUATE_CONSTANT_H_ 11 12 #include "formatting.h" 13 #include "type.h" 14 #include "flang/Common/default-kinds.h" 15 #include "flang/Common/reference.h" 16 #include <map> 17 #include <vector> 18 19 namespace llvm { 20 class raw_ostream; 21 } 22 23 namespace Fortran::semantics { 24 class Symbol; 25 } 26 27 namespace Fortran::evaluate { 28 29 using semantics::Symbol; 30 using SymbolRef = common::Reference<const Symbol>; 31 32 // Wraps a constant value in a class templated by its resolved type. 33 // This Constant<> template class should be instantiated only for 34 // concrete intrinsic types and SomeDerived. There is no instance 35 // Constant<SomeType> since there is no way to constrain each 36 // element of its array to hold the same type. To represent a generic 37 // constant, use a generic expression like Expr<SomeInteger> or 38 // Expr<SomeType>) to wrap the appropriate instantiation of Constant<>. 39 40 template <typename> class Constant; 41 42 // When describing shapes of constants or specifying 1-based subscript 43 // values as indices into constants, use a vector of integers. 44 using ConstantSubscripts = std::vector<ConstantSubscript>; 45 inline int GetRank(const ConstantSubscripts &s) { 46 return static_cast<int>(s.size()); 47 } 48 49 // Returns the number of elements of shape, if no overflow occurs. 50 std::optional<uint64_t> TotalElementCount(const ConstantSubscripts &shape); 51 52 // Validate dimension re-ordering like ORDER in RESHAPE. 53 // On success, return a vector that can be used as dimOrder in 54 // ConstantBounds::IncrementSubscripts(). 55 std::optional<std::vector<int>> ValidateDimensionOrder( 56 int rank, const std::vector<int> &order); 57 58 bool HasNegativeExtent(const ConstantSubscripts &); 59 60 class ConstantBounds { 61 public: 62 ConstantBounds() = default; 63 explicit ConstantBounds(const ConstantSubscripts &shape); 64 explicit ConstantBounds(ConstantSubscripts &&shape); 65 ~ConstantBounds(); 66 const ConstantSubscripts &shape() const { return shape_; } 67 int Rank() const { return GetRank(shape_); } 68 static constexpr int Corank() { return 0; } 69 Constant<SubscriptInteger> SHAPE() const; 70 71 // It is possible in this representation for a constant array to have 72 // lower bounds other than 1, which is of course not expressible in 73 // Fortran. This case arises only from definitions of named constant 74 // arrays with such bounds, as in: 75 // REAL, PARAMETER :: NAMED(0:1) = [1.,2.] 76 // Bundling the lower bounds of the named constant with its 77 // constant value allows folding of subscripted array element 78 // references, LBOUND, and UBOUND without having to thread the named 79 // constant or its bounds throughout folding. 80 const ConstantSubscripts &lbounds() const { return lbounds_; } 81 ConstantSubscripts ComputeUbounds(std::optional<int> dim) const; 82 void set_lbounds(ConstantSubscripts &&); 83 void SetLowerBoundsToOne(); 84 bool HasNonDefaultLowerBound() const; 85 86 // If no optional dimension order argument is passed, increments a vector of 87 // subscripts in Fortran array order (first dimension varying most quickly). 88 // Otherwise, increments the vector of subscripts according to the given 89 // dimension order (dimension dimOrder[0] varying most quickly; dimension 90 // indexing is zero based here). Returns false when last element was visited. 91 bool IncrementSubscripts( 92 ConstantSubscripts &, const std::vector<int> *dimOrder = nullptr) const; 93 94 protected: 95 ConstantSubscript SubscriptsToOffset(const ConstantSubscripts &) const; 96 97 private: 98 ConstantSubscripts shape_; 99 ConstantSubscripts lbounds_; 100 }; 101 102 // Constant<> is specialized for Character kinds and SomeDerived. 103 // The non-Character intrinsic types, and SomeDerived, share enough 104 // common behavior that they use this common base class. 105 template <typename RESULT, typename ELEMENT = Scalar<RESULT>> 106 class ConstantBase : public ConstantBounds { 107 static_assert(RESULT::category != TypeCategory::Character); 108 109 public: 110 using Result = RESULT; 111 using Element = ELEMENT; 112 113 template <typename A> 114 ConstantBase(const A &x, Result res = Result{}) : result_{res}, values_{x} {} 115 ConstantBase(ELEMENT &&x, Result res = Result{}) 116 : result_{res}, values_{std::move(x)} {} 117 ConstantBase( 118 std::vector<Element> &&, ConstantSubscripts &&, Result = Result{}); 119 120 DEFAULT_CONSTRUCTORS_AND_ASSIGNMENTS(ConstantBase) 121 ~ConstantBase(); 122 123 bool operator==(const ConstantBase &) const; 124 bool empty() const { return values_.empty(); } 125 std::size_t size() const { return values_.size(); } 126 const std::vector<Element> &values() const { return values_; } 127 constexpr Result result() const { return result_; } 128 129 constexpr DynamicType GetType() const { return result_.GetType(); } 130 llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const; 131 132 protected: 133 std::vector<Element> Reshape(const ConstantSubscripts &) const; 134 std::size_t CopyFrom(const ConstantBase &source, std::size_t count, 135 ConstantSubscripts &resultSubscripts, const std::vector<int> *dimOrder); 136 137 Result result_; 138 std::vector<Element> values_; 139 }; 140 141 template <typename T> class Constant : public ConstantBase<T> { 142 public: 143 using Result = T; 144 using Base = ConstantBase<T>; 145 using Element = Scalar<T>; 146 147 using Base::Base; 148 CLASS_BOILERPLATE(Constant) 149 150 std::optional<Scalar<T>> GetScalarValue() const { 151 if (ConstantBounds::Rank() == 0) { 152 return Base::values_.at(0); 153 } else { 154 return std::nullopt; 155 } 156 } 157 158 // Apply subscripts. Excess subscripts are ignored, including the 159 // case of a scalar. 160 Element At(const ConstantSubscripts &) const; 161 162 Constant Reshape(ConstantSubscripts &&) const; 163 std::size_t CopyFrom(const Constant &source, std::size_t count, 164 ConstantSubscripts &resultSubscripts, const std::vector<int> *dimOrder); 165 }; 166 167 template <int KIND> 168 class Constant<Type<TypeCategory::Character, KIND>> : public ConstantBounds { 169 public: 170 using Result = Type<TypeCategory::Character, KIND>; 171 using Element = Scalar<Result>; 172 173 CLASS_BOILERPLATE(Constant) 174 explicit Constant(const Scalar<Result> &); 175 explicit Constant(Scalar<Result> &&); 176 Constant( 177 ConstantSubscript length, std::vector<Element> &&, ConstantSubscripts &&); 178 ~Constant(); 179 180 bool operator==(const Constant &that) const { 181 return LEN() == that.LEN() && shape() == that.shape() && 182 values_ == that.values_; 183 } 184 bool empty() const; 185 std::size_t size() const; 186 187 const Scalar<Result> &values() const { return values_; } 188 ConstantSubscript LEN() const { return length_; } 189 bool wasHollerith() const { return wasHollerith_; } 190 void set_wasHollerith(bool yes = true) { wasHollerith_ = yes; } 191 192 std::optional<Scalar<Result>> GetScalarValue() const { 193 if (Rank() == 0) { 194 return values_; 195 } else { 196 return std::nullopt; 197 } 198 } 199 200 // Apply subscripts, if any. 201 Scalar<Result> At(const ConstantSubscripts &) const; 202 203 // Extract substring(s); returns nullopt for errors. 204 std::optional<Constant> Substring(ConstantSubscript, ConstantSubscript) const; 205 206 Constant Reshape(ConstantSubscripts &&) const; 207 llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const; 208 DynamicType GetType() const { return {KIND, length_}; } 209 std::size_t CopyFrom(const Constant &source, std::size_t count, 210 ConstantSubscripts &resultSubscripts, const std::vector<int> *dimOrder); 211 212 private: 213 Scalar<Result> values_; // one contiguous string 214 ConstantSubscript length_; 215 bool wasHollerith_{false}; 216 }; 217 218 class StructureConstructor; 219 struct ComponentCompare { 220 bool operator()(SymbolRef x, SymbolRef y) const; 221 }; 222 using StructureConstructorValues = std::map<SymbolRef, 223 common::CopyableIndirection<Expr<SomeType>>, ComponentCompare>; 224 225 template <> 226 class Constant<SomeDerived> 227 : public ConstantBase<SomeDerived, StructureConstructorValues> { 228 public: 229 using Result = SomeDerived; 230 using Element = StructureConstructorValues; 231 using Base = ConstantBase<SomeDerived, StructureConstructorValues>; 232 233 Constant(const StructureConstructor &); 234 Constant(StructureConstructor &&); 235 Constant(const semantics::DerivedTypeSpec &, 236 std::vector<StructureConstructorValues> &&, ConstantSubscripts &&); 237 Constant(const semantics::DerivedTypeSpec &, 238 std::vector<StructureConstructor> &&, ConstantSubscripts &&); 239 CLASS_BOILERPLATE(Constant) 240 241 std::optional<StructureConstructor> GetScalarValue() const; 242 StructureConstructor At(const ConstantSubscripts &) const; 243 244 bool operator==(const Constant &) const; 245 Constant Reshape(ConstantSubscripts &&) const; 246 std::size_t CopyFrom(const Constant &source, std::size_t count, 247 ConstantSubscripts &resultSubscripts, const std::vector<int> *dimOrder); 248 }; 249 250 FOR_EACH_LENGTHLESS_INTRINSIC_KIND(extern template class ConstantBase, ) 251 extern template class ConstantBase<SomeDerived, StructureConstructorValues>; 252 FOR_EACH_INTRINSIC_KIND(extern template class Constant, ) 253 254 #define INSTANTIATE_CONSTANT_TEMPLATES \ 255 FOR_EACH_LENGTHLESS_INTRINSIC_KIND(template class ConstantBase, ) \ 256 template class ConstantBase<SomeDerived, StructureConstructorValues>; \ 257 FOR_EACH_INTRINSIC_KIND(template class Constant, ) 258 } // namespace Fortran::evaluate 259 #endif // FORTRAN_EVALUATE_CONSTANT_H_ 260