(root)/
gcc-13.2.0/
gcc/
rust/
backend/
rust-compile-context.h
       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