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
32namespace Fortran::evaluate {
33
34using common::ConstantSubscript;
35
36// Identifies a single contiguous interval of bytes at a fixed offset
37// from a known symbol.
38class OffsetSymbol {
39public:
40 OffsetSymbol(const Symbol &symbol, std::size_t bytes)
41 : symbol_{symbol}, size_{bytes} {}
42 DECLARE_CONSTRUCTORS_AND_ASSIGNMENTS(OffsetSymbol)
43
44 const Symbol &symbol() const { return *symbol_; }
45 void set_symbol(const Symbol &symbol) { symbol_ = symbol; };
46 ConstantSubscript offset() const { return offset_; }
47 void Augment(ConstantSubscript n) { offset_ += n; }
48 std::size_t size() const { return size_; }
49 void set_size(std::size_t bytes) { size_ = bytes; }
50
51private:
52 SymbolRef symbol_;
53 ConstantSubscript offset_{0};
54 std::size_t size_;
55};
56
57// Folds a Designator<T> into a sequence of OffsetSymbols, if it can
58// be so folded. Array sections yield multiple results, each
59// corresponding to an element in array element order.
60class DesignatorFolder {
61public:
62 // A named constant has no storage assignment, but its designators can
63 // still be folded to (offset, size) within the constant's own storage
64 // sequence, which storage sequence association checks need; opt in with
65 // foldNamedConstants. Clients that map real memory (e.g. DATA statement
66 // initialization) must keep the default.
67 explicit DesignatorFolder(FoldingContext &c, bool getLastComponent = false,
68 bool foldNamedConstants = false)
69 : context_{c}, getLastComponent_{getLastComponent},
70 foldNamedConstants_{foldNamedConstants} {}
71
72 bool isEmpty() const { return isEmpty_; }
73 bool isOutOfRange() const { return isOutOfRange_; }
74
75 template <typename T>
76 std::optional<OffsetSymbol> FoldDesignator(const Expr<T> &expr) {
77 return common::visit(
78 [&](const auto &x) { return FoldDesignator(x, elementNumber_++); },
79 expr.u);
80 }
81
82private:
83 std::optional<OffsetSymbol> FoldDesignator(const Symbol &, ConstantSubscript);
84 std::optional<OffsetSymbol> FoldDesignator(
85 const SymbolRef &x, ConstantSubscript which) {
86 return FoldDesignator(*x, which);
87 }
88 std::optional<OffsetSymbol> FoldDesignator(
89 const ArrayRef &, ConstantSubscript);
90 std::optional<OffsetSymbol> FoldDesignator(
91 const Component &, ConstantSubscript);
92 std::optional<OffsetSymbol> FoldDesignator(
93 const ComplexPart &, ConstantSubscript);
94 std::optional<OffsetSymbol> FoldDesignator(
95 const Substring &, ConstantSubscript);
96 std::optional<OffsetSymbol> FoldDesignator(
97 const DataRef &, ConstantSubscript);
98 std::optional<OffsetSymbol> FoldDesignator(
99 const NamedEntity &, ConstantSubscript);
100 std::optional<OffsetSymbol> FoldDesignator(
101 const CoarrayRef &, ConstantSubscript);
102 std::optional<OffsetSymbol> FoldDesignator(
103 const ProcedureDesignator &, ConstantSubscript);
104
105 template <typename T>
106 std::optional<OffsetSymbol> FoldDesignator(
107 const Expr<T> &expr, ConstantSubscript which) {
108 return common::visit(
109 [&](const auto &x) { return FoldDesignator(x, which); }, expr.u);
110 }
111
112 template <typename A>
113 std::optional<OffsetSymbol> FoldDesignator(const A &, ConstantSubscript) {
114 return std::nullopt;
115 }
116
117 template <typename T>
118 std::optional<OffsetSymbol> FoldDesignator(
119 const Designator<T> &designator, ConstantSubscript which) {
120 return common::visit(
121 [&](const auto &x) { return FoldDesignator(x, which); }, designator.u);
122 }
123 template <int KIND>
124 std::optional<OffsetSymbol> FoldDesignator(
126 ConstantSubscript which) {
127 return common::visit(
129 [&](const Substring &ss) {
130 if (const auto *dataRef{ss.GetParentIf<DataRef>()}) {
131 if (auto result{FoldDesignator(*dataRef, which)}) {
132 if (auto start{ToInt64(ss.lower())}) {
133 std::optional<ConstantSubscript> end;
134 auto len{dataRef->LEN()};
135 if (ss.upper()) {
136 end = ToInt64(*ss.upper());
137 } else if (len) {
138 end = ToInt64(*len);
139 }
140 if (end) {
141 if (*start < 1) {
142 isOutOfRange_ = true;
143 }
144 result->Augment(KIND * (*start - 1));
145 result->set_size(
146 *end >= *start ? KIND * (*end - *start + 1) : 0);
147 if (len) {
148 if (auto lenVal{ToInt64(*len)}) {
149 if (*end > *lenVal) {
150 isOutOfRange_ = true;
151 }
152 }
153 }
154 return result;
155 }
156 }
157 }
158 }
159 return std::optional<OffsetSymbol>{};
160 },
161 [&](const auto &x) { return FoldDesignator(x, which); },
162 },
163 designator.u);
164 }
165
166 FoldingContext &context_;
167 bool getLastComponent_{false};
168 bool foldNamedConstants_{false};
169 ConstantSubscript elementNumber_{0}; // zero-based
170 bool isEmpty_{false};
171 bool isOutOfRange_{false};
172};
173
174// Reconstructs a Designator<> from a symbol and an offset.
175std::optional<Expr<SomeType>> OffsetToDesignator(
176 FoldingContext &, const Symbol &, ConstantSubscript offset, std::size_t);
177std::optional<Expr<SomeType>> OffsetToDesignator(
178 FoldingContext &, const OffsetSymbol &);
179
180// Represents a compile-time constant Descriptor suitable for use
181// as a pointer initializer. Lower bounds are always 1.
182struct ConstantObjectPointer : public OffsetSymbol {
183 struct Dimension {
184 ConstantSubscript byteStride;
185 ConstantSubscript extent;
186 };
187 using Dimensions = std::vector<Dimension>;
188
189 ConstantObjectPointer(
190 const Symbol &symbol, std::size_t size, Dimensions &&dims)
191 : OffsetSymbol{symbol, size}, dimensions{std::move(dims)} {}
192
193 // Folds a designator to a constant pointer. Crashes on failure.
194 // Use IsInitialDataTarget() to validate the expression beforehand.
196
197 Dimensions dimensions;
198};
199
200} // namespace Fortran::evaluate
201#endif // FORTRAN_EVALUATE_FOLD_DESIGNATOR_H_
Definition variable.h:205
Definition variable.h:243
Definition variable.h:357
Definition variable.h:73
Definition variable.h:381
Definition common.h:215
Definition common.h:217
Definition variable.h:101
Definition fold-designator.h:38
Definition variable.h:304
Definition type.h:56
Definition symbol.h:916
Definition call.h:34
Definition idioms.h:60
Definition fold-designator.h:182
Definition variable.h:288