blob: 8e8fac80d5938740f39759fe863113579a6dbc5c [file] [log] [blame]
// Copyright (C) 2020-2023 Free Software Foundation, Inc.
// This file is part of GCC.
// GCC is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 3, or (at your option) any later
// version.
// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
// You should have received a copy of the GNU General Public License
// along with GCC; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
#ifndef RUST_COMPILE_CONTEXT
#define RUST_COMPILE_CONTEXT
#include "rust-system.h"
#include "rust-hir-map.h"
#include "rust-name-resolver.h"
#include "rust-hir-type-check.h"
#include "rust-backend.h"
#include "rust-hir-full.h"
#include "rust-mangle.h"
#include "rust-tree.h"
namespace Rust {
namespace Compile {
struct fncontext
{
tree fndecl;
::Bvariable *ret_addr;
};
class Context
{
public:
Context (::Backend *backend);
void setup_builtins ();
bool lookup_compiled_types (tree t, tree *type)
{
hashval_t h = type_hasher (t);
auto it = compiled_type_map.find (h);
if (it == compiled_type_map.end ())
return false;
*type = it->second;
return true;
}
tree insert_compiled_type (tree type)
{
hashval_t h = type_hasher (type);
auto it = compiled_type_map.find (h);
if (it != compiled_type_map.end ())
return it->second;
compiled_type_map.insert ({h, type});
push_type (type);
return type;
}
tree insert_main_variant (tree type)
{
hashval_t h = type_hasher (type);
auto it = main_variants.find (h);
if (it != main_variants.end ())
return it->second;
main_variants.insert ({h, type});
return type;
}
::Backend *get_backend () { return backend; }
Resolver::Resolver *get_resolver () { return resolver; }
Resolver::TypeCheckContext *get_tyctx () { return tyctx; }
Analysis::Mappings *get_mappings () { return mappings; }
void push_block (tree scope)
{
scope_stack.push_back (scope);
statements.push_back ({});
}
tree pop_block ()
{
auto block = scope_stack.back ();
scope_stack.pop_back ();
auto stmts = statements.back ();
statements.pop_back ();
backend->block_add_statements (block, stmts);
return block;
}
tree peek_enclosing_scope ()
{
if (scope_stack.size () == 0)
return nullptr;
return scope_stack.back ();
}
void add_statement_to_enclosing_scope (tree stmt)
{
statements.at (statements.size () - 2).push_back (stmt);
}
void add_statement (tree stmt) { statements.back ().push_back (stmt); }
void insert_var_decl (HirId id, ::Bvariable *decl)
{
compiled_var_decls[id] = decl;
}
bool lookup_var_decl (HirId id, ::Bvariable **decl)
{
auto it = compiled_var_decls.find (id);
if (it == compiled_var_decls.end ())
return false;
*decl = it->second;
return true;
}
void insert_function_decl (const TyTy::FnType *ref, tree fn)
{
auto id = ref->get_ty_ref ();
auto dId = ref->get_id ();
rust_assert (compiled_fn_map.find (id) == compiled_fn_map.end ());
compiled_fn_map[id] = fn;
auto it = mono_fns.find (dId);
if (it == mono_fns.end ())
mono_fns[dId] = {};
mono_fns[dId].push_back ({ref, fn});
}
void insert_closure_decl (const TyTy::ClosureType *ref, tree fn)
{
auto dId = ref->get_def_id ();
auto it = mono_closure_fns.find (dId);
if (it == mono_closure_fns.end ())
mono_closure_fns[dId] = {};
mono_closure_fns[dId].push_back ({ref, fn});
}
tree lookup_closure_decl (const TyTy::ClosureType *ref)
{
auto dId = ref->get_def_id ();
auto it = mono_closure_fns.find (dId);
if (it == mono_closure_fns.end ())
return error_mark_node;
for (auto &i : it->second)
{
const TyTy::ClosureType *t = i.first;
tree fn = i.second;
if (ref->is_equal (*t))
return fn;
}
return error_mark_node;
}
bool lookup_function_decl (HirId id, tree *fn, DefId dId = UNKNOWN_DEFID,
const TyTy::BaseType *ref = nullptr,
const std::string &asm_name = std::string ())
{
// for for any monomorphized fns
if (ref != nullptr)
{
rust_assert (dId != UNKNOWN_DEFID);
auto it = mono_fns.find (dId);
if (it == mono_fns.end ())
return false;
for (auto &e : mono_fns[dId])
{
const TyTy::BaseType *r = e.first;
tree f = e.second;
if (ref->is_equal (*r))
{
*fn = f;
return true;
}
if (DECL_ASSEMBLER_NAME_SET_P (f) && !asm_name.empty ())
{
tree raw = DECL_ASSEMBLER_NAME_RAW (f);
const char *rptr = IDENTIFIER_POINTER (raw);
bool lengths_match_p
= IDENTIFIER_LENGTH (raw) == asm_name.size ();
if (lengths_match_p
&& strncmp (rptr, asm_name.c_str (),
IDENTIFIER_LENGTH (raw))
== 0)
{
*fn = f;
return true;
}
}
}
return false;
}
auto it = compiled_fn_map.find (id);
if (it == compiled_fn_map.end ())
return false;
*fn = it->second;
return true;
}
void insert_const_decl (HirId id, tree expr) { compiled_consts[id] = expr; }
bool lookup_const_decl (HirId id, tree *expr)
{
auto it = compiled_consts.find (id);
if (it == compiled_consts.end ())
return false;
*expr = it->second;
return true;
}
void insert_label_decl (HirId id, tree label) { compiled_labels[id] = label; }
bool lookup_label_decl (HirId id, tree *label)
{
auto it = compiled_labels.find (id);
if (it == compiled_labels.end ())
return false;
*label = it->second;
return true;
}
void insert_pattern_binding (HirId id, tree binding)
{
implicit_pattern_bindings[id] = binding;
}
bool lookup_pattern_binding (HirId id, tree *binding)
{
auto it = implicit_pattern_bindings.find (id);
if (it == implicit_pattern_bindings.end ())
return false;
*binding = it->second;
return true;
}
void push_fn (tree fn, ::Bvariable *ret_addr)
{
fn_stack.push_back (fncontext{fn, ret_addr});
}
void pop_fn () { fn_stack.pop_back (); }
bool in_fn () { return fn_stack.size () != 0; }
// Note: it is undefined behavior to call peek_fn () if fn_stack is empty.
fncontext peek_fn ()
{
rust_assert (!fn_stack.empty ());
return fn_stack.back ();
}
void push_type (tree t) { type_decls.push_back (t); }
void push_var (::Bvariable *v) { var_decls.push_back (v); }
void push_const (tree c) { const_decls.push_back (c); }
void push_function (tree f) { func_decls.push_back (f); }
void write_to_backend ()
{
backend->write_global_definitions (type_decls, const_decls, func_decls,
var_decls);
}
bool function_completed (tree fn)
{
for (auto it = func_decls.begin (); it != func_decls.end (); it++)
{
tree i = (*it);
if (i == fn)
{
return true;
}
}
return false;
}
void push_loop_context (Bvariable *var) { loop_value_stack.push_back (var); }
Bvariable *peek_loop_context () { return loop_value_stack.back (); }
Bvariable *pop_loop_context ()
{
auto back = loop_value_stack.back ();
loop_value_stack.pop_back ();
return back;
}
void push_loop_begin_label (tree label)
{
loop_begin_labels.push_back (label);
}
tree peek_loop_begin_label () { return loop_begin_labels.back (); }
tree pop_loop_begin_label ()
{
tree pop = loop_begin_labels.back ();
loop_begin_labels.pop_back ();
return pop;
}
void push_const_context (void) { const_context++; }
void pop_const_context (void)
{
if (const_context > 0)
const_context--;
}
bool const_context_p (void) { return (const_context > 0); }
std::string mangle_item (const TyTy::BaseType *ty,
const Resolver::CanonicalPath &path) const
{
return mangler.mangle_item (ty, path);
}
void push_closure_context (HirId id);
void pop_closure_context ();
void insert_closure_binding (HirId id, tree expr);
bool lookup_closure_binding (HirId id, tree *expr);
std::vector<tree> &get_type_decls () { return type_decls; }
std::vector<::Bvariable *> &get_var_decls () { return var_decls; }
std::vector<tree> &get_const_decls () { return const_decls; }
std::vector<tree> &get_func_decls () { return func_decls; }
static hashval_t type_hasher (tree type);
private:
::Backend *backend;
Resolver::Resolver *resolver;
Resolver::TypeCheckContext *tyctx;
Analysis::Mappings *mappings;
Mangler mangler;
// state
std::vector<fncontext> fn_stack;
std::map<HirId, ::Bvariable *> compiled_var_decls;
std::map<hashval_t, tree> compiled_type_map;
std::map<HirId, tree> compiled_fn_map;
std::map<HirId, tree> compiled_consts;
std::map<HirId, tree> compiled_labels;
std::vector<::std::vector<tree>> statements;
std::vector<tree> scope_stack;
std::vector<::Bvariable *> loop_value_stack;
std::vector<tree> loop_begin_labels;
std::map<DefId, std::vector<std::pair<const TyTy::BaseType *, tree>>>
mono_fns;
std::map<DefId, std::vector<std::pair<const TyTy::ClosureType *, tree>>>
mono_closure_fns;
std::map<HirId, tree> implicit_pattern_bindings;
std::map<hashval_t, tree> main_variants;
// closure bindings
std::vector<HirId> closure_scope_bindings;
std::map<HirId, std::map<HirId, tree>> closure_bindings;
// To GCC middle-end
std::vector<tree> type_decls;
std::vector<::Bvariable *> var_decls;
std::vector<tree> const_decls;
std::vector<tree> func_decls;
// Nonzero iff we are currently compiling something inside a constant context.
unsigned int const_context = 0;
};
} // namespace Compile
} // namespace Rust
#endif // RUST_COMPILE_CONTEXT