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: DesignatorFolder(FoldingContext & c)63 explicit DesignatorFolder(FoldingContext &c) : context_{c} {} 64 isEmpty()65 bool isEmpty() const { return isEmpty_; } isOutOfRange()66 bool isOutOfRange() const { return isOutOfRange_; } 67 68 template <typename T> FoldDesignator(const Expr<T> & expr)69 std::optional<OffsetSymbol> FoldDesignator(const Expr<T> &expr) { 70 return std::visit( 71 [&](const auto &x) { return FoldDesignator(x, elementNumber_++); }, 72 expr.u); 73 } 74 75 private: 76 std::optional<OffsetSymbol> FoldDesignator(const Symbol &, ConstantSubscript); FoldDesignator(const SymbolRef & x,ConstantSubscript which)77 std::optional<OffsetSymbol> FoldDesignator( 78 const SymbolRef &x, ConstantSubscript which) { 79 return FoldDesignator(*x, which); 80 } 81 std::optional<OffsetSymbol> FoldDesignator( 82 const ArrayRef &, ConstantSubscript); 83 std::optional<OffsetSymbol> FoldDesignator( 84 const Component &, ConstantSubscript); 85 std::optional<OffsetSymbol> FoldDesignator( 86 const ComplexPart &, ConstantSubscript); 87 std::optional<OffsetSymbol> FoldDesignator( 88 const Substring &, ConstantSubscript); 89 std::optional<OffsetSymbol> FoldDesignator( 90 const DataRef &, ConstantSubscript); 91 std::optional<OffsetSymbol> FoldDesignator( 92 const NamedEntity &, ConstantSubscript); 93 std::optional<OffsetSymbol> FoldDesignator( 94 const CoarrayRef &, ConstantSubscript); 95 std::optional<OffsetSymbol> FoldDesignator( 96 const ProcedureDesignator &, ConstantSubscript); 97 98 template <typename T> FoldDesignator(const Expr<T> & expr,ConstantSubscript which)99 std::optional<OffsetSymbol> FoldDesignator( 100 const Expr<T> &expr, ConstantSubscript which) { 101 return std::visit( 102 [&](const auto &x) { return FoldDesignator(x, which); }, expr.u); 103 } 104 105 template <typename A> FoldDesignator(const A & x,ConstantSubscript)106 std::optional<OffsetSymbol> FoldDesignator(const A &x, ConstantSubscript) { 107 return std::nullopt; 108 } 109 110 template <typename T> FoldDesignator(const Designator<T> & designator,ConstantSubscript which)111 std::optional<OffsetSymbol> FoldDesignator( 112 const Designator<T> &designator, ConstantSubscript which) { 113 return std::visit( 114 [&](const auto &x) { return FoldDesignator(x, which); }, designator.u); 115 } 116 template <int KIND> FoldDesignator(const Designator<Type<TypeCategory::Character,KIND>> & designator,ConstantSubscript which)117 std::optional<OffsetSymbol> FoldDesignator( 118 const Designator<Type<TypeCategory::Character, KIND>> &designator, 119 ConstantSubscript which) { 120 return std::visit( 121 common::visitors{ 122 [&](const Substring &ss) { 123 if (const auto *dataRef{ss.GetParentIf<DataRef>()}) { 124 if (auto result{FoldDesignator(*dataRef, which)}) { 125 if (auto start{ToInt64(ss.lower())}) { 126 std::optional<ConstantSubscript> end; 127 auto len{dataRef->LEN()}; 128 if (ss.upper()) { 129 end = ToInt64(*ss.upper()); 130 } else if (len) { 131 end = ToInt64(*len); 132 } 133 if (end) { 134 if (*start < 1) { 135 isOutOfRange_ = true; 136 } 137 result->Augment(KIND * (*start - 1)); 138 result->set_size( 139 *end >= *start ? KIND * (*end - *start + 1) : 0); 140 if (len) { 141 if (auto lenVal{ToInt64(*len)}) { 142 if (*end > *lenVal) { 143 isOutOfRange_ = true; 144 } 145 } 146 } 147 return result; 148 } 149 } 150 } 151 } 152 return std::optional<OffsetSymbol>{}; 153 }, 154 [&](const auto &x) { return FoldDesignator(x, which); }, 155 }, 156 designator.u); 157 } 158 159 FoldingContext &context_; 160 ConstantSubscript elementNumber_{0}; // zero-based 161 bool isEmpty_{false}; 162 bool isOutOfRange_{false}; 163 }; 164 165 // Reconstructs a Designator<> from a symbol and an offset. 166 std::optional<Expr<SomeType>> OffsetToDesignator( 167 FoldingContext &, const Symbol &, ConstantSubscript offset, std::size_t); 168 std::optional<Expr<SomeType>> OffsetToDesignator( 169 FoldingContext &, const OffsetSymbol &); 170 171 // Represents a compile-time constant Descriptor suitable for use 172 // as a pointer initializer. Lower bounds are always 1. 173 struct ConstantObjectPointer : public OffsetSymbol { 174 struct Dimension { 175 ConstantSubscript byteStride; 176 ConstantSubscript extent; 177 }; 178 using Dimensions = std::vector<Dimension>; 179 ConstantObjectPointerConstantObjectPointer180 ConstantObjectPointer( 181 const Symbol &symbol, std::size_t size, Dimensions &&dims) 182 : OffsetSymbol{symbol, size}, dimensions{std::move(dims)} {} 183 184 // Folds a designator to a constant pointer. Crashes on failure. 185 // Use IsInitialDataTarget() to validate the expression beforehand. 186 static ConstantObjectPointer From(FoldingContext &, const Expr<SomeType> &); 187 188 Dimensions dimensions; 189 }; 190 191 } // namespace Fortran::evaluate 192 #endif // FORTRAN_EVALUATE_FOLD_DESIGNATOR_H_ 193