xref: /llvm-project/flang/include/flang/Evaluate/fold-designator.h (revision 5718a4256be0b357a6493a875f57ce4ff0f76459)
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