1 //===-- include/flang/Evaluate/fold-designator.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_FOLD_DESIGNATOR_H_ 10 #define FORTRAN_EVALUATE_FOLD_DESIGNATOR_H_ 11 12 // Resolves a designator at compilation time to a base symbol, a byte offset 13 // from that symbol, and a byte size. Also resolves in the reverse direction, 14 // reconstructing a designator from a symbol, byte offset, and size. 15 // Used for resolving variables in DATA statements to ranges in their 16 // initial images. 17 // Some designators can also be folded into constant pointer descriptors, 18 // which also have per-dimension extent and stride information suitable 19 // for initializing a descriptor. 20 // (The designators that cannot be folded are those with vector-valued 21 // subscripts; they are allowed as DATA statement objects, but are not valid 22 // initial pointer targets.) 23 24 #include "common.h" 25 #include "expression.h" 26 #include "fold.h" 27 #include "shape.h" 28 #include "type.h" 29 #include "variable.h" 30 #include <optional> 31 #include <variant> 32 33 namespace Fortran::evaluate { 34 35 using common::ConstantSubscript; 36 37 // Identifies a single contiguous interval of bytes at a fixed offset 38 // from a known symbol. 39 class OffsetSymbol { 40 public: OffsetSymbol(const Symbol & symbol,std::size_t bytes)41 OffsetSymbol(const Symbol &symbol, std::size_t bytes) 42 : symbol_{symbol}, size_{bytes} {} DECLARE_CONSTRUCTORS_AND_ASSIGNMENTS(OffsetSymbol)43 DECLARE_CONSTRUCTORS_AND_ASSIGNMENTS(OffsetSymbol) 44 45 const Symbol &symbol() const { return *symbol_; } set_symbol(const Symbol & symbol)46 void set_symbol(const Symbol &symbol) { symbol_ = symbol; }; offset()47 ConstantSubscript offset() const { return offset_; } Augment(ConstantSubscript n)48 void Augment(ConstantSubscript n) { offset_ += n; } size()49 std::size_t size() const { return size_; } set_size(std::size_t bytes)50 void set_size(std::size_t bytes) { size_ = bytes; } 51 52 private: 53 SymbolRef symbol_; 54 ConstantSubscript offset_{0}; 55 std::size_t size_; 56 }; 57 58 // Folds a Designator<T> into a sequence of OffsetSymbols, if it can 59 // be so folded. Array sections yield multiple results, each 60 // corresponding to an element in array element order. 61 class DesignatorFolder { 62 public: 63 explicit DesignatorFolder(FoldingContext &c, bool getLastComponent = false) 64 : context_{c}, getLastComponent_{getLastComponent} {} 65 isEmpty()66 bool isEmpty() const { return isEmpty_; } isOutOfRange()67 bool isOutOfRange() const { return isOutOfRange_; } 68 69 template <typename T> FoldDesignator(const Expr<T> & expr)70 std::optional<OffsetSymbol> FoldDesignator(const Expr<T> &expr) { 71 return common::visit( 72 [&](const auto &x) { return FoldDesignator(x, elementNumber_++); }, 73 expr.u); 74 } 75 76 private: 77 std::optional<OffsetSymbol> FoldDesignator(const Symbol &, ConstantSubscript); FoldDesignator(const SymbolRef & x,ConstantSubscript which)78 std::optional<OffsetSymbol> FoldDesignator( 79 const SymbolRef &x, ConstantSubscript which) { 80 return FoldDesignator(*x, which); 81 } 82 std::optional<OffsetSymbol> FoldDesignator( 83 const ArrayRef &, ConstantSubscript); 84 std::optional<OffsetSymbol> FoldDesignator( 85 const Component &, ConstantSubscript); 86 std::optional<OffsetSymbol> FoldDesignator( 87 const ComplexPart &, ConstantSubscript); 88 std::optional<OffsetSymbol> FoldDesignator( 89 const Substring &, ConstantSubscript); 90 std::optional<OffsetSymbol> FoldDesignator( 91 const DataRef &, ConstantSubscript); 92 std::optional<OffsetSymbol> FoldDesignator( 93 const NamedEntity &, ConstantSubscript); 94 std::optional<OffsetSymbol> FoldDesignator( 95 const CoarrayRef &, ConstantSubscript); 96 std::optional<OffsetSymbol> FoldDesignator( 97 const ProcedureDesignator &, ConstantSubscript); 98 99 template <typename T> FoldDesignator(const Expr<T> & expr,ConstantSubscript which)100 std::optional<OffsetSymbol> FoldDesignator( 101 const Expr<T> &expr, ConstantSubscript which) { 102 return common::visit( 103 [&](const auto &x) { return FoldDesignator(x, which); }, expr.u); 104 } 105 106 template <typename A> FoldDesignator(const A &,ConstantSubscript)107 std::optional<OffsetSymbol> FoldDesignator(const A &, ConstantSubscript) { 108 return std::nullopt; 109 } 110 111 template <typename T> FoldDesignator(const Designator<T> & designator,ConstantSubscript which)112 std::optional<OffsetSymbol> FoldDesignator( 113 const Designator<T> &designator, ConstantSubscript which) { 114 return common::visit( 115 [&](const auto &x) { return FoldDesignator(x, which); }, designator.u); 116 } 117 template <int KIND> FoldDesignator(const Designator<Type<TypeCategory::Character,KIND>> & designator,ConstantSubscript which)118 std::optional<OffsetSymbol> FoldDesignator( 119 const Designator<Type<TypeCategory::Character, KIND>> &designator, 120 ConstantSubscript which) { 121 return common::visit( 122 common::visitors{ 123 [&](const Substring &ss) { 124 if (const auto *dataRef{ss.GetParentIf<DataRef>()}) { 125 if (auto result{FoldDesignator(*dataRef, which)}) { 126 if (auto start{ToInt64(ss.lower())}) { 127 std::optional<ConstantSubscript> end; 128 auto len{dataRef->LEN()}; 129 if (ss.upper()) { 130 end = ToInt64(*ss.upper()); 131 } else if (len) { 132 end = ToInt64(*len); 133 } 134 if (end) { 135 if (*start < 1) { 136 isOutOfRange_ = true; 137 } 138 result->Augment(KIND * (*start - 1)); 139 result->set_size( 140 *end >= *start ? KIND * (*end - *start + 1) : 0); 141 if (len) { 142 if (auto lenVal{ToInt64(*len)}) { 143 if (*end > *lenVal) { 144 isOutOfRange_ = true; 145 } 146 } 147 } 148 return result; 149 } 150 } 151 } 152 } 153 return std::optional<OffsetSymbol>{}; 154 }, 155 [&](const auto &x) { return FoldDesignator(x, which); }, 156 }, 157 designator.u); 158 } 159 160 FoldingContext &context_; 161 bool getLastComponent_{false}; 162 ConstantSubscript elementNumber_{0}; // zero-based 163 bool isEmpty_{false}; 164 bool isOutOfRange_{false}; 165 }; 166 167 // Reconstructs a Designator<> from a symbol and an offset. 168 std::optional<Expr<SomeType>> OffsetToDesignator( 169 FoldingContext &, const Symbol &, ConstantSubscript offset, std::size_t); 170 std::optional<Expr<SomeType>> OffsetToDesignator( 171 FoldingContext &, const OffsetSymbol &); 172 173 // Represents a compile-time constant Descriptor suitable for use 174 // as a pointer initializer. Lower bounds are always 1. 175 struct ConstantObjectPointer : public OffsetSymbol { 176 struct Dimension { 177 ConstantSubscript byteStride; 178 ConstantSubscript extent; 179 }; 180 using Dimensions = std::vector<Dimension>; 181 ConstantObjectPointerConstantObjectPointer182 ConstantObjectPointer( 183 const Symbol &symbol, std::size_t size, Dimensions &&dims) 184 : OffsetSymbol{symbol, size}, dimensions{std::move(dims)} {} 185 186 // Folds a designator to a constant pointer. Crashes on failure. 187 // Use IsInitialDataTarget() to validate the expression beforehand. 188 static ConstantObjectPointer From(FoldingContext &, const Expr<SomeType> &); 189 190 Dimensions dimensions; 191 }; 192 193 } // namespace Fortran::evaluate 194 #endif // FORTRAN_EVALUATE_FOLD_DESIGNATOR_H_ 195