FLANG

fold-designator.h
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:
41 OffsetSymbol(const Symbol &symbol, std::size_t bytes)
42 : symbol_{symbol}, size_{bytes} {}
43 DECLARE_CONSTRUCTORS_AND_ASSIGNMENTS(OffsetSymbol)
44
45 const Symbol &symbol() const { return *symbol_; }
46 void set_symbol(const Symbol &symbol) { symbol_ = symbol; };
47 ConstantSubscript offset() const { return offset_; }
48 void Augment(ConstantSubscript n) { offset_ += n; }
49 std::size_t size() const { return size_; }
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) : context_{c} {}
64
65 bool isEmpty() const { return isEmpty_; }
66 bool isOutOfRange() const { return isOutOfRange_; }
67
68 template <typename T>
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);
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>
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>
106 std::optional<OffsetSymbol> FoldDesignator(const A &x, ConstantSubscript) {
107 return std::nullopt;
108 }
109
110 template <typename T>
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>
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
180 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_
Fortran::evaluate::ConstantObjectPointer
Definition: fold-designator.h:173
Fortran::evaluate::CoarrayRef
Definition: variable.h:242
Fortran::evaluate::Substring
Definition: variable.h:301
Fortran::evaluate::DesignatorFolder
Definition: fold-designator.h:61
Fortran::evaluate::Type
Definition: type.h:48
Fortran::evaluate::Component
Definition: variable.h:73
Fortran::semantics::Symbol
Definition: symbol.h:479
Fortran::evaluate::ComplexPart
Definition: variable.h:347
Fortran::evaluate::OffsetSymbol
Definition: fold-designator.h:39
Fortran::evaluate::DataRef
Definition: variable.h:286
Fortran::evaluate::ArrayRef
Definition: variable.h:196
Fortran::evaluate::FoldingContext
Definition: common.h:209
Fortran::evaluate::ProcedureDesignator
Definition: call.h:159
Fortran::common::Reference< const Symbol >
Fortran::evaluate::Designator
Definition: variable.h:369
Fortran::evaluate::NamedEntity
Definition: variable.h:99
Fortran::common::visitors
Definition: idioms.h:58
Fortran::evaluate::Expr
Definition: common.h:207
Fortran::evaluate::ConstantObjectPointer::Dimension
Definition: fold-designator.h:174