]>
Commit | Line | Data |
---|---|---|
767698ff | 1 | // Copyright (C) 2020-2024 Free Software Foundation, Inc. |
dbd29204 JD |
2 | |
3 | // This file is part of GCC. | |
4 | ||
5 | // GCC is free software; you can redistribute it and/or modify it under | |
6 | // the terms of the GNU General Public License as published by the Free | |
7 | // Software Foundation; either version 3, or (at your option) any later | |
8 | // version. | |
9 | ||
10 | // GCC is distributed in the hope that it will be useful, but WITHOUT ANY | |
11 | // WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
12 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
13 | // for more details. | |
14 | ||
15 | // You should have received a copy of the GNU General Public License | |
16 | // along with GCC; see the file COPYING3. If not see | |
17 | // <http://www.gnu.org/licenses/>. | |
18 | ||
19 | #ifndef RUST_BIR_PLACE_H | |
20 | #define RUST_BIR_PLACE_H | |
21 | ||
22 | #include <limits> | |
23 | #include "rust-mapping-common.h" | |
24 | #include "rust-system.h" | |
25 | #include "rust-tyty.h" | |
26 | ||
27 | namespace Rust { | |
28 | namespace BIR { | |
29 | ||
30 | /** A unique identifier for a place in the BIR. */ | |
31 | using PlaceId = uint32_t; | |
32 | ||
33 | static constexpr PlaceId INVALID_PLACE = 0; | |
34 | static constexpr PlaceId RETURN_VALUE_PLACE = 1; | |
35 | static constexpr PlaceId FIRST_VARIABLE_PLACE = RETURN_VALUE_PLACE; | |
36 | ||
37 | /** | |
38 | * A unique identifier for a lifetime in the BIR. Only to be used INTERNALLY. | |
39 | */ | |
40 | using LifetimeID = uint32_t; | |
41 | ||
42 | constexpr LifetimeID INVALID_LIFETIME_ID = 0; | |
43 | constexpr LifetimeID STATIC_LIFETIME_ID = 1; | |
44 | constexpr LifetimeID FIRST_NORMAL_LIFETIME_ID = 2; | |
45 | ||
46 | /** Representation of lifetimes in BIR. */ | |
47 | struct Lifetime | |
48 | { | |
49 | LifetimeID id = INVALID_LIFETIME_ID; | |
50 | ||
51 | constexpr Lifetime (LifetimeID id) : id (id) {} | |
52 | constexpr Lifetime (const Lifetime &) = default; | |
53 | WARN_UNUSED_RESULT bool has_lifetime () const | |
54 | { | |
55 | return id != INVALID_LIFETIME_ID; | |
56 | } | |
57 | LifetimeID operator() () const { return id; } | |
58 | }; | |
59 | constexpr Lifetime NO_LIFETIME = {INVALID_LIFETIME_ID}; | |
60 | constexpr Lifetime STATIC_LIFETIME = {STATIC_LIFETIME_ID}; | |
61 | ||
62 | /** | |
63 | * Representation of lvalues and constants in BIR. | |
64 | * See bir bir design notes (in this directory) and the Polonius book. | |
65 | */ | |
66 | struct Place | |
67 | { | |
68 | enum Kind | |
69 | { | |
70 | INVALID, | |
71 | VARIABLE, | |
72 | TEMPORARY, | |
73 | CONSTANT, | |
74 | FIELD, | |
75 | INDEX, | |
76 | DEREF, | |
77 | }; | |
78 | ||
79 | Kind kind; | |
80 | uint32_t variable_or_field_index; // NodeId for VARIABLE | |
81 | /** Data for traversing paths in the PlaceDB. */ | |
82 | struct Path | |
83 | { | |
84 | PlaceId parent = INVALID_PLACE; | |
85 | PlaceId first_child = INVALID_PLACE; | |
86 | PlaceId next_sibling = INVALID_PLACE; | |
87 | ||
88 | Path (PlaceId parent, PlaceId first_child, PlaceId next_sibling) | |
89 | : parent (parent), first_child (first_child), next_sibling (next_sibling) | |
90 | {} | |
91 | Path () = default; | |
92 | } path; | |
93 | /** Copy trait */ | |
94 | bool is_copy; | |
95 | /** This place can be moved from safety. */ | |
96 | bool is_rvalue; | |
97 | Lifetime lifetime; | |
98 | TyTy::BaseType *tyty; | |
99 | ||
100 | Place (Kind kind, uint32_t variable_or_field_index, const Path &path, | |
101 | bool is_copy, bool is_rvalue, const Lifetime &lifetime, | |
102 | TyTy::BaseType *tyty) | |
103 | : kind (kind), variable_or_field_index (variable_or_field_index), | |
104 | path (path), is_copy (is_copy), is_rvalue (is_rvalue), | |
105 | lifetime (lifetime), tyty (tyty) | |
106 | {} | |
107 | }; | |
108 | ||
109 | /** Allocated places and keeps track of paths. */ | |
110 | class PlaceDB | |
111 | { | |
112 | // Possible optimizations: separate variables to speedup lookup. | |
113 | std::vector<Place> places; | |
114 | std::unordered_map<TyTy::BaseType *, PlaceId> constants_lookup; | |
115 | ||
116 | public: | |
117 | PlaceDB () | |
118 | { | |
119 | // Reserved index for invalid place. | |
120 | places.push_back ( | |
121 | {Place::INVALID, 0, {}, false, false, NO_LIFETIME, nullptr}); | |
122 | } | |
123 | ||
124 | Place &operator[] (PlaceId id) { return places.at (id); } | |
125 | const Place &operator[] (PlaceId id) const { return places.at (id); } | |
126 | ||
127 | size_t size () const { return places.size (); } | |
128 | ||
129 | PlaceId add_place (Place place, PlaceId last_sibling = 0) | |
130 | { | |
131 | places.push_back (place); | |
132 | PlaceId new_place = places.size () - 1; | |
133 | if (last_sibling == 0) | |
134 | { | |
135 | places[place.path.parent].path.first_child = new_place; | |
136 | } | |
137 | else | |
138 | { | |
139 | places[last_sibling].path.next_sibling = new_place; | |
140 | } | |
141 | return new_place; | |
142 | } | |
143 | ||
144 | PlaceId add_variable (NodeId id, TyTy::BaseType *tyty) | |
145 | { | |
146 | return add_place ( | |
147 | {Place::VARIABLE, id, {}, is_type_copy (tyty), false, NO_LIFETIME, tyty}, | |
148 | 0); | |
149 | } | |
150 | ||
35d5f82e JD |
151 | WARN_UNUSED_RESULT PlaceId lookup_or_add_path (Place::Kind kind, |
152 | TyTy::BaseType *tyty, | |
153 | PlaceId parent, size_t id = 0) | |
dbd29204 JD |
154 | { |
155 | PlaceId current = 0; | |
156 | if (parent < places.size ()) | |
157 | { | |
158 | current = places[parent].path.first_child; | |
159 | while (current != 0) | |
160 | { | |
161 | if (places[current].kind == kind | |
162 | && places[current].variable_or_field_index == id) | |
163 | { | |
164 | rust_assert (places[current].tyty->is_equal (*tyty)); | |
165 | return current; | |
166 | } | |
167 | current = places[current].path.next_sibling; | |
168 | } | |
169 | } | |
170 | return add_place ( | |
171 | {kind, id, {parent, 0, 0}, is_type_copy (tyty), false, NO_LIFETIME, tyty}, | |
172 | current); | |
173 | } | |
174 | ||
32dcd3ec JD |
175 | PlaceId add_temporary (TyTy::BaseType *tyty) |
176 | { | |
177 | return add_place ( | |
178 | {Place::TEMPORARY, 0, {}, is_type_copy (tyty), false, NO_LIFETIME, tyty}, | |
179 | 0); | |
180 | } | |
181 | ||
dbd29204 JD |
182 | PlaceId get_constant (TyTy::BaseType *tyty) |
183 | { | |
184 | auto lookup = constants_lookup.find (tyty); | |
185 | if (lookup != constants_lookup.end ()) | |
186 | return lookup->second; | |
187 | Lifetime lifetime | |
188 | = tyty->get_kind () == TyTy::REF ? STATIC_LIFETIME : NO_LIFETIME; | |
189 | Place place | |
190 | = {Place::CONSTANT, 0, {}, is_type_copy (tyty), false, lifetime, tyty}; | |
191 | places.push_back (place); | |
192 | return places.size () - 1; | |
193 | } | |
194 | ||
32dcd3ec JD |
195 | PlaceId lookup_variable (NodeId id) |
196 | { | |
197 | PlaceId current = FIRST_VARIABLE_PLACE; | |
198 | ||
199 | while (current != places.size ()) | |
200 | { | |
201 | if (places[current].kind == Place::VARIABLE | |
202 | && places[current].variable_or_field_index == id) | |
203 | return current; | |
204 | current++; | |
205 | } | |
206 | return INVALID_PLACE; | |
207 | }; | |
208 | ||
209 | PlaceId lookup_or_add_variable (NodeId id, TyTy::BaseType *tyty) | |
210 | { | |
211 | auto lookup = lookup_variable (id); | |
212 | if (lookup != INVALID_PLACE) | |
213 | return lookup; | |
c54326a8 | 214 | add_place ( |
32dcd3ec JD |
215 | {Place::VARIABLE, id, {}, is_type_copy (tyty), false, NO_LIFETIME, tyty}); |
216 | return places.size () - 1; | |
217 | }; | |
218 | ||
219 | PlaceId into_rvalue (PlaceId place) | |
220 | { | |
221 | if (places[place].is_rvalue || places[place].kind == Place::CONSTANT | |
222 | || places[place].tyty->get_kind () == TyTy::REF) | |
223 | return place; | |
224 | return add_place ({Place::TEMPORARY, | |
225 | 0, | |
226 | {}, | |
227 | places[place].is_copy, | |
228 | true, | |
229 | NO_LIFETIME, | |
230 | places[place].tyty}); | |
231 | } | |
232 | ||
dbd29204 JD |
233 | private: |
234 | static bool is_type_copy (TyTy::BaseType *ty) | |
235 | { | |
236 | switch (ty->get_kind ()) | |
237 | { | |
238 | case TyTy::REF: | |
239 | case TyTy::POINTER: | |
240 | case TyTy::SLICE: | |
241 | case TyTy::BOOL: | |
242 | case TyTy::CHAR: | |
243 | case TyTy::INT: | |
244 | case TyTy::UINT: | |
245 | case TyTy::FLOAT: | |
246 | case TyTy::USIZE: | |
247 | case TyTy::ISIZE: | |
248 | case TyTy::FNPTR: | |
249 | case TyTy::FNDEF: | |
250 | case TyTy::NEVER: | |
251 | return true; | |
252 | case TyTy::TUPLE: { | |
253 | auto &fields = ty->as<TyTy::TupleType> ()->get_fields (); | |
254 | return std::all_of (fields.begin (), fields.end (), | |
255 | [] (const TyTy::TyVar &field) { | |
256 | return is_type_copy (field.get_tyty ()); | |
257 | }); | |
258 | } | |
259 | case TyTy::ARRAY: { | |
260 | return is_type_copy (ty->as<TyTy::ArrayType> ()->get_element_type ()); | |
261 | } | |
262 | case TyTy::INFER: | |
263 | case TyTy::PARAM: | |
264 | case TyTy::ERROR: | |
265 | case TyTy::STR: | |
266 | case TyTy::PLACEHOLDER: | |
267 | rust_unreachable (); | |
268 | case TyTy::ADT: // TODO: check trait | |
269 | case TyTy::PROJECTION: // TODO: DUNNO | |
270 | case TyTy::CLOSURE: // TODO: DUNNO | |
271 | case TyTy::DYNAMIC: // TODO: dunno | |
272 | return false; | |
273 | } | |
274 | rust_unreachable (); | |
275 | } | |
276 | }; | |
277 | ||
278 | } // namespace BIR | |
279 | } // namespace Rust | |
280 | ||
281 | #endif // RUST_BIR_PLACE_H |