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 explicit DesignatorFolder(FoldingContext &c, bool getLastComponent = false)
63 : context_{c}, getLastComponent_{getLastComponent} {}
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 common::visit(
71 [&](const auto &x) { return FoldDesignator(x, elementNumber_++); },
72 expr.u);
73 }
74
75private:
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 common::visit(
102 [&](const auto &x) { return FoldDesignator(x, which); }, expr.u);
103 }
104
105 template <typename A>
106 std::optional<OffsetSymbol> FoldDesignator(const A &, 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 common::visit(
114 [&](const auto &x) { return FoldDesignator(x, which); }, designator.u);
115 }
116 template <int KIND>
117 std::optional<OffsetSymbol> FoldDesignator(
119 ConstantSubscript which) {
120 return common::visit(
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 bool getLastComponent_{false};
161 ConstantSubscript elementNumber_{0}; // zero-based
162 bool isEmpty_{false};
163 bool isOutOfRange_{false};
164};
165
166// Reconstructs a Designator<> from a symbol and an offset.
167std::optional<Expr<SomeType>> OffsetToDesignator(
168 FoldingContext &, const Symbol &, ConstantSubscript offset, std::size_t);
169std::optional<Expr<SomeType>> OffsetToDesignator(
170 FoldingContext &, const OffsetSymbol &);
171
172// Represents a compile-time constant Descriptor suitable for use
173// as a pointer initializer. Lower bounds are always 1.
174struct ConstantObjectPointer : public OffsetSymbol {
175 struct Dimension {
176 ConstantSubscript byteStride;
177 ConstantSubscript extent;
178 };
179 using Dimensions = std::vector<Dimension>;
180
181 ConstantObjectPointer(
182 const Symbol &symbol, std::size_t size, Dimensions &&dims)
183 : OffsetSymbol{symbol, size}, dimensions{std::move(dims)} {}
184
185 // Folds a designator to a constant pointer. Crashes on failure.
186 // Use IsInitialDataTarget() to validate the expression beforehand.
188
189 Dimensions dimensions;
190};
191
192} // namespace Fortran::evaluate
193#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:893
Definition call.h:34
Definition idioms.h:60
Definition fold-designator.h:174
Definition variable.h:288