1 // Copyright (C) 2020-2023 Free Software Foundation, Inc.
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_COMPILE_CONTEXT
20 #define RUST_COMPILE_CONTEXT
21
22 #include "rust-system.h"
23 #include "rust-hir-map.h"
24 #include "rust-name-resolver.h"
25 #include "rust-hir-type-check.h"
26 #include "rust-backend.h"
27 #include "rust-hir-full.h"
28 #include "rust-mangle.h"
29 #include "rust-tree.h"
30
31 namespace Rust {
32 namespace Compile {
33
34 struct fncontext
35 {
36 tree fndecl;
37 ::Bvariable *ret_addr;
38 };
39
40 class Context
41 {
42 public:
43 Context (::Backend *backend);
44
45 void setup_builtins ();
46
47 bool lookup_compiled_types (tree t, tree *type)
48 {
49 hashval_t h = type_hasher (t);
50 auto it = compiled_type_map.find (h);
51 if (it == compiled_type_map.end ())
52 return false;
53
54 *type = it->second;
55 return true;
56 }
57
58 tree insert_compiled_type (tree type)
59 {
60 hashval_t h = type_hasher (type);
61 auto it = compiled_type_map.find (h);
62 if (it != compiled_type_map.end ())
63 return it->second;
64
65 compiled_type_map.insert ({h, type});
66 push_type (type);
67 return type;
68 }
69
70 tree insert_main_variant (tree type)
71 {
72 hashval_t h = type_hasher (type);
73 auto it = main_variants.find (h);
74 if (it != main_variants.end ())
75 return it->second;
76
77 main_variants.insert ({h, type});
78 return type;
79 }
80
81 ::Backend *get_backend () { return backend; }
82 Resolver::Resolver *get_resolver () { return resolver; }
83 Resolver::TypeCheckContext *get_tyctx () { return tyctx; }
84 Analysis::Mappings *get_mappings () { return mappings; }
85
86 void push_block (tree scope)
87 {
88 scope_stack.push_back (scope);
89 statements.push_back ({});
90 }
91
92 tree pop_block ()
93 {
94 auto block = scope_stack.back ();
95 scope_stack.pop_back ();
96
97 auto stmts = statements.back ();
98 statements.pop_back ();
99
100 backend->block_add_statements (block, stmts);
101
102 return block;
103 }
104
105 tree peek_enclosing_scope ()
106 {
107 if (scope_stack.size () == 0)
108 return nullptr;
109
110 return scope_stack.back ();
111 }
112
113 void add_statement_to_enclosing_scope (tree stmt)
114 {
115 statements.at (statements.size () - 2).push_back (stmt);
116 }
117
118 void add_statement (tree stmt) { statements.back ().push_back (stmt); }
119
120 void insert_var_decl (HirId id, ::Bvariable *decl)
121 {
122 compiled_var_decls[id] = decl;
123 }
124
125 bool lookup_var_decl (HirId id, ::Bvariable **decl)
126 {
127 auto it = compiled_var_decls.find (id);
128 if (it == compiled_var_decls.end ())
129 return false;
130
131 *decl = it->second;
132 return true;
133 }
134
135 void insert_function_decl (const TyTy::FnType *ref, tree fn)
136 {
137 auto id = ref->get_ty_ref ();
138 auto dId = ref->get_id ();
139
140 rust_assert (compiled_fn_map.find (id) == compiled_fn_map.end ());
141 compiled_fn_map[id] = fn;
142
143 auto it = mono_fns.find (dId);
144 if (it == mono_fns.end ())
145 mono_fns[dId] = {};
146
147 mono_fns[dId].push_back ({ref, fn});
148 }
149
150 void insert_closure_decl (const TyTy::ClosureType *ref, tree fn)
151 {
152 auto dId = ref->get_def_id ();
153 auto it = mono_closure_fns.find (dId);
154 if (it == mono_closure_fns.end ())
155 mono_closure_fns[dId] = {};
156
157 mono_closure_fns[dId].push_back ({ref, fn});
158 }
159
160 tree lookup_closure_decl (const TyTy::ClosureType *ref)
161 {
162 auto dId = ref->get_def_id ();
163 auto it = mono_closure_fns.find (dId);
164 if (it == mono_closure_fns.end ())
165 return error_mark_node;
166
167 for (auto &i : it->second)
168 {
169 const TyTy::ClosureType *t = i.first;
170 tree fn = i.second;
171
172 if (ref->is_equal (*t))
173 return fn;
174 }
175
176 return error_mark_node;
177 }
178
179 bool lookup_function_decl (HirId id, tree *fn, DefId dId = UNKNOWN_DEFID,
180 const TyTy::BaseType *ref = nullptr,
181 const std::string &asm_name = std::string ())
182 {
183 // for for any monomorphized fns
184 if (ref != nullptr)
185 {
186 rust_assert (dId != UNKNOWN_DEFID);
187
188 auto it = mono_fns.find (dId);
189 if (it == mono_fns.end ())
190 return false;
191
192 for (auto &e : mono_fns[dId])
193 {
194 const TyTy::BaseType *r = e.first;
195 tree f = e.second;
196
197 if (ref->is_equal (*r))
198 {
199 *fn = f;
200 return true;
201 }
202
203 if (DECL_ASSEMBLER_NAME_SET_P (f) && !asm_name.empty ())
204 {
205 tree raw = DECL_ASSEMBLER_NAME_RAW (f);
206 const char *rptr = IDENTIFIER_POINTER (raw);
207
208 bool lengths_match_p
209 = IDENTIFIER_LENGTH (raw) == asm_name.size ();
210 if (lengths_match_p
211 && strncmp (rptr, asm_name.c_str (),
212 IDENTIFIER_LENGTH (raw))
213 == 0)
214 {
215 *fn = f;
216 return true;
217 }
218 }
219 }
220 return false;
221 }
222
223 auto it = compiled_fn_map.find (id);
224 if (it == compiled_fn_map.end ())
225 return false;
226
227 *fn = it->second;
228 return true;
229 }
230
231 void insert_const_decl (HirId id, tree expr) { compiled_consts[id] = expr; }
232
233 bool lookup_const_decl (HirId id, tree *expr)
234 {
235 auto it = compiled_consts.find (id);
236 if (it == compiled_consts.end ())
237 return false;
238
239 *expr = it->second;
240 return true;
241 }
242
243 void insert_label_decl (HirId id, tree label) { compiled_labels[id] = label; }
244
245 bool lookup_label_decl (HirId id, tree *label)
246 {
247 auto it = compiled_labels.find (id);
248 if (it == compiled_labels.end ())
249 return false;
250
251 *label = it->second;
252 return true;
253 }
254
255 void insert_pattern_binding (HirId id, tree binding)
256 {
257 implicit_pattern_bindings[id] = binding;
258 }
259
260 bool lookup_pattern_binding (HirId id, tree *binding)
261 {
262 auto it = implicit_pattern_bindings.find (id);
263 if (it == implicit_pattern_bindings.end ())
264 return false;
265
266 *binding = it->second;
267 return true;
268 }
269
270 void push_fn (tree fn, ::Bvariable *ret_addr)
271 {
272 fn_stack.push_back (fncontext{fn, ret_addr});
273 }
274 void pop_fn () { fn_stack.pop_back (); }
275
276 bool in_fn () { return fn_stack.size () != 0; }
277
278 // Note: it is undefined behavior to call peek_fn () if fn_stack is empty.
279 fncontext peek_fn ()
280 {
281 rust_assert (!fn_stack.empty ());
282 return fn_stack.back ();
283 }
284
285 void push_type (tree t) { type_decls.push_back (t); }
286 void push_var (::Bvariable *v) { var_decls.push_back (v); }
287 void push_const (tree c) { const_decls.push_back (c); }
288 void push_function (tree f) { func_decls.push_back (f); }
289
290 void write_to_backend ()
291 {
292 backend->write_global_definitions (type_decls, const_decls, func_decls,
293 var_decls);
294 }
295
296 bool function_completed (tree fn)
297 {
298 for (auto it = func_decls.begin (); it != func_decls.end (); it++)
299 {
300 tree i = (*it);
301 if (i == fn)
302 {
303 return true;
304 }
305 }
306 return false;
307 }
308
309 void push_loop_context (Bvariable *var) { loop_value_stack.push_back (var); }
310
311 Bvariable *peek_loop_context () { return loop_value_stack.back (); }
312
313 Bvariable *pop_loop_context ()
314 {
315 auto back = loop_value_stack.back ();
316 loop_value_stack.pop_back ();
317 return back;
318 }
319
320 void push_loop_begin_label (tree label)
321 {
322 loop_begin_labels.push_back (label);
323 }
324
325 tree peek_loop_begin_label () { return loop_begin_labels.back (); }
326
327 tree pop_loop_begin_label ()
328 {
329 tree pop = loop_begin_labels.back ();
330 loop_begin_labels.pop_back ();
331 return pop;
332 }
333
334 void push_const_context (void) { const_context++; }
335 void pop_const_context (void)
336 {
337 if (const_context > 0)
338 const_context--;
339 }
340 bool const_context_p (void) { return (const_context > 0); }
341
342 std::string mangle_item (const TyTy::BaseType *ty,
343 const Resolver::CanonicalPath &path) const
344 {
345 return mangler.mangle_item (ty, path);
346 }
347
348 void push_closure_context (HirId id);
349 void pop_closure_context ();
350 void insert_closure_binding (HirId id, tree expr);
351 bool lookup_closure_binding (HirId id, tree *expr);
352
353 std::vector<tree> &get_type_decls () { return type_decls; }
354 std::vector<::Bvariable *> &get_var_decls () { return var_decls; }
355 std::vector<tree> &get_const_decls () { return const_decls; }
356 std::vector<tree> &get_func_decls () { return func_decls; }
357
358 static hashval_t type_hasher (tree type);
359
360 private:
361 ::Backend *backend;
362 Resolver::Resolver *resolver;
363 Resolver::TypeCheckContext *tyctx;
364 Analysis::Mappings *mappings;
365 Mangler mangler;
366
367 // state
368 std::vector<fncontext> fn_stack;
369 std::map<HirId, ::Bvariable *> compiled_var_decls;
370 std::map<hashval_t, tree> compiled_type_map;
371 std::map<HirId, tree> compiled_fn_map;
372 std::map<HirId, tree> compiled_consts;
373 std::map<HirId, tree> compiled_labels;
374 std::vector<::std::vector<tree>> statements;
375 std::vector<tree> scope_stack;
376 std::vector<::Bvariable *> loop_value_stack;
377 std::vector<tree> loop_begin_labels;
378 std::map<DefId, std::vector<std::pair<const TyTy::BaseType *, tree>>>
379 mono_fns;
380 std::map<DefId, std::vector<std::pair<const TyTy::ClosureType *, tree>>>
381 mono_closure_fns;
382 std::map<HirId, tree> implicit_pattern_bindings;
383 std::map<hashval_t, tree> main_variants;
384
385 // closure bindings
386 std::vector<HirId> closure_scope_bindings;
387 std::map<HirId, std::map<HirId, tree>> closure_bindings;
388
389 // To GCC middle-end
390 std::vector<tree> type_decls;
391 std::vector<::Bvariable *> var_decls;
392 std::vector<tree> const_decls;
393 std::vector<tree> func_decls;
394
395 // Nonzero iff we are currently compiling something inside a constant context.
396 unsigned int const_context = 0;
397 };
398
399 } // namespace Compile
400 } // namespace Rust
401
402 #endif // RUST_COMPILE_CONTEXT