LCOV - code coverage report
Current view: top level - gcc/jit - jit-playback.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 87.9 % 1710 1503
Test Date: 2026-02-28 14:20:25 Functions: 95.5 % 132 126
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* Internals of libgccjit: classes for playing back recorded API calls.
       2              :    Copyright (C) 2013-2026 Free Software Foundation, Inc.
       3              :    Contributed by David Malcolm <dmalcolm@redhat.com>.
       4              : 
       5              : This file is part of GCC.
       6              : 
       7              : GCC is free software; you can redistribute it and/or modify it
       8              : under the terms of the GNU General Public License as published by
       9              : the Free Software Foundation; either version 3, or (at your option)
      10              : any later version.
      11              : 
      12              : GCC is distributed in the hope that it will be useful, but
      13              : WITHOUT ANY WARRANTY; without even the implied warranty of
      14              : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      15              : General Public License for more details.
      16              : 
      17              : You should have received a copy of the GNU General Public License
      18              : along with GCC; see the file COPYING3.  If not see
      19              : <http://www.gnu.org/licenses/>.  */
      20              : 
      21              : #include "config.h"
      22              : #define INCLUDE_MUTEX
      23              : #define INCLUDE_DLFCN_H
      24              : #include "libgccjit.h"
      25              : #include "system.h"
      26              : #include "coretypes.h"
      27              : #include "target.h"
      28              : #include "tree.h"
      29              : #include "stringpool.h"
      30              : #include "cgraph.h"
      31              : #include "dumpfile.h"
      32              : #include "toplev.h"
      33              : #include "tree-cfg.h"
      34              : #include "convert.h"
      35              : #include "gimple-expr.h"
      36              : #include "stor-layout.h"
      37              : #include "print-tree.h"
      38              : #include "gimplify.h"
      39              : #include "gcc-driver-name.h"
      40              : #include "attribs.h"
      41              : #include "context.h"
      42              : #include "fold-const.h"
      43              : #include "opt-suggestions.h"
      44              : #include "gcc.h"
      45              : #include "diagnostic.h"
      46              : #include "stmt.h"
      47              : #include "realmpfr.h"
      48              : 
      49              : #include "jit-playback.h"
      50              : #include "jit-result.h"
      51              : #include "jit-builtins.h"
      52              : #include "jit-tempdir.h"
      53              : #include "jit-target.h"
      54              : 
      55              : #ifdef _WIN32
      56              : #include "jit-w32.h"
      57              : #endif
      58              : 
      59              : /* Compare with gcc/c-family/c-common.h: DECL_C_BIT_FIELD,
      60              :    SET_DECL_C_BIT_FIELD.
      61              :    These are redefined here to avoid depending from the C frontend.  */
      62              : #define DECL_JIT_BIT_FIELD(NODE) \
      63              :   (DECL_LANG_FLAG_4 (FIELD_DECL_CHECK (NODE)) == 1)
      64              : #define SET_DECL_JIT_BIT_FIELD(NODE) \
      65              :   (DECL_LANG_FLAG_4 (FIELD_DECL_CHECK (NODE)) = 1)
      66              : 
      67              : /* gcc::jit::playback::context::build_cast uses the convert.h API,
      68              :    which in turn requires the frontend to provide a "convert"
      69              :    function, apparently as a fallback for casts that can be simplified
      70              :    (truncation, extension). */
      71              : extern tree convert (tree type, tree expr);
      72              : 
      73              : tree
      74           15 : convert (tree dst_type, tree expr)
      75              : {
      76           15 :   tree t_ret = NULL;
      77           15 :   t_ret = targetm.convert_to_type (dst_type, expr);
      78           15 :   if (t_ret)
      79              :       return t_ret;
      80           15 :   switch (TREE_CODE (dst_type))
      81              :     {
      82           15 :     case INTEGER_TYPE:
      83           15 :     case ENUMERAL_TYPE:
      84           15 :       return fold (convert_to_integer (dst_type, expr));
      85              : 
      86            0 :     default:
      87            0 :       gcc_assert (gcc::jit::active_playback_ctxt);
      88            0 :       gcc::jit::active_playback_ctxt->add_error (NULL, "unhandled conversion");
      89            0 :       fprintf (stderr, "input expression:\n");
      90            0 :       debug_tree (expr);
      91            0 :       fprintf (stderr, "requested type:\n");
      92            0 :       debug_tree (dst_type);
      93            0 :       return error_mark_node;
      94              :     }
      95              : }
      96              : 
      97              : namespace gcc {
      98              : namespace jit {
      99              : 
     100              : /**********************************************************************
     101              :  Playback.
     102              :  **********************************************************************/
     103              : 
     104              : /* Fold a readonly non-volatile variable with an initial constant value,
     105              :    to that value.
     106              : 
     107              :    Otherwise return the argument unchanged.
     108              : 
     109              :    This fold is needed for setting a variable's DECL_INITIAL to the value
     110              :    of a const variable.  The c-frontend does this in its own special
     111              :    fold (), so we lift this part out and do it explicitly where there is a
     112              :    potential for variables to be used as rvalues.  */
     113              : static tree
     114        13011 : fold_const_var (tree node)
     115              : {
     116              :   /* See c_fully_fold_internal in c-fold.cc and decl_constant_value_1
     117              :      in c-typeck.cc.  */
     118        13011 :   if (VAR_P (node)
     119         4428 :       && TREE_READONLY (node)
     120           50 :       && !TREE_THIS_VOLATILE (node)
     121           50 :       && DECL_INITIAL (node) != NULL_TREE
     122              :       /* "This is invalid if initial value is not constant.
     123              :           If it has either a function call, a memory reference,
     124              :           or a variable, then re-evaluating it could give different
     125              :           results."  */
     126        13056 :       && TREE_CONSTANT (DECL_INITIAL (node)))
     127              :     {
     128           45 :       tree ret = DECL_INITIAL (node);
     129              :       /* "Avoid unwanted tree sharing between the initializer and current
     130              :           function's body where the tree can be modified e.g. by the
     131              :           gimplifier."  */
     132           45 :       if (TREE_STATIC (node))
     133           45 :         ret = unshare_expr (ret);
     134              : 
     135           45 :       return ret;
     136              :     }
     137              : 
     138              :   return node;
     139              : }
     140              : 
     141              : /* Build a STRING_CST tree for STR, or return NULL if it is NULL.
     142              :    The TREE_TYPE is not initialized.  */
     143              : 
     144              : static tree
     145          350 : build_string (const char *str)
     146              : {
     147          350 :   if (str)
     148          270 :     return ::build_string (strlen (str), str);
     149              :   else
     150              :     return NULL_TREE;
     151              : }
     152              : 
     153              : /* The constructor for gcc::jit::playback::context.  */
     154              : 
     155         1331 : playback::context::context (recording::context *ctxt)
     156              :   : log_user (ctxt->get_logger ()),
     157         1331 :     m_recording_ctxt (ctxt),
     158         1331 :     m_tempdir (NULL),
     159         1331 :     m_const_char_ptr (NULL)
     160              : {
     161         1331 :   JIT_LOG_SCOPE (get_logger ());
     162         1331 :   m_functions.create (0);
     163         1331 :   m_globals.create (0);
     164         1331 :   m_source_files.create (0);
     165         1331 :   m_cached_locations.create (0);
     166         1331 : }
     167              : 
     168              : /* The destructor for gcc::jit::playback::context.  */
     169              : 
     170         1331 : playback::context::~context ()
     171              : {
     172         1331 :   JIT_LOG_SCOPE (get_logger ());
     173              : 
     174              :   /* Normally the playback::context is responsible for cleaning up the
     175              :      tempdir (including "fake.so" within the filesystem).
     176              : 
     177              :      In the normal case, clean it up now.
     178              : 
     179              :      However m_tempdir can be NULL if the context has handed over
     180              :      responsibility for the tempdir cleanup to the jit::result object, so
     181              :      that the cleanup can be delayed (see PR jit/64206).  If that's the
     182              :      case this "delete NULL;" is a no-op. */
     183         1331 :   delete m_tempdir;
     184              : 
     185         1331 :   m_functions.release ();
     186         1331 : }
     187              : 
     188              : /* A playback::context can reference GC-managed pointers.  Mark them
     189              :    ("by hand", rather than by gengtype).
     190              : 
     191              :    This is called on the active playback context (if any) by the
     192              :    my_ggc_walker hook in the jit_root_table in dummy-frontend.cc.  */
     193              : 
     194              : void
     195       514851 : playback::context::
     196              : gt_ggc_mx ()
     197              : {
     198       514851 :   int i;
     199       514851 :   function *func;
     200     36823970 :   FOR_EACH_VEC_ELT (m_functions, i, func)
     201              :     {
     202     36309119 :       if (ggc_test_and_set_mark (func))
     203     36309119 :         func->gt_ggc_mx ();
     204              :     }
     205       514851 : }
     206              : 
     207              : /* Given an enum gcc_jit_types value, get a "tree" type.  */
     208              : 
     209              : tree
     210         8289 : playback::context::
     211              : get_tree_node_for_type (enum gcc_jit_types type_)
     212              : {
     213         8289 :   switch (type_)
     214              :     {
     215         1291 :     case GCC_JIT_TYPE_VOID:
     216         1291 :       return void_type_node;
     217              : 
     218           70 :     case GCC_JIT_TYPE_VOID_PTR:
     219           70 :       return ptr_type_node;
     220              : 
     221          662 :     case GCC_JIT_TYPE_BOOL:
     222          662 :       return boolean_type_node;
     223              : 
     224          141 :     case GCC_JIT_TYPE_CHAR:
     225          141 :       return char_type_node;
     226           30 :     case GCC_JIT_TYPE_SIGNED_CHAR:
     227           30 :       return signed_char_type_node;
     228           41 :     case GCC_JIT_TYPE_UNSIGNED_CHAR:
     229           41 :       return unsigned_char_type_node;
     230              : 
     231           40 :     case GCC_JIT_TYPE_SHORT:
     232           40 :       return short_integer_type_node;
     233           25 :     case GCC_JIT_TYPE_UNSIGNED_SHORT:
     234           25 :       return short_unsigned_type_node;
     235              : 
     236          117 :     case GCC_JIT_TYPE_CONST_CHAR_PTR:
     237          117 :       return m_const_char_ptr;
     238              : 
     239         1321 :     case GCC_JIT_TYPE_INT:
     240         1321 :       return integer_type_node;
     241         1291 :     case GCC_JIT_TYPE_UNSIGNED_INT:
     242         1291 :       return unsigned_type_node;
     243              : 
     244           15 :     case GCC_JIT_TYPE_UINT8_T:
     245           15 :       return unsigned_intQI_type_node;
     246           15 :     case GCC_JIT_TYPE_UINT16_T:
     247           15 :       return uint16_type_node;
     248           15 :     case GCC_JIT_TYPE_UINT32_T:
     249           15 :       return uint32_type_node;
     250           15 :     case GCC_JIT_TYPE_UINT64_T:
     251           15 :       return uint64_type_node;
     252           15 :     case GCC_JIT_TYPE_UINT128_T:
     253           15 :       if (targetm.scalar_mode_supported_p (TImode))
     254           15 :         return uint128_type_node;
     255              : 
     256            0 :       add_error (NULL, "gcc_jit_types value unsupported on this target: %i",
     257              :                  type_);
     258            0 :       return NULL;
     259              : 
     260           15 :     case GCC_JIT_TYPE_INT8_T:
     261           15 :       return intQI_type_node;
     262           15 :     case GCC_JIT_TYPE_INT16_T:
     263           15 :       return intHI_type_node;
     264           15 :     case GCC_JIT_TYPE_INT32_T:
     265           15 :       return intSI_type_node;
     266           15 :     case GCC_JIT_TYPE_INT64_T:
     267           15 :       return intDI_type_node;
     268           15 :     case GCC_JIT_TYPE_INT128_T:
     269           15 :       if (targetm.scalar_mode_supported_p (TImode))
     270           15 :         return intTI_type_node;
     271              : 
     272            0 :       add_error (NULL, "gcc_jit_types value unsupported on this target: %i",
     273              :                  type_);
     274            0 :       return NULL;
     275              : 
     276           78 :     case GCC_JIT_TYPE_LONG:
     277           78 :       return long_integer_type_node;
     278         1291 :     case GCC_JIT_TYPE_UNSIGNED_LONG:
     279         1291 :       return long_unsigned_type_node;
     280              : 
     281           28 :     case GCC_JIT_TYPE_LONG_LONG:
     282           28 :       return long_long_integer_type_node;
     283         1291 :     case GCC_JIT_TYPE_UNSIGNED_LONG_LONG:
     284         1291 :       return long_long_unsigned_type_node;
     285              : 
     286          105 :     case GCC_JIT_TYPE_FLOAT:
     287          105 :       return float_type_node;
     288            5 :     case GCC_JIT_TYPE_BFLOAT16:
     289              : #ifndef HAVE_BFmode
     290              :       add_error (NULL, "gcc_jit_types value unsupported on this target: %i",
     291              :                  type_);
     292              : #endif
     293            5 :       return bfloat16_type_node;
     294          132 :     case GCC_JIT_TYPE_DOUBLE:
     295          132 :       return double_type_node;
     296           15 :     case GCC_JIT_TYPE_LONG_DOUBLE:
     297           15 :       return long_double_type_node;
     298           15 :     case GCC_JIT_TYPE_FLOAT16:
     299           15 :       if (float16_type_node == NULL || TYPE_PRECISION (float16_type_node) != 16)
     300              :       {
     301            0 :         add_error (NULL, "gcc_jit_types value unsupported on this target: %i",
     302              :                    type_);
     303            0 :         return NULL;
     304              :       }
     305              :       return float16_type_node;
     306           15 :     case GCC_JIT_TYPE_FLOAT32:
     307           15 :       if (float32_type_node == NULL || TYPE_PRECISION (float32_type_node) != 32)
     308              :       {
     309            0 :         add_error (NULL, "gcc_jit_types value unsupported on this target: %i",
     310              :                    type_);
     311            0 :         return NULL;
     312              :       }
     313              :       return float32_type_node;
     314           15 :     case GCC_JIT_TYPE_FLOAT64:
     315           15 :       if (float64_type_node == NULL || TYPE_PRECISION (float64_type_node) != 64)
     316              :       {
     317            0 :         add_error (NULL, "gcc_jit_types value unsupported on this target: %i",
     318              :                    type_);
     319            0 :         return NULL;
     320              :       }
     321              :       return float64_type_node;
     322           15 :     case GCC_JIT_TYPE_FLOAT128:
     323           15 :       if (float128_type_node == NULL
     324           15 :           || TYPE_PRECISION (float128_type_node) != 128)
     325              :       {
     326            0 :         add_error (NULL, "gcc_jit_types value unsupported on this target: %i",
     327              :                    type_);
     328            0 :         return NULL;
     329              :       }
     330              :       return float128_type_node;
     331              : 
     332           75 :     case GCC_JIT_TYPE_SIZE_T:
     333           75 :       return size_type_node;
     334              : 
     335           15 :     case GCC_JIT_TYPE_FILE_PTR:
     336           15 :       return fileptr_type_node;
     337              : 
     338            0 :     case GCC_JIT_TYPE_COMPLEX_FLOAT:
     339            0 :       return complex_float_type_node;
     340           15 :     case GCC_JIT_TYPE_COMPLEX_DOUBLE:
     341           15 :       return complex_double_type_node;
     342            0 :     case GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE:
     343            0 :       return complex_long_double_type_node;
     344              :     }
     345              : 
     346            0 :   add_error (NULL, "unrecognized (enum gcc_jit_types) value: %i",
     347              :              type_);
     348              : 
     349            0 :   return NULL;
     350              : }
     351              : 
     352              : /* Construct a playback::type instance (wrapping a tree) for the given
     353              :    enum value.  */
     354              : 
     355              : playback::type *
     356         8289 : playback::context::
     357              : get_type (enum gcc_jit_types type_)
     358              : {
     359         8289 :   tree type_node = get_tree_node_for_type (type_);
     360         8289 :   if (type_node == NULL)
     361              :     return NULL;
     362              : 
     363         8289 :   return new type (type_node);
     364              : }
     365              : 
     366              : void
     367            5 : playback::context::
     368              : set_output_ident (const char* ident)
     369              : {
     370            5 :   targetm.asm_out.output_ident (ident);
     371            5 : }
     372              : 
     373              : /* Construct a playback::type instance (wrapping a tree) for the given
     374              :    array type.  */
     375              : 
     376              : playback::type *
     377          330 : playback::context::
     378              : new_array_type (playback::location *loc,
     379              :                 playback::type *element_type,
     380              :                 uint64_t num_elements)
     381              : {
     382          330 :   gcc_assert (element_type);
     383              : 
     384          330 :   tree t = build_array_type_nelts (element_type->as_tree (),
     385          330 :                                    num_elements);
     386          330 :   layout_type (t);
     387              : 
     388          330 :   if (loc)
     389            0 :     set_tree_location (t, loc);
     390              : 
     391          330 :   return new type (t);
     392              : }
     393              : 
     394              : /* Construct a playback::field instance (wrapping a tree).  */
     395              : 
     396              : playback::field *
     397         1718 : playback::context::
     398              : new_field (location *loc,
     399              :            type *type,
     400              :            const char *name)
     401              : {
     402         1718 :   gcc_assert (type);
     403         1718 :   gcc_assert (name);
     404              : 
     405              :   /* compare with c/c-decl.cc:grokfield and grokdeclarator.  */
     406         1718 :   tree decl = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
     407              :                           get_identifier (name), type->as_tree ());
     408              : 
     409         1718 :   if (loc)
     410            0 :     set_tree_location (decl, loc);
     411              : 
     412         1718 :   return new field (decl);
     413              : }
     414              : 
     415              : /* Construct a playback::bitfield instance (wrapping a tree).  */
     416              : 
     417              : playback::field *
     418           95 : playback::context::
     419              : new_bitfield (location *loc,
     420              :               type *type,
     421              :               int width,
     422              :               const char *name)
     423              : {
     424           95 :   gcc_assert (type);
     425           95 :   gcc_assert (name);
     426           95 :   gcc_assert (width);
     427              : 
     428              :   /* compare with c/c-decl.cc:grokfield,  grokdeclarator and
     429              :      check_bitfield_type_and_width.  */
     430              : 
     431           95 :   tree tree_type = type->as_tree ();
     432           95 :   gcc_assert (INTEGRAL_TYPE_P (tree_type));
     433           95 :   tree tree_width = build_int_cst (integer_type_node, width);
     434           95 :   if (compare_tree_int (tree_width, TYPE_PRECISION (tree_type)) > 0)
     435              :     {
     436           10 :       add_error (
     437              :         loc,
     438              :         "width of bit-field %s (width: %i) is wider than its type (width: %i)",
     439            5 :         name, width, TYPE_PRECISION (tree_type));
     440            5 :       return NULL;
     441              :     }
     442              : 
     443           90 :   tree decl = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
     444              :                           get_identifier (name), type->as_tree ());
     445           90 :   DECL_NONADDRESSABLE_P (decl) = true;
     446           90 :   DECL_INITIAL (decl) = tree_width;
     447           90 :   SET_DECL_JIT_BIT_FIELD (decl);
     448              : 
     449           90 :   if (loc)
     450            0 :     set_tree_location (decl, loc);
     451              : 
     452           90 :   return new field (decl);
     453              : }
     454              : 
     455              : /* Construct a playback::compound_type instance (wrapping a tree).  */
     456              : 
     457              : playback::compound_type *
     458          602 : playback::context::
     459              : new_compound_type (location *loc,
     460              :                    const char *name,
     461              :                    bool is_struct) /* else is union */
     462              : {
     463          602 :   gcc_assert (name);
     464              : 
     465              :   /* Compare with c/c-decl.cc: start_struct. */
     466              : 
     467          677 :   tree t = make_node (is_struct ? RECORD_TYPE : UNION_TYPE);
     468          602 :   TYPE_NAME (t) = get_identifier (name);
     469          602 :   TYPE_SIZE (t) = 0;
     470              : 
     471          602 :   if (loc)
     472            0 :     set_tree_location (t, loc);
     473              : 
     474          602 :   return new compound_type (t);
     475              : }
     476              : 
     477              : void
     478          572 : playback::compound_type::set_fields (const auto_vec<playback::field *> *fields)
     479              : {
     480              :   /* Compare with c/c-decl.cc: finish_struct. */
     481          572 :   tree t = as_tree ();
     482              : 
     483          572 :   tree fieldlist = NULL;
     484         2375 :   for (unsigned i = 0; i < fields->length (); i++)
     485              :     {
     486         1803 :       field *f = (*fields)[i];
     487         1803 :       tree x = f->as_tree ();
     488         1803 :       DECL_CONTEXT (x) = t;
     489         1803 :       if (DECL_JIT_BIT_FIELD (x))
     490              :         {
     491           85 :           unsigned HOST_WIDE_INT width = tree_to_uhwi (DECL_INITIAL (x));
     492           85 :           DECL_SIZE (x) = bitsize_int (width);
     493           85 :           DECL_BIT_FIELD (x) = 1;
     494              :         }
     495         1803 :       fieldlist = chainon (x, fieldlist);
     496              :     }
     497          572 :   fieldlist = nreverse (fieldlist);
     498          572 :   TYPE_FIELDS (t) = fieldlist;
     499              : 
     500          572 :   layout_type (t);
     501          572 : }
     502              : 
     503              : /* Construct a playback::type instance (wrapping a tree) for a function
     504              :    type.  */
     505              : 
     506              : playback::type *
     507         5379 : playback::context::
     508              : new_function_type (type *return_type,
     509              :                    const auto_vec<type *> *param_types,
     510              :                    int is_variadic)
     511              : {
     512         5379 :   int i;
     513         5379 :   type *param_type;
     514              : 
     515         5379 :   tree *arg_types = (tree *)xcalloc(param_types->length (), sizeof(tree*));
     516              : 
     517        15076 :   FOR_EACH_VEC_ELT (*param_types, i, param_type)
     518         4318 :     arg_types[i] = param_type->as_tree ();
     519              : 
     520         5379 :   tree fn_type;
     521         5379 :   if (is_variadic)
     522           15 :     fn_type =
     523           15 :       build_varargs_function_type_array (return_type->as_tree (),
     524           15 :                                          param_types->length (),
     525              :                                          arg_types);
     526              :   else
     527        10728 :     fn_type = build_function_type_array (return_type->as_tree (),
     528         9437 :                                          param_types->length (),
     529              :                                          arg_types);
     530         5379 :   free (arg_types);
     531              : 
     532         5379 :   return new type (fn_type);
     533              : }
     534              : 
     535              : /* Construct a playback::param instance (wrapping a tree).  */
     536              : 
     537              : playback::param *
     538        16518 : playback::context::
     539              : new_param (location *loc,
     540              :            type *type,
     541              :            const char *name)
     542              : {
     543        16518 :   gcc_assert (type);
     544        16518 :   gcc_assert (name);
     545        16518 :   tree inner = build_decl (UNKNOWN_LOCATION, PARM_DECL,
     546              :                            get_identifier (name), type->as_tree ());
     547        16518 :   if (loc)
     548           29 :     set_tree_location (inner, loc);
     549              : 
     550        16518 :   return new param (this, inner);
     551              : }
     552              : 
     553           55 : const char* fn_attribute_to_string (gcc_jit_fn_attribute attr)
     554              : {
     555           55 :   switch (attr)
     556              :   {
     557              :     case GCC_JIT_FN_ATTRIBUTE_ALIAS:
     558              :       return "alias";
     559            5 :     case GCC_JIT_FN_ATTRIBUTE_ALWAYS_INLINE:
     560            5 :       return "always_inline";
     561              :     case GCC_JIT_FN_ATTRIBUTE_INLINE:
     562              :       return NULL;
     563            5 :     case GCC_JIT_FN_ATTRIBUTE_NOINLINE:
     564            5 :       return "noinline";
     565            0 :     case GCC_JIT_FN_ATTRIBUTE_TARGET:
     566            0 :       return "target";
     567            5 :     case GCC_JIT_FN_ATTRIBUTE_USED:
     568            5 :       return "used";
     569            0 :     case GCC_JIT_FN_ATTRIBUTE_VISIBILITY:
     570            0 :       return "visibility";
     571            5 :     case GCC_JIT_FN_ATTRIBUTE_COLD:
     572            5 :       return "cold";
     573            0 :     case GCC_JIT_FN_ATTRIBUTE_RETURNS_TWICE:
     574            0 :       return "returns_twice";
     575            5 :     case GCC_JIT_FN_ATTRIBUTE_PURE:
     576            5 :       return "pure";
     577            5 :     case GCC_JIT_FN_ATTRIBUTE_CONST:
     578            5 :       return "const";
     579            5 :     case GCC_JIT_FN_ATTRIBUTE_WEAK:
     580            5 :       return "weak";
     581            5 :     case GCC_JIT_FN_ATTRIBUTE_NONNULL:
     582            5 :       return "nonnull";
     583            0 :     case GCC_JIT_FN_ATTRIBUTE_ARM_CMSE_NONSECURE_CALL:
     584            0 :       return "cmse_nonsecure_call";
     585            0 :     case GCC_JIT_FN_ATTRIBUTE_ARM_CMSE_NONSECURE_ENTRY:
     586            0 :       return "cmse_nonsecure_entry";
     587            0 :     case GCC_JIT_FN_ATTRIBUTE_ARM_PCS:
     588            0 :       return "pcs";
     589              :     case GCC_JIT_FN_ATTRIBUTE_AVR_INTERRUPT:
     590              :       return "interrupt";
     591            0 :     case GCC_JIT_FN_ATTRIBUTE_AVR_NOBLOCK:
     592            0 :       return "noblock";
     593            0 :     case GCC_JIT_FN_ATTRIBUTE_AVR_SIGNAL:
     594            0 :       return "signal";
     595            0 :     case GCC_JIT_FN_ATTRIBUTE_GCN_AMDGPU_HSA_KERNEL:
     596            0 :       return "amdgpu_hsa_kernel";
     597              :     case GCC_JIT_FN_ATTRIBUTE_MSP430_INTERRUPT:
     598              :       return "interrupt";
     599            0 :     case GCC_JIT_FN_ATTRIBUTE_NVPTX_KERNEL:
     600            0 :       return "kernel";
     601              :     case GCC_JIT_FN_ATTRIBUTE_RISCV_INTERRUPT:
     602              :       return "interrupt";
     603            0 :     case GCC_JIT_FN_ATTRIBUTE_X86_FAST_CALL:
     604            0 :       return "fastcall";
     605              :     case GCC_JIT_FN_ATTRIBUTE_X86_INTERRUPT:
     606              :       return "interrupt";
     607            5 :     case GCC_JIT_FN_ATTRIBUTE_X86_MS_ABI:
     608            5 :       return "ms_abi";
     609            0 :     case GCC_JIT_FN_ATTRIBUTE_X86_STDCALL:
     610            0 :       return "stdcall";
     611            0 :     case GCC_JIT_FN_ATTRIBUTE_X86_SYSV_ABI:
     612            0 :       return "sysv_abi";
     613            0 :     case GCC_JIT_FN_ATTRIBUTE_X86_THIS_CALL:
     614            0 :       return "thiscall";
     615              :     case GCC_JIT_FN_ATTRIBUTE_MAX:
     616              :       return NULL;
     617              :   }
     618              :   return NULL;
     619              : }
     620              : 
     621            5 : const char* variable_attribute_to_string (gcc_jit_variable_attribute attr)
     622              : {
     623            5 :   switch (attr)
     624              :   {
     625              :     case GCC_JIT_VARIABLE_ATTRIBUTE_VISIBILITY:
     626              :       return "visibility";
     627              :     case GCC_JIT_VARIABLE_ATTRIBUTE_MAX:
     628              :       return NULL;
     629              :   }
     630              :   return NULL;
     631              : }
     632              : 
     633              : /* Construct a playback::function instance.  */
     634              : 
     635              : playback::function *
     636        16667 : playback::context::
     637              : new_function (location *loc,
     638              :               enum gcc_jit_function_kind kind,
     639              :               type *return_type,
     640              :               const char *name,
     641              :               const auto_vec<param *> *params,
     642              :               int is_variadic,
     643              :               enum built_in_function builtin_id,
     644              :               const std::vector<gcc_jit_fn_attribute> &attributes,
     645              :               const std::vector<std::pair<gcc_jit_fn_attribute,
     646              :                                           std::string>> &string_attributes,
     647              :               const std::vector<std::pair<gcc_jit_fn_attribute,
     648              :                                           std::vector<int>>>
     649              :                                           &int_array_attributes,
     650              :               bool is_target_builtin)
     651              : {
     652        16667 :   int i;
     653        16667 :   param *param;
     654              : 
     655              :   //can return_type be NULL?
     656        16667 :   gcc_assert (name);
     657              : 
     658        16667 :   tree *arg_types = (tree *)xcalloc(params->length (), sizeof(tree*));
     659        49852 :   FOR_EACH_VEC_ELT (*params, i, param)
     660        16518 :     arg_types[i] = TREE_TYPE (param->as_tree ());
     661              : 
     662        16667 :   tree fn_type;
     663        16667 :   if (is_variadic)
     664          204 :     fn_type = build_varargs_function_type_array (return_type->as_tree (),
     665          154 :                                                  params->length (), arg_types);
     666              :   else
     667        33130 :     fn_type = build_function_type_array (return_type->as_tree (),
     668        30958 :                                          params->length (), arg_types);
     669        16667 :   free (arg_types);
     670              : 
     671              :   /* FIXME: this uses input_location: */
     672        16667 :   tree fndecl = build_fn_decl (name, fn_type);
     673              : 
     674        16667 :   if (loc)
     675           56 :     set_tree_location (fndecl, loc);
     676              : 
     677        16667 :   tree resdecl = build_decl (UNKNOWN_LOCATION, RESULT_DECL,
     678              :                              NULL_TREE, return_type->as_tree ());
     679        16667 :   DECL_ARTIFICIAL (resdecl) = 1;
     680        16667 :   DECL_IGNORED_P (resdecl) = 1;
     681        16667 :   DECL_RESULT (fndecl) = resdecl;
     682        16667 :   DECL_CONTEXT (resdecl) = fndecl;
     683              : 
     684        16667 :   tree fn_attributes = NULL_TREE;
     685              : 
     686        16667 :   if (is_target_builtin)
     687              :   {
     688           10 :     tree *decl = target_builtins.get (name);
     689           10 :     if (decl != NULL)
     690           10 :       fndecl = *decl;
     691              :     else
     692            0 :       add_error (loc, "cannot find target builtin %s", name);
     693              :   }
     694              : 
     695        16667 :   if (builtin_id)
     696              :     {
     697        13120 :       gcc_assert (loc == NULL);
     698        13120 :       DECL_SOURCE_LOCATION (fndecl) = BUILTINS_LOCATION;
     699              : 
     700        13120 :       built_in_class fclass = builtins_manager::get_class (builtin_id);
     701        13120 :       set_decl_built_in_function (fndecl, fclass, builtin_id);
     702        13120 :       set_builtin_decl (builtin_id, fndecl,
     703        13120 :                         builtins_manager::implicit_p (builtin_id));
     704              : 
     705        13120 :       builtins_manager *bm = get_builtins_manager ();
     706        13120 :       tree attrs = bm->get_attrs_tree (builtin_id);
     707        13120 :       if (attrs)
     708        13120 :         decl_attributes (&fndecl, attrs, ATTR_FLAG_BUILT_IN);
     709              :       else
     710            0 :         decl_attributes (&fndecl, NULL_TREE, 0);
     711              :     }
     712              : 
     713        16667 :   if (kind != GCC_JIT_FUNCTION_IMPORTED)
     714              :     {
     715              :       tree param_decl_list = NULL;
     716         7590 :       FOR_EACH_VEC_ELT (*params, i, param)
     717              :         {
     718         4244 :           param_decl_list = chainon (param->as_tree (), param_decl_list);
     719              :         }
     720              : 
     721              :       /* The param list was created in reverse order; fix it: */
     722         3346 :       param_decl_list = nreverse (param_decl_list);
     723              : 
     724         3346 :       tree t;
     725        10936 :       for (t = param_decl_list; t; t = DECL_CHAIN (t))
     726              :         {
     727         4244 :           DECL_CONTEXT (t) = fndecl;
     728         4244 :           DECL_ARG_TYPE (t) = TREE_TYPE (t);
     729              :         }
     730              : 
     731              :       /* Set it up on DECL_ARGUMENTS */
     732         3346 :       DECL_ARGUMENTS(fndecl) = param_decl_list;
     733              :     }
     734              : 
     735         3346 :   if (kind == GCC_JIT_FUNCTION_ALWAYS_INLINE)
     736              :     {
     737           15 :       DECL_DECLARED_INLINE_P (fndecl) = 1;
     738              : 
     739              :       /* Add attribute "always_inline": */
     740           15 :       fn_attributes = tree_cons (get_identifier ("always_inline"),
     741              :                                  NULL,
     742              :                                  fn_attributes);
     743              :     }
     744              : 
     745              :   /* All attributes need to be declared in `dummy-frontend.cc` and more
     746              :      specifically in `jit_attribute_table`. */
     747        16712 :   for (auto attr: attributes)
     748              :   {
     749           45 :     if (attr == GCC_JIT_FN_ATTRIBUTE_INLINE)
     750            5 :       DECL_DECLARED_INLINE_P (fndecl) = 1;
     751              : 
     752           45 :     const char* attribute = fn_attribute_to_string (attr);
     753           45 :     if (attribute)
     754              :     {
     755           40 :       tree ident = get_identifier (attribute);
     756           40 :       fn_attributes = tree_cons (ident, NULL_TREE, fn_attributes);
     757              :     }
     758              :   }
     759              : 
     760        16672 :   for (auto attr: string_attributes)
     761              :   {
     762            5 :     gcc_jit_fn_attribute& name = std::get<0>(attr);
     763            5 :     std::string& value = std::get<1>(attr);
     764           10 :     tree attribute_value = build_tree_list (NULL_TREE,
     765            5 :         ::build_string (value.length () + 1, value.c_str ()));
     766            5 :     const char* attribute = fn_attribute_to_string (name);
     767            5 :     tree ident = attribute ? get_identifier (attribute) : NULL;
     768              : 
     769            5 :     if (ident)
     770            5 :       fn_attributes = tree_cons (ident, attribute_value, fn_attributes);
     771            5 :   }
     772              : 
     773        16672 :   for (auto attr: int_array_attributes)
     774              :   {
     775            5 :     gcc_jit_fn_attribute& name = std::get<0>(attr);
     776            5 :     std::vector<int>& values = std::get<1>(attr);
     777              : 
     778            5 :     const char* attribute = fn_attribute_to_string (name);
     779            5 :     tree ident = attribute ? get_identifier (attribute) : NULL;
     780              : 
     781            5 :     if (!ident)
     782            0 :       continue;
     783              : 
     784            5 :     tree tree_list = NULL_TREE;
     785            5 :     tree *p_tree_list = &tree_list;
     786           10 :     for (auto value : values)
     787              :     {
     788            5 :       tree int_value = build_int_cst (integer_type_node, value);
     789            5 :       *p_tree_list = build_tree_list (NULL, int_value);
     790            5 :       p_tree_list = &TREE_CHAIN (*p_tree_list);
     791              :     }
     792            5 :     fn_attributes = tree_cons (ident, tree_list, fn_attributes);
     793            5 :   }
     794              : 
     795        16667 :   decl_attributes (&fndecl, fn_attributes, 0);
     796        16667 :   function *func = new function (this, fndecl, kind);
     797        16667 :   m_functions.safe_push (func);
     798        16667 :   return func;
     799              : }
     800              : 
     801              : /* In use by new_global and new_global_initialized.  */
     802              : 
     803              : tree
     804         1061 : playback::context::
     805              : global_new_decl (location *loc,
     806              :                  enum gcc_jit_global_kind kind,
     807              :                  type *type,
     808              :                  const char *name,
     809              :                  enum global_var_flags flags,
     810              :                  const std::vector<std::pair<gcc_jit_variable_attribute,
     811              :                                              std::string>> &attributes,
     812              :                  bool readonly)
     813              : {
     814         1061 :   gcc_assert (type);
     815         1061 :   gcc_assert (name);
     816              : 
     817         1061 :   tree type_tree = type->as_tree ();
     818              : 
     819         1061 :   tree inner = build_decl (UNKNOWN_LOCATION, VAR_DECL,
     820              :                            get_identifier (name),
     821              :                            type_tree);
     822              : 
     823         1061 :   TREE_PUBLIC (inner) = (kind != GCC_JIT_GLOBAL_INTERNAL);
     824              : 
     825              : 
     826         1061 :   int will_be_init = flags & (GLOBAL_VAR_FLAGS_WILL_BE_RVAL_INIT |
     827              :                               GLOBAL_VAR_FLAGS_WILL_BE_BLOB_INIT);
     828              : 
     829              :   /* A VAR_DECL with DECL_INITIAL will not end up in .common section.  */
     830         1061 :   if (!will_be_init)
     831          196 :     DECL_COMMON (inner) = 1;
     832              : 
     833         1061 :   switch (kind)
     834              :     {
     835            0 :     default:
     836            0 :       gcc_unreachable ();
     837              : 
     838          920 :     case GCC_JIT_GLOBAL_EXPORTED:
     839          920 :       TREE_STATIC (inner) = 1;
     840          920 :       break;
     841              : 
     842           96 :     case GCC_JIT_GLOBAL_INTERNAL:
     843           96 :       TREE_STATIC (inner) = 1;
     844           96 :       break;
     845              : 
     846           45 :     case GCC_JIT_GLOBAL_IMPORTED:
     847           45 :       DECL_EXTERNAL (inner) = 1;
     848           45 :       break;
     849              :     }
     850              : 
     851         1061 :   if (TYPE_READONLY (type_tree) || readonly)
     852          145 :     TREE_READONLY (inner) = 1;
     853              : 
     854         1061 :   if (loc)
     855            5 :     set_tree_location (inner, loc);
     856              : 
     857         1061 :   set_variable_string_attribute (attributes, inner);
     858              : 
     859         1061 :   return inner;
     860              : }
     861              : 
     862              : void
     863         3253 : playback::
     864              : set_variable_string_attribute (
     865              :   const std::vector<std::pair<gcc_jit_variable_attribute,
     866              :                                std::string>> &string_attributes,
     867              :   tree decl)
     868              : {
     869         3253 :   tree var_attributes = NULL_TREE;
     870         3258 :   for (auto attr: string_attributes)
     871              :   {
     872            5 :     gcc_jit_variable_attribute& name = std::get<0>(attr);
     873            5 :     std::string& value = std::get<1>(attr);
     874           10 :     tree attribute_value = build_tree_list (NULL_TREE,
     875            5 :         ::build_string (value.length () + 1, value.c_str ()));
     876            5 :     tree ident = get_identifier (variable_attribute_to_string (name));
     877            5 :     if (ident)
     878            5 :       var_attributes = tree_cons (ident, attribute_value, var_attributes);
     879            5 :   }
     880         3253 :   decl_attributes (&decl, var_attributes, 0);
     881         3253 : }
     882              : 
     883              : /* In use by new_global and new_global_initialized.  */
     884              : 
     885              : playback::lvalue *
     886         1061 : playback::context::
     887              : global_finalize_lvalue (tree inner)
     888              : {
     889         1061 :   m_globals.safe_push (inner);
     890              : 
     891         1061 :   return new lvalue (this, inner);
     892              : }
     893              : 
     894              : /* Construct a playback::lvalue instance (wrapping a tree).  */
     895              : 
     896              : playback::lvalue *
     897         1046 : playback::context::
     898              : new_global (location *loc,
     899              :             enum gcc_jit_global_kind kind,
     900              :             type *type,
     901              :             const char *name,
     902              :             enum global_var_flags flags,
     903              :             const std::vector<std::pair<gcc_jit_variable_attribute,
     904              :                                         std::string>> &attributes,
     905              :             bool readonly)
     906              : {
     907         1046 :   tree inner =
     908         1046 :     global_new_decl (loc, kind, type, name, flags, attributes, readonly);
     909              : 
     910         1046 :   return global_finalize_lvalue (inner);
     911              : }
     912              : 
     913              : void
     914          850 : playback::context::
     915              : global_set_init_rvalue (lvalue* variable,
     916              :                         rvalue* init)
     917              : {
     918          850 :   tree inner = variable->as_tree ();
     919              : 
     920              :   /* We need to fold all expressions as much as possible.  The code
     921              :      for a DECL_INITIAL only handles some operations,
     922              :      etc addition, minus, 'address of'.  See output_addressed_constants ()
     923              :      in varasm.cc.  */
     924          850 :   tree init_tree = init->as_tree ();
     925          850 :   tree folded = fold_const_var (init_tree);
     926              : 
     927          850 :   if (!TREE_CONSTANT (folded))
     928              :     {
     929           15 :       tree name = DECL_NAME (inner);
     930              : 
     931           15 :       if (name != NULL_TREE)
     932           15 :         add_error (NULL,
     933              :                    "unable to convert initial value for the global variable %s"
     934              :                    " to a compile-time constant",
     935           15 :                    IDENTIFIER_POINTER (name));
     936              :       else
     937            0 :         add_error (NULL,
     938              :                    "unable to convert initial value for global variable"
     939              :                    " to a compile-time constant");
     940           15 :       return;
     941              :     }
     942              : 
     943          835 :   DECL_INITIAL (inner) = folded;
     944              : }
     945              : 
     946              : playback::rvalue *
     947          675 : playback::context::
     948              : new_ctor (location *loc,
     949              :           type *type,
     950              :           const auto_vec<field*> *fields,
     951              :           const auto_vec<rvalue*> *rvalues)
     952              : {
     953          675 :   tree type_tree = type->as_tree ();
     954              : 
     955              :   /* Handle empty ctors first.  I.e. set everything to 0.  */
     956          675 :   if (rvalues->length () == 0)
     957           60 :     return new rvalue (this, build_constructor (type_tree, NULL));
     958              : 
     959              :   /* Handle arrays (and return).  */
     960          615 :   if (TREE_CODE (type_tree) == ARRAY_TYPE)
     961              :     {
     962          240 :       int n = rvalues->length ();
     963              :       /* The vec for the constructor node.  */
     964          240 :       vec<constructor_elt, va_gc> *v = NULL;
     965          240 :       vec_alloc (v, n);
     966              : 
     967         1020 :       for (int i = 0; i < n; i++)
     968              :         {
     969          780 :           rvalue *rv = (*rvalues)[i];
     970              :           /* null rvalues indicate that the element should be zeroed.  */
     971          780 :           if (rv)
     972          705 :             CONSTRUCTOR_APPEND_ELT (v,
     973              :                                     build_int_cst (size_type_node, i),
     974              :                                     rv->as_tree ());
     975              :           else
     976          855 :             CONSTRUCTOR_APPEND_ELT (v,
     977              :                                     build_int_cst (size_type_node, i),
     978              :                                     build_zero_cst (TREE_TYPE (type_tree)));
     979              :         }
     980              : 
     981          240 :       tree ctor = build_constructor (type_tree, v);
     982              : 
     983          240 :       if (loc)
     984            0 :         set_tree_location (ctor, loc);
     985              : 
     986          240 :       return new rvalue (this, ctor);
     987              :     }
     988              : 
     989              :   /* Handle structs and unions.  */
     990          375 :   int n = fields->length ();
     991              : 
     992              :   /* The vec for the constructor node.  */
     993          375 :   vec<constructor_elt, va_gc> *v = NULL;
     994          375 :   vec_alloc (v, n);
     995              : 
     996              :   /* Iterate over the fields, building initializations.  */
     997          990 :   for (int i = 0;i < n; i++)
     998              :     {
     999          615 :       tree field = (*fields)[i]->as_tree ();
    1000          615 :       rvalue *rv = (*rvalues)[i];
    1001              :       /* If the value is NULL, it means we should zero the field.  */
    1002          615 :       if (rv)
    1003          525 :         CONSTRUCTOR_APPEND_ELT (v, field, rv->as_tree ());
    1004              :       else
    1005              :         {
    1006           90 :           tree zero_cst = build_zero_cst (TREE_TYPE (field));
    1007          705 :           CONSTRUCTOR_APPEND_ELT (v, field, zero_cst);
    1008              :         }
    1009              :     }
    1010              : 
    1011          375 :   tree ctor = build_constructor (type_tree, v);
    1012              : 
    1013          375 :   if (loc)
    1014            0 :     set_tree_location (ctor, loc);
    1015              : 
    1016          375 :   return new rvalue (this, build_constructor (type_tree, v));
    1017              : }
    1018              : 
    1019              : /* Fill 'constructor_elements' with the memory content of
    1020              :    'initializer'.  Each element of the initializer is of the size of
    1021              :    type T.  In use by new_global_initialized.*/
    1022              : 
    1023              : template<typename T>
    1024              : static void
    1025           15 : load_blob_in_ctor (vec<constructor_elt, va_gc> *&constructor_elements,
    1026              :                    size_t num_elem,
    1027              :                    const void *initializer)
    1028              : {
    1029              :   /* Loosely based on 'output_init_element' c-typeck.cc:9691.  */
    1030           15 :   const T *p = (const T *)initializer;
    1031           15 :   tree node = make_unsigned_type (BITS_PER_UNIT * sizeof (T));
    1032        20555 :   for (size_t i = 0; i < num_elem; i++)
    1033              :     {
    1034        41080 :       constructor_elt celt =
    1035        20540 :         { build_int_cst (long_unsigned_type_node, i),
    1036        20540 :           build_int_cst (node, p[i]) };
    1037        20540 :       vec_safe_push (constructor_elements, celt);
    1038              :     }
    1039           15 : }
    1040              : 
    1041              : /* Construct an initialized playback::lvalue instance (wrapping a
    1042              :    tree).  */
    1043              : 
    1044              : playback::lvalue *
    1045           15 : playback::context::
    1046              : new_global_initialized (location *loc,
    1047              :                         enum gcc_jit_global_kind kind,
    1048              :                         type *type,
    1049              :                         size_t element_size,
    1050              :                         size_t initializer_num_elem,
    1051              :                         const void *initializer,
    1052              :                         const char *name,
    1053              :                         enum global_var_flags flags,
    1054              :                         const std::vector<std::pair<gcc_jit_variable_attribute,
    1055              :                                                     std::string>> &attributes,
    1056              :                         bool readonly)
    1057              : {
    1058           15 :   tree inner = global_new_decl (loc, kind, type, name, flags, attributes, readonly);
    1059              : 
    1060           15 :   vec<constructor_elt, va_gc> *constructor_elements = NULL;
    1061              : 
    1062           15 :   switch (element_size)
    1063              :     {
    1064           10 :     case 1:
    1065           10 :       load_blob_in_ctor<uint8_t> (constructor_elements, initializer_num_elem,
    1066              :                                   initializer);
    1067           10 :       break;
    1068            0 :     case 2:
    1069            0 :       load_blob_in_ctor<uint16_t> (constructor_elements, initializer_num_elem,
    1070              :                                    initializer);
    1071            0 :       break;
    1072            5 :     case 4:
    1073            5 :       load_blob_in_ctor<uint32_t> (constructor_elements, initializer_num_elem,
    1074              :                                    initializer);
    1075            5 :       break;
    1076            0 :     case 8:
    1077            0 :       load_blob_in_ctor<uint64_t> (constructor_elements, initializer_num_elem,
    1078              :                                    initializer);
    1079            0 :       break;
    1080            0 :     default:
    1081              :       /* This function is serving on sizes returned by 'get_size',
    1082              :          these are all covered by the previous cases.  */
    1083            0 :       gcc_unreachable ();
    1084              :     }
    1085              :   /* Compare with 'pop_init_level' c-typeck.cc:8780.  */
    1086           15 :   tree ctor = build_constructor (type->as_tree (), constructor_elements);
    1087           15 :   constructor_elements = NULL;
    1088              : 
    1089              :   /* Compare with 'store_init_value' c-typeck.cc:7555.  */
    1090           15 :   DECL_INITIAL (inner) = ctor;
    1091              : 
    1092           15 :   return global_finalize_lvalue (inner);
    1093              : }
    1094              : 
    1095              : /* Implementation of the various
    1096              :       gcc::jit::playback::context::new_rvalue_from_const <HOST_TYPE>
    1097              :    methods.
    1098              :    Each of these constructs a playback::rvalue instance (wrapping a tree).
    1099              : 
    1100              :    These specializations are required to be in the same namespace
    1101              :    as the template, hence we now have to enter the gcc::jit::playback
    1102              :    namespace.  */
    1103              : 
    1104              : namespace playback
    1105              : {
    1106              : 
    1107              : /* Specialization of making an rvalue from a const, for host <int>.  */
    1108              : 
    1109              : template <>
    1110              : rvalue *
    1111         6064 : context::
    1112              : new_rvalue_from_const <int> (type *type,
    1113              :                              int value)
    1114              : {
    1115              :   // FIXME: type-checking, or coercion?
    1116         6064 :   tree inner_type = type->as_tree ();
    1117         6064 :   if (INTEGRAL_TYPE_P (inner_type))
    1118              :     {
    1119         5457 :       tree inner = build_int_cst (inner_type, value);
    1120         5457 :       return new rvalue (this, inner);
    1121              :     }
    1122              :   else
    1123              :     {
    1124          607 :       REAL_VALUE_TYPE real_value;
    1125          607 :       real_from_integer (&real_value, VOIDmode, value, SIGNED);
    1126          607 :       tree inner = build_real (inner_type, real_value);
    1127          607 :       return new rvalue (this, inner);
    1128              :     }
    1129              : }
    1130              : 
    1131              : /* Specialization of making an rvalue from a const, for host <long>.  */
    1132              : 
    1133              : template <>
    1134              : rvalue *
    1135           75 : context::
    1136              : new_rvalue_from_const <long> (type *type,
    1137              :                               long value)
    1138              : {
    1139              :   // FIXME: type-checking, or coercion?
    1140           75 :   tree inner_type = type->as_tree ();
    1141           75 :   if (INTEGRAL_TYPE_P (inner_type))
    1142              :     {
    1143           75 :       tree inner = build_int_cst (inner_type, value);
    1144           75 :       return new rvalue (this, inner);
    1145              :     }
    1146              :   else
    1147              :     {
    1148            0 :       REAL_VALUE_TYPE real_value;
    1149            0 :       real_from_integer (&real_value, VOIDmode, value, SIGNED);
    1150            0 :       tree inner = build_real (inner_type, real_value);
    1151            0 :       return new rvalue (this, inner);
    1152              :     }
    1153              : }
    1154              : 
    1155              : /* Specialization of making an rvalue from a const, for host <double>.  */
    1156              : 
    1157              : template <>
    1158              : rvalue *
    1159          185 : context::
    1160              : new_rvalue_from_const <double> (type *type,
    1161              :                                 double value)
    1162              : {
    1163              :   // FIXME: type-checking, or coercion?
    1164          185 :   tree inner_type = type->as_tree ();
    1165              : 
    1166          185 :   mpfr_t mpf_value;
    1167              : 
    1168          185 :   mpfr_init2 (mpf_value, 64);
    1169          185 :   mpfr_set_d (mpf_value, value, MPFR_RNDN);
    1170              : 
    1171              :   /* We have a "double", we want a REAL_VALUE_TYPE.
    1172              : 
    1173              :      realmpfr.cc:real_from_mpfr.  */
    1174          185 :   REAL_VALUE_TYPE real_value;
    1175          185 :   real_from_mpfr (&real_value, mpf_value, inner_type, MPFR_RNDN);
    1176          185 :   tree inner = build_real (inner_type, real_value);
    1177          185 :   return new rvalue (this, inner);
    1178              : }
    1179              : 
    1180              : /* Specialization of making an rvalue from a const, for host <void *>.  */
    1181              : 
    1182              : template <>
    1183              : rvalue *
    1184          145 : context::
    1185              : new_rvalue_from_const <void *> (type *type,
    1186              :                                 void *value)
    1187              : {
    1188          145 :   tree inner_type = type->as_tree ();
    1189              :   /* FIXME: how to ensure we have a wide enough type?  */
    1190          145 :   tree inner = build_int_cstu (inner_type, (unsigned HOST_WIDE_INT)value);
    1191          145 :   return new rvalue (this, inner);
    1192              : }
    1193              : 
    1194              : /* We're done implementing the specializations of
    1195              :       gcc::jit::playback::context::new_rvalue_from_const <T>
    1196              :    so we can exit the gcc::jit::playback namespace.  */
    1197              : 
    1198              : } // namespace playback
    1199              : 
    1200              : /* Construct a playback::rvalue instance (wrapping a tree).  */
    1201              : 
    1202              : playback::rvalue *
    1203           15 : playback::context::
    1204              : new_sizeof (type *type)
    1205              : {
    1206           15 :   tree inner = TYPE_SIZE_UNIT (type->as_tree ());
    1207           15 :   return new rvalue (this, inner);
    1208              : }
    1209              : 
    1210              : /* Construct a playback::rvalue instance (wrapping a tree).  */
    1211              : 
    1212              : playback::rvalue *
    1213           15 : playback::context::
    1214              : new_alignof (type *type)
    1215              : {
    1216           15 :   int alignment = TYPE_ALIGN (type->as_tree ()) / BITS_PER_UNIT;
    1217           15 :   tree inner = build_int_cst (integer_type_node, alignment);
    1218           15 :   return new rvalue (this, inner);
    1219              : }
    1220              : 
    1221              : /* Construct a playback::rvalue instance (wrapping a tree).  */
    1222              : 
    1223              : playback::rvalue *
    1224          187 : playback::context::
    1225              : new_string_literal (const char *value)
    1226              : {
    1227              :   /* Compare with c-family/c-common.cc: fix_string_type.  */
    1228          187 :   size_t len = strlen (value);
    1229          187 :   tree i_type = build_index_type (size_int (len));
    1230          187 :   tree a_type = build_array_type (char_type_node, i_type);
    1231              :   /* build_string len parameter must include NUL terminator when
    1232              :      building C strings.  */
    1233          187 :   tree t_str = ::build_string (len + 1, value);
    1234          187 :   TREE_TYPE (t_str) = a_type;
    1235              : 
    1236              :   /* Convert to (const char*), loosely based on
    1237              :      c/c-typeck.cc: array_to_pointer_conversion,
    1238              :      by taking address of start of string.  */
    1239          187 :   tree t_addr = build1 (ADDR_EXPR, m_const_char_ptr, t_str);
    1240              : 
    1241          187 :   return new rvalue (this, t_addr);
    1242              : }
    1243              : 
    1244              : /* Construct a playback::rvalue instance (wrapping a tree) for a
    1245              :    vector.  */
    1246              : 
    1247              : playback::rvalue *
    1248          120 : playback::context::new_rvalue_from_vector (location *,
    1249              :                                            type *type,
    1250              :                                            const auto_vec<rvalue *> &elements)
    1251              : {
    1252          120 :   vec<constructor_elt, va_gc> *v;
    1253          240 :   vec_alloc (v, elements.length ());
    1254          600 :   for (unsigned i = 0; i < elements.length (); ++i)
    1255          480 :     CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, elements[i]->as_tree ());
    1256          120 :   tree t_ctor = build_constructor (type->as_tree (), v);
    1257          120 :   return new rvalue (this, t_ctor);
    1258              : }
    1259              : 
    1260              : /* Construct a playback::rvalue instance (wrapping a tree) for a
    1261              :    vector perm.  */
    1262              : 
    1263              : playback::rvalue *
    1264           15 : playback::context::new_rvalue_vector_perm (location *loc,
    1265              :                                            rvalue* elements1,
    1266              :                                            rvalue* elements2,
    1267              :                                            rvalue* mask)
    1268              : {
    1269           15 :   tree t_elements1 = elements1->as_tree ();
    1270           15 :   tree t_elements2 = elements2->as_tree ();
    1271           15 :   tree t_mask = mask->as_tree ();
    1272              : 
    1273           15 :   tree t_vector_perm = build3 (VEC_PERM_EXPR, TREE_TYPE (t_elements1),
    1274              :                                t_elements1, t_elements2, t_mask);
    1275           15 :   if (loc)
    1276            0 :     set_tree_location (t_vector_perm, loc);
    1277           15 :   return new rvalue (this, t_vector_perm);
    1278              : }
    1279              : 
    1280              : /* Coerce a tree expression into a boolean tree expression.  */
    1281              : 
    1282              : tree
    1283          620 : playback::context::
    1284              : as_truth_value (tree expr, location *loc)
    1285              : {
    1286              :   /* Compare to c-typeck.cc:c_objc_common_truthvalue_conversion */
    1287          620 :   tree typed_zero = fold_build1 (CONVERT_EXPR,
    1288              :                                  TREE_TYPE (expr),
    1289              :                                  integer_zero_node);
    1290          620 :   if (loc)
    1291            0 :     set_tree_location (typed_zero, loc);
    1292              : 
    1293          620 :   tree type = TREE_TYPE (expr);
    1294          620 :   expr = fold_build2_loc (UNKNOWN_LOCATION,
    1295              :     NE_EXPR, type, expr, typed_zero);
    1296          620 :   if (loc)
    1297            0 :     set_tree_location (expr, loc);
    1298              : 
    1299          620 :   return expr;
    1300              : }
    1301              : 
    1302              : /* Add a "top-level" basic asm statement (i.e. one outside of any functions)
    1303              :    containing ASM_STMTS.
    1304              : 
    1305              :    Compare with c_parser_asm_definition.  */
    1306              : 
    1307              : void
    1308           10 : playback::context::add_top_level_asm (const char *asm_stmts)
    1309              : {
    1310           10 :   tree asm_str = build_string (asm_stmts);
    1311           10 :   symtab->finalize_toplevel_asm (asm_str);
    1312           10 : }
    1313              : 
    1314              : /* Construct a playback::rvalue instance (wrapping a tree) for a
    1315              :    unary op.  */
    1316              : 
    1317              : playback::rvalue *
    1318          128 : playback::context::
    1319              : new_unary_op (location *loc,
    1320              :               enum gcc_jit_unary_op op,
    1321              :               type *result_type,
    1322              :               rvalue *a)
    1323              : {
    1324              :   // FIXME: type-checking, or coercion?
    1325          128 :   enum tree_code inner_op;
    1326              : 
    1327          128 :   gcc_assert (result_type);
    1328          128 :   gcc_assert (a);
    1329              : 
    1330          128 :   tree node = a->as_tree ();
    1331          128 :   node = fold_const_var (node);
    1332              : 
    1333          128 :   tree inner_result = NULL;
    1334              : 
    1335          128 :   switch (op)
    1336              :     {
    1337            0 :     default:
    1338            0 :       add_error (loc, "unrecognized (enum gcc_jit_unary_op) value: %i", op);
    1339            0 :       return NULL;
    1340              : 
    1341              :     case GCC_JIT_UNARY_OP_MINUS:
    1342              :       inner_op = NEGATE_EXPR;
    1343              :       break;
    1344              : 
    1345           30 :     case GCC_JIT_UNARY_OP_BITWISE_NEGATE:
    1346           30 :       inner_op = BIT_NOT_EXPR;
    1347           30 :       break;
    1348              : 
    1349           20 :     case GCC_JIT_UNARY_OP_LOGICAL_NEGATE:
    1350           20 :       node = as_truth_value (node, loc);
    1351           20 :       inner_result = invert_truthvalue (node);
    1352           20 :       if (loc)
    1353            0 :         set_tree_location (inner_result, loc);
    1354           20 :       return new rvalue (this, inner_result);
    1355              : 
    1356           15 :     case GCC_JIT_UNARY_OP_ABS:
    1357           15 :       inner_op = ABS_EXPR;
    1358           15 :       break;
    1359              :     }
    1360              : 
    1361          108 :   inner_result = build1 (inner_op,
    1362              :                          result_type->as_tree (),
    1363              :                          node);
    1364              : 
    1365              :   /* Try to fold.  */
    1366          108 :   inner_result = fold (inner_result);
    1367              : 
    1368          108 :   if (loc)
    1369            0 :     set_tree_location (inner_result, loc);
    1370              : 
    1371          108 :   return new rvalue (this, inner_result);
    1372              : }
    1373              : 
    1374              : /* Construct a playback::rvalue instance (wrapping a tree) for a
    1375              :    binary op.  */
    1376              : 
    1377              : playback::rvalue *
    1378         3844 : playback::context::
    1379              : new_binary_op (location *loc,
    1380              :                enum gcc_jit_binary_op op,
    1381              :                type *result_type,
    1382              :                rvalue *a, rvalue *b)
    1383              : {
    1384              :   // FIXME: type-checking, or coercion?
    1385         3844 :   enum tree_code inner_op;
    1386              : 
    1387         3844 :   gcc_assert (result_type);
    1388         3844 :   gcc_assert (a);
    1389         3844 :   gcc_assert (b);
    1390              : 
    1391         3844 :   tree node_a = a->as_tree ();
    1392         3844 :   node_a = fold_const_var (node_a);
    1393              : 
    1394         3844 :   tree node_b = b->as_tree ();
    1395         3844 :   node_b = fold_const_var (node_b);
    1396              : 
    1397         3844 :   switch (op)
    1398              :     {
    1399            0 :     default:
    1400            0 :       add_error (loc, "unrecognized (enum gcc_jit_binary_op) value: %i", op);
    1401            0 :       return NULL;
    1402              : 
    1403              :     case GCC_JIT_BINARY_OP_PLUS:
    1404              :       inner_op = PLUS_EXPR;
    1405              :       break;
    1406              : 
    1407          278 :     case GCC_JIT_BINARY_OP_MINUS:
    1408          278 :       inner_op = MINUS_EXPR;
    1409          278 :       break;
    1410              : 
    1411         1250 :     case GCC_JIT_BINARY_OP_MULT:
    1412         1250 :       inner_op = MULT_EXPR;
    1413         1250 :       break;
    1414              : 
    1415          159 :     case GCC_JIT_BINARY_OP_DIVIDE:
    1416          159 :       if (FLOAT_TYPE_P (result_type->as_tree ()))
    1417              :         /* Floating-point division: */
    1418              :         inner_op = RDIV_EXPR;
    1419              :       else
    1420              :         /* Truncating to zero: */
    1421              :         inner_op = TRUNC_DIV_EXPR;
    1422              :       break;
    1423              : 
    1424           15 :     case GCC_JIT_BINARY_OP_MODULO:
    1425           15 :       inner_op = TRUNC_MOD_EXPR;
    1426           15 :       break;
    1427              : 
    1428          215 :     case GCC_JIT_BINARY_OP_BITWISE_AND:
    1429          215 :       inner_op = BIT_AND_EXPR;
    1430          215 :       break;
    1431              : 
    1432           30 :     case GCC_JIT_BINARY_OP_BITWISE_XOR:
    1433           30 :       inner_op = BIT_XOR_EXPR;
    1434           30 :       break;
    1435              : 
    1436           30 :     case GCC_JIT_BINARY_OP_BITWISE_OR:
    1437           30 :       inner_op = BIT_IOR_EXPR;
    1438           30 :       break;
    1439              : 
    1440          240 :     case GCC_JIT_BINARY_OP_LOGICAL_AND:
    1441          240 :       node_a = as_truth_value (node_a, loc);
    1442          240 :       node_b = as_truth_value (node_b, loc);
    1443          240 :       inner_op = TRUTH_ANDIF_EXPR;
    1444          240 :       break;
    1445              : 
    1446           60 :     case GCC_JIT_BINARY_OP_LOGICAL_OR:
    1447           60 :       node_a = as_truth_value (node_a, loc);
    1448           60 :       node_b = as_truth_value (node_b, loc);
    1449           60 :       inner_op = TRUTH_ORIF_EXPR;
    1450           60 :       break;
    1451              : 
    1452           30 :     case GCC_JIT_BINARY_OP_LSHIFT:
    1453           30 :       inner_op = LSHIFT_EXPR;
    1454           30 :       break;
    1455              : 
    1456           40 :     case GCC_JIT_BINARY_OP_RSHIFT:
    1457           40 :       inner_op = RSHIFT_EXPR;
    1458           40 :       break;
    1459              :     }
    1460              : 
    1461         3844 :   tree inner_expr = build2 (inner_op,
    1462              :                             result_type->as_tree (),
    1463              :                             node_a,
    1464              :                             node_b);
    1465              : 
    1466              :   /* Try to fold the expression.  */
    1467         3844 :   inner_expr = fold (inner_expr);
    1468              : 
    1469         3844 :   if (loc)
    1470          265 :     set_tree_location (inner_expr, loc);
    1471              : 
    1472         3844 :   return new rvalue (this, inner_expr);
    1473              : }
    1474              : 
    1475              : /* Construct a playback::rvalue instance (wrapping a tree) for a
    1476              :    comparison.  */
    1477              : 
    1478              : playback::rvalue *
    1479         1509 : playback::context::
    1480              : new_comparison (location *loc,
    1481              :                 enum gcc_jit_comparison op,
    1482              :                 rvalue *a, rvalue *b, type *vec_result_type)
    1483              : {
    1484              :   // FIXME: type-checking, or coercion?
    1485         1509 :   enum tree_code inner_op;
    1486              : 
    1487         1509 :   gcc_assert (a);
    1488         1509 :   gcc_assert (b);
    1489              : 
    1490         1509 :   switch (op)
    1491              :     {
    1492            0 :     default:
    1493            0 :       add_error (loc, "unrecognized (enum gcc_jit_comparison) value: %i", op);
    1494            0 :       return NULL;
    1495              : 
    1496              :     case GCC_JIT_COMPARISON_EQ:
    1497              :       inner_op = EQ_EXPR;
    1498              :       break;
    1499              :     case GCC_JIT_COMPARISON_NE:
    1500              :       inner_op = NE_EXPR;
    1501              :       break;
    1502              :     case GCC_JIT_COMPARISON_LT:
    1503              :       inner_op = LT_EXPR;
    1504              :       break;
    1505              :     case GCC_JIT_COMPARISON_LE:
    1506              :       inner_op = LE_EXPR;
    1507              :       break;
    1508              :     case GCC_JIT_COMPARISON_GT:
    1509              :       inner_op = GT_EXPR;
    1510              :       break;
    1511              :     case GCC_JIT_COMPARISON_GE:
    1512              :       inner_op = GE_EXPR;
    1513              :       break;
    1514              :     }
    1515              : 
    1516         1509 :   tree node_a = a->as_tree ();
    1517         1509 :   node_a = fold_const_var (node_a);
    1518         1509 :   tree node_b = b->as_tree ();
    1519         1509 :   node_b = fold_const_var (node_b);
    1520              : 
    1521         1509 :   tree inner_expr;
    1522         1509 :   tree a_type = TREE_TYPE (node_a);
    1523         1509 :   if (VECTOR_TYPE_P (a_type))
    1524              :   {
    1525              :     /* Build a vector comparison.  See build_vec_cmp in c-typeck.cc for
    1526              :        reference.  */
    1527          135 :     tree t_vec_result_type = vec_result_type->as_tree ();
    1528          135 :     tree zero_vec = build_zero_cst (t_vec_result_type);
    1529          135 :     tree minus_one_vec = build_minus_one_cst (t_vec_result_type);
    1530          135 :     tree cmp_type = truth_type_for (a_type);
    1531          135 :     tree cmp = build2 (inner_op, cmp_type, node_a, node_b);
    1532          135 :     inner_expr = build3 (VEC_COND_EXPR, t_vec_result_type, cmp, minus_one_vec,
    1533              :                          zero_vec);
    1534              :   }
    1535              :   else
    1536              :   {
    1537         1374 :     inner_expr = build2 (inner_op,
    1538              :                          boolean_type_node,
    1539              :                          node_a,
    1540              :                          node_b);
    1541              :   }
    1542              : 
    1543              :   /* Try to fold.  */
    1544         1509 :   inner_expr = fold (inner_expr);
    1545              : 
    1546         1509 :   if (loc)
    1547           21 :     set_tree_location (inner_expr, loc);
    1548         1509 :   return new rvalue (this, inner_expr);
    1549              : }
    1550              : 
    1551              : /* Construct a playback::rvalue instance (wrapping a tree) for a
    1552              :    function call.  */
    1553              : 
    1554              : playback::rvalue *
    1555          820 : playback::context::
    1556              : build_call (location *loc,
    1557              :             tree fn_ptr,
    1558              :             const auto_vec<rvalue *> *args,
    1559              :             bool require_tail_call)
    1560              : {
    1561          820 :   vec<tree, va_gc> *tree_args;
    1562         1545 :   vec_alloc (tree_args, args->length ());
    1563         1987 :   for (unsigned i = 0; i < args->length (); i++)
    1564         1167 :     tree_args->quick_push ((*args)[i]->as_tree ());
    1565              : 
    1566          820 :   if (loc)
    1567           37 :     set_tree_location (fn_ptr, loc);
    1568              : 
    1569          820 :   tree fn = TREE_TYPE (fn_ptr);
    1570          820 :   tree fn_type = TREE_TYPE (fn);
    1571          820 :   tree return_type = TREE_TYPE (fn_type);
    1572              : 
    1573          820 :   tree call = build_call_vec (return_type,
    1574              :                               fn_ptr, tree_args);
    1575              : 
    1576          820 :   if (require_tail_call)
    1577           20 :     CALL_EXPR_MUST_TAIL_CALL (call) = 1;
    1578              : 
    1579          820 :   return new rvalue (this, call);
    1580              : 
    1581              :   /* see c-typeck.cc: build_function_call
    1582              :      which calls build_function_call_vec
    1583              : 
    1584              :      which does lots of checking, then:
    1585              :     result = build_call_array_loc (loc, TREE_TYPE (fntype),
    1586              :                                    function, nargs, argarray);
    1587              :     which is in tree.cc
    1588              :     (see also build_call_vec)
    1589              :    */
    1590              : }
    1591              : 
    1592              : /* Construct a playback::rvalue instance (wrapping a tree) for a
    1593              :    call to a specific function.  */
    1594              : 
    1595              : playback::rvalue *
    1596          805 : playback::context::
    1597              : new_call (location *loc,
    1598              :           function *func,
    1599              :           const auto_vec<rvalue *> *args,
    1600              :           bool require_tail_call)
    1601              : {
    1602          805 :   tree fndecl;
    1603              : 
    1604          805 :   gcc_assert (func);
    1605              : 
    1606          805 :   fndecl = func->as_fndecl ();
    1607              : 
    1608          805 :   tree fntype = TREE_TYPE (fndecl);
    1609              : 
    1610          805 :   tree fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl);
    1611              : 
    1612          805 :   return build_call (loc, fn, args, require_tail_call);
    1613              : }
    1614              : 
    1615              : /* Construct a playback::rvalue instance (wrapping a tree) for a
    1616              :    call through a function pointer.  */
    1617              : 
    1618              : playback::rvalue *
    1619           15 : playback::context::
    1620              : new_call_through_ptr (location *loc,
    1621              :                       rvalue *fn_ptr,
    1622              :                       const auto_vec<rvalue *> *args,
    1623              :                       bool require_tail_call)
    1624              : {
    1625           15 :   gcc_assert (fn_ptr);
    1626           15 :   tree t_fn_ptr = fn_ptr->as_tree ();
    1627              : 
    1628           15 :   return build_call (loc, t_fn_ptr, args, require_tail_call);
    1629              : }
    1630              : 
    1631              : /* Construct a tree for a cast.  */
    1632              : 
    1633              : tree
    1634          379 : playback::context::build_cast (playback::location *loc,
    1635              :                                playback::rvalue *expr,
    1636              :                                playback::type *type_)
    1637              : {
    1638              :   /* For comparison, see:
    1639              :      - c/c-typeck.cc:build_c_cast
    1640              :      - c/c-convert.cc: convert
    1641              :      - convert.h
    1642              : 
    1643              :      Only some kinds of cast are currently supported here.  */
    1644          379 :   tree t_expr = expr->as_tree ();
    1645          379 :   t_expr = fold_const_var (t_expr);
    1646              : 
    1647          379 :   tree t_dst_type = type_->as_tree ();
    1648          379 :   tree t_ret = NULL;
    1649          379 :   t_ret = targetm.convert_to_type (t_dst_type, t_expr);
    1650          379 :   if (t_ret)
    1651              :       return t_ret;
    1652          379 :   enum tree_code dst_code = TREE_CODE (t_dst_type);
    1653          379 :   switch (dst_code)
    1654              :     {
    1655          155 :     case INTEGER_TYPE:
    1656          155 :     case ENUMERAL_TYPE:
    1657          155 :       t_ret = convert_to_integer (t_dst_type, t_expr);
    1658          155 :       goto maybe_fold;
    1659              : 
    1660           34 :     case BOOLEAN_TYPE:
    1661              :       /* Compare with c_objc_common_truthvalue_conversion and
    1662              :          c_common_truthvalue_conversion. */
    1663              :       /* For now, convert to: (t_expr != 0)  */
    1664           34 :       t_ret = build2 (NE_EXPR, t_dst_type,
    1665              :                       t_expr,
    1666           34 :                       build_int_cst (TREE_TYPE (t_expr), 0));
    1667           34 :       goto maybe_fold;
    1668              : 
    1669           15 :     case REAL_TYPE:
    1670           15 :       t_ret = convert_to_real (t_dst_type, t_expr);
    1671           15 :       goto maybe_fold;
    1672              : 
    1673          175 :     case POINTER_TYPE:
    1674          175 :       t_ret = build1 (NOP_EXPR, t_dst_type, t_expr);
    1675          175 :       goto maybe_fold;
    1676              : 
    1677            0 :     default:
    1678            0 :       add_error (loc, "couldn't handle cast during playback");
    1679            0 :       fprintf (stderr, "input expression:\n");
    1680            0 :       debug_tree (t_expr);
    1681            0 :       fprintf (stderr, "requested type:\n");
    1682            0 :       debug_tree (t_dst_type);
    1683            0 :       return error_mark_node;
    1684              : 
    1685          379 :     maybe_fold:
    1686          379 :       if (TREE_CODE (t_ret) != C_MAYBE_CONST_EXPR)
    1687          379 :         t_ret = fold (t_ret);
    1688              :       return t_ret;
    1689              :     }
    1690              : }
    1691              : 
    1692              : /* Construct a playback::rvalue instance (wrapping a tree) for a
    1693              :    cast.  */
    1694              : 
    1695              : playback::rvalue *
    1696          379 : playback::context::
    1697              : new_cast (playback::location *loc,
    1698              :           playback::rvalue *expr,
    1699              :           playback::type *type_)
    1700              : {
    1701              : 
    1702          379 :   tree t_cast = build_cast (loc, expr, type_);
    1703          379 :   if (loc)
    1704            9 :     set_tree_location (t_cast, loc);
    1705          379 :   return new rvalue (this, t_cast);
    1706              : }
    1707              : 
    1708              : /* Construct a playback::rvalue instance (wrapping a tree) for a
    1709              :    bitcast.  */
    1710              : 
    1711              : playback::rvalue *
    1712           25 : playback::context::
    1713              : new_bitcast (location *loc,
    1714              :              rvalue *expr,
    1715              :              type *type_)
    1716              : {
    1717           25 :   tree expr_size = TYPE_SIZE (expr->get_type ()->as_tree ());
    1718           25 :   tree type_size = TYPE_SIZE (type_->as_tree ());
    1719           25 :   tree t_expr = expr->as_tree ();
    1720           25 :   tree t_dst_type = type_->as_tree ();
    1721           25 :   if (expr_size != type_size)
    1722              :   {
    1723           10 :     active_playback_ctxt->add_error (loc,
    1724              :       "bitcast with types of different sizes");
    1725           10 :     fprintf (stderr, "input expression (size: " HOST_WIDE_INT_PRINT_DEC "):\n",
    1726              :              tree_to_uhwi (expr_size));
    1727           10 :     debug_tree (t_expr);
    1728           10 :     fprintf (stderr, "requested type (size: " HOST_WIDE_INT_PRINT_DEC "):\n",
    1729              :              tree_to_uhwi (type_size));
    1730           10 :     debug_tree (t_dst_type);
    1731              :   }
    1732           25 :   tree t_bitcast = build1 (VIEW_CONVERT_EXPR, t_dst_type, t_expr);
    1733           25 :   if (loc)
    1734            0 :     set_tree_location (t_bitcast, loc);
    1735           25 :   return new rvalue (this, t_bitcast);
    1736              : }
    1737              : 
    1738              : /* Construct a playback::lvalue instance (wrapping a tree) for an
    1739              :    array access.  */
    1740              : 
    1741              : playback::lvalue *
    1742          474 : playback::context::
    1743              : new_array_access (location *loc,
    1744              :                   rvalue *ptr,
    1745              :                   rvalue *index)
    1746              : {
    1747          474 :   gcc_assert (ptr);
    1748          474 :   gcc_assert (index);
    1749              : 
    1750              :   /* For comparison, see:
    1751              :        c/c-typeck.cc: build_array_ref
    1752              :        c-family/c-common.cc: pointer_int_sum
    1753              :   */
    1754          474 :   tree t_ptr = ptr->as_tree ();
    1755          474 :   t_ptr = fold_const_var (t_ptr);
    1756          474 :   tree t_index = index->as_tree ();
    1757          474 :   t_index = fold_const_var (t_index);
    1758              : 
    1759          474 :   tree t_type_ptr = TREE_TYPE (t_ptr);
    1760          474 :   tree t_type_star_ptr = TREE_TYPE (t_type_ptr);
    1761              : 
    1762          474 :   if (TREE_CODE (t_type_ptr) == ARRAY_TYPE)
    1763              :     {
    1764          299 :       tree t_result = build4 (ARRAY_REF, t_type_star_ptr, t_ptr, t_index,
    1765              :                               NULL_TREE, NULL_TREE);
    1766          299 :       t_result = fold (t_result);
    1767          299 :       if (loc)
    1768          209 :         set_tree_location (t_result, loc);
    1769          299 :       return new lvalue (this, t_result);
    1770              :     }
    1771              :   else
    1772              :     {
    1773              :       /* Convert index to an offset in bytes.  */
    1774          175 :       tree t_sizeof = size_in_bytes (t_type_star_ptr);
    1775          175 :       t_index = fold_build1 (CONVERT_EXPR, sizetype, t_index);
    1776          175 :       tree t_offset = fold_build2_loc (UNKNOWN_LOCATION,
    1777              :         MULT_EXPR, sizetype, t_index, t_sizeof);
    1778              : 
    1779              :       /* Locate (ptr + offset).  */
    1780          175 :       tree t_address = fold_build2_loc (UNKNOWN_LOCATION,
    1781              :         POINTER_PLUS_EXPR, t_type_ptr, t_ptr, t_offset);
    1782              : 
    1783          175 :       tree t_indirection = fold_build1 (INDIRECT_REF, t_type_star_ptr, t_address);
    1784          175 :       if (loc)
    1785              :         {
    1786            0 :           set_tree_location (t_sizeof, loc);
    1787            0 :           set_tree_location (t_offset, loc);
    1788            0 :           set_tree_location (t_address, loc);
    1789            0 :           set_tree_location (t_indirection, loc);
    1790              :         }
    1791              : 
    1792          175 :       return new lvalue (this, t_indirection);
    1793              :     }
    1794              : }
    1795              : 
    1796              : /* Construct a playback::rvalue instance (wrapping a tree) for a
    1797              :    vector conversion.  */
    1798              : 
    1799              : playback::rvalue *
    1800           15 : playback::context::
    1801              : convert_vector (location *loc,
    1802              :                    rvalue *vector,
    1803              :                    type *type)
    1804              : {
    1805           15 :   gcc_assert (vector);
    1806           15 :   gcc_assert (type);
    1807              : 
    1808              :   /* For comparison, see:
    1809              :        c/c-common.cc: c_build_vec_convert
    1810              :   */
    1811              : 
    1812           15 :   tree t_vector = vector->as_tree ();
    1813              : 
    1814           15 :   tree t_result =
    1815           15 :     build_call_expr_internal_loc (UNKNOWN_LOCATION, IFN_VEC_CONVERT,
    1816              :       type->as_tree (), 1, t_vector);
    1817              : 
    1818           15 :   if (loc)
    1819            0 :     set_tree_location (t_result, loc);
    1820              : 
    1821           15 :   return new rvalue (this, t_result);
    1822              : }
    1823              : 
    1824              : /* The following functions come from c-common.h.  */
    1825              : /* Like c_mark_addressable but don't check register qualifier.  */
    1826              : void
    1827           15 : common_mark_addressable_vec (tree t)
    1828              : {
    1829           15 :   while (handled_component_p (t) || TREE_CODE (t) == C_MAYBE_CONST_EXPR)
    1830              :     {
    1831            0 :       t = TREE_OPERAND (t, 0);
    1832              :     }
    1833           15 :   if (!VAR_P (t)
    1834           15 :       && TREE_CODE (t) != PARM_DECL
    1835           15 :       && TREE_CODE (t) != COMPOUND_LITERAL_EXPR
    1836           15 :       && TREE_CODE (t) != TARGET_EXPR)
    1837              :     return;
    1838            0 :   if (!VAR_P (t) || !DECL_HARD_REGISTER (t))
    1839            0 :     TREE_ADDRESSABLE (t) = 1;
    1840            0 :   if (TREE_CODE (t) == COMPOUND_LITERAL_EXPR)
    1841            0 :     TREE_ADDRESSABLE (COMPOUND_LITERAL_EXPR_DECL (t)) = 1;
    1842            0 :   else if (TREE_CODE (t) == TARGET_EXPR)
    1843            0 :     TREE_ADDRESSABLE (TARGET_EXPR_SLOT (t)) = 1;
    1844              : }
    1845              : 
    1846              : /* Return true if TYPE is a vector type that should be subject to the GNU
    1847              :    vector extensions (as opposed to a vector type that is used only for
    1848              :    the purposes of defining target-specific built-in functions).  */
    1849              : 
    1850              : inline bool
    1851           15 : gnu_vector_type_p (const_tree type)
    1852              : {
    1853           15 :   return TREE_CODE (type) == VECTOR_TYPE && !TYPE_INDIVISIBLE_P (type);
    1854              : }
    1855              : 
    1856              : /* Return nonzero if REF is an lvalue valid for this language.
    1857              :    Lvalues can be assigned, unless their type has TYPE_READONLY.
    1858              :    Lvalues can have their address taken, unless they have C_DECL_REGISTER.  */
    1859              : 
    1860              : bool
    1861           15 : lvalue_p (const_tree ref)
    1862              : {
    1863           15 :   const enum tree_code code = TREE_CODE (ref);
    1864              : 
    1865           15 :   switch (code)
    1866              :     {
    1867            0 :     case REALPART_EXPR:
    1868            0 :     case IMAGPART_EXPR:
    1869            0 :     case COMPONENT_REF:
    1870            0 :       return lvalue_p (TREE_OPERAND (ref, 0));
    1871              : 
    1872            0 :     case C_MAYBE_CONST_EXPR:
    1873            0 :       return lvalue_p (TREE_OPERAND (ref, 1));
    1874              : 
    1875              :     case COMPOUND_LITERAL_EXPR:
    1876              :     case STRING_CST:
    1877              :       return true;
    1878              : 
    1879            0 :     case MEM_REF:
    1880            0 :     case TARGET_MEM_REF:
    1881              :       /* MEM_REFs can appear from -fgimple parsing or folding, so allow them
    1882              :          here as well.  */
    1883            0 :     case INDIRECT_REF:
    1884            0 :     case ARRAY_REF:
    1885            0 :     case VAR_DECL:
    1886            0 :     case PARM_DECL:
    1887            0 :     case RESULT_DECL:
    1888            0 :     case ERROR_MARK:
    1889            0 :       return (TREE_CODE (TREE_TYPE (ref)) != FUNCTION_TYPE
    1890            0 :               && TREE_CODE (TREE_TYPE (ref)) != METHOD_TYPE);
    1891              : 
    1892            0 :     case BIND_EXPR:
    1893            0 :       return TREE_CODE (TREE_TYPE (ref)) == ARRAY_TYPE;
    1894              : 
    1895              :     default:
    1896              :       return false;
    1897              :     }
    1898              : }
    1899              : 
    1900              : bool
    1901           15 : convert_vector_to_array_for_subscript (tree *vecp)
    1902              : {
    1903           15 :   bool ret = false;
    1904           15 :   if (gnu_vector_type_p (TREE_TYPE (*vecp)))
    1905              :     {
    1906           15 :       tree type = TREE_TYPE (*vecp);
    1907              : 
    1908           15 :       ret = !lvalue_p (*vecp);
    1909              : 
    1910              :       /* We are building an ARRAY_REF so mark the vector as addressable
    1911              :         to not run into the gimplifiers premature setting of DECL_GIMPLE_REG_P
    1912              :          for function parameters.  */
    1913              :       /* NOTE: that was the missing piece for making vector access work with
    1914              :         optimizations enabled.  */
    1915           15 :       common_mark_addressable_vec (*vecp);
    1916              : 
    1917           30 :       *vecp = build1 (VIEW_CONVERT_EXPR,
    1918           15 :                       build_array_type_nelts (TREE_TYPE (type),
    1919              :                                               TYPE_VECTOR_SUBPARTS (type)),
    1920              :                       *vecp);
    1921              :     }
    1922           15 :   return ret;
    1923              : }
    1924              : 
    1925              : /* Construct a playback::lvalue instance (wrapping a tree) for a
    1926              :    vector access.  */
    1927              : 
    1928              : playback::lvalue *
    1929           15 : playback::context::
    1930              : new_vector_access (location *loc,
    1931              :                    rvalue *vector,
    1932              :                    rvalue *index)
    1933              : {
    1934           15 :   gcc_assert (vector);
    1935           15 :   gcc_assert (index);
    1936              : 
    1937              :   /* For comparison, see:
    1938              :        c/c-typeck.cc: build_array_ref
    1939              :   */
    1940              : 
    1941           15 :   tree t_vector = vector->as_tree ();
    1942           15 :   bool non_lvalue = convert_vector_to_array_for_subscript (&t_vector);
    1943           15 :   tree type = TREE_TYPE (TREE_TYPE (t_vector));
    1944           15 :   tree t_result = build4 (ARRAY_REF, type, t_vector, index->as_tree (),
    1945              :                           NULL_TREE, NULL_TREE);
    1946           15 :   if (non_lvalue)
    1947           15 :     t_result = non_lvalue (t_result);
    1948              : 
    1949           15 :   if (loc)
    1950            0 :     set_tree_location (t_result, loc);
    1951           15 :   return new lvalue (this, t_result);
    1952              : }
    1953              : 
    1954              : /* Construct a tree for a field access.  */
    1955              : 
    1956              : tree
    1957         1886 : playback::context::
    1958              : new_field_access (location *loc,
    1959              :                   tree datum,
    1960              :                   field *field)
    1961              : {
    1962         1886 :   gcc_assert (datum);
    1963         1886 :   gcc_assert (field);
    1964              : 
    1965              :   /* Compare with c/c-typeck.cc:lookup_field, build_indirect_ref, and
    1966              :      build_component_ref. */
    1967         1886 :   tree type = TREE_TYPE (datum);
    1968         1886 :   gcc_assert (type);
    1969         1886 :   gcc_assert (TREE_CODE (type) != POINTER_TYPE);
    1970              : 
    1971         1886 :  tree t_field = field->as_tree ();
    1972         1886 :  tree ref = build3 (COMPONENT_REF, TREE_TYPE (t_field), datum,
    1973              :                      t_field, NULL_TREE);
    1974         1886 :   if (loc)
    1975            0 :     set_tree_location (ref, loc);
    1976         1886 :   return ref;
    1977              : }
    1978              : 
    1979              : /* Construct a tree for a dereference.  */
    1980              : 
    1981              : tree
    1982         2232 : playback::context::
    1983              : new_dereference (tree ptr,
    1984              :                  location *loc)
    1985              : {
    1986         2232 :   gcc_assert (ptr);
    1987              : 
    1988         2232 :   tree type = TREE_TYPE (TREE_TYPE(ptr));
    1989         2232 :   tree datum = fold_build1 (INDIRECT_REF, type, ptr);
    1990         2232 :   if (loc)
    1991            0 :     set_tree_location (datum, loc);
    1992         2232 :   return datum;
    1993              : }
    1994              : 
    1995              : /* Construct a playback::type instance (wrapping a tree)
    1996              :    with the given alignment.  */
    1997              : 
    1998              : playback::type *
    1999          160 : playback::type::
    2000              : get_aligned (size_t alignment_in_bytes) const
    2001              : {
    2002          160 :   tree t_new_type = build_variant_type_copy (m_inner);
    2003              : 
    2004          160 :   SET_TYPE_ALIGN (t_new_type, alignment_in_bytes * BITS_PER_UNIT);
    2005          160 :   TYPE_USER_ALIGN (t_new_type) = 1;
    2006              : 
    2007          160 :   return new type (t_new_type);
    2008              : }
    2009              : 
    2010              : /* Construct a playback::type instance (wrapping a tree)
    2011              :    for the given vector type.  */
    2012              : 
    2013              : playback::type *
    2014          375 : playback::type::
    2015              : get_vector (size_t num_units) const
    2016              : {
    2017          375 :   tree t_new_type = build_vector_type (m_inner, num_units);
    2018          375 :   return new type (t_new_type);
    2019              : }
    2020              : 
    2021              : /* Construct a playback::lvalue instance (wrapping a tree) for a
    2022              :    field access.  */
    2023              : 
    2024              : playback::lvalue *
    2025          199 : playback::lvalue::
    2026              : access_field (location *loc,
    2027              :               field *field)
    2028              : {
    2029          199 :   tree datum = as_tree ();
    2030          199 :   tree ref = get_context ()->new_field_access (loc, datum, field);
    2031          199 :   if (!ref)
    2032              :     return NULL;
    2033          199 :   return new lvalue (get_context (), ref);
    2034              : }
    2035              : 
    2036              : /* Construct a playback::rvalue instance (wrapping a tree) for a
    2037              :    field access.  */
    2038              : 
    2039              : playback::rvalue *
    2040          139 : playback::rvalue::
    2041              : access_field (location *loc,
    2042              :               field *field)
    2043              : {
    2044          139 :   tree datum = as_tree ();
    2045          139 :   tree ref = get_context ()->new_field_access (loc, datum, field);
    2046          139 :   if (!ref)
    2047              :     return NULL;
    2048          139 :   return new rvalue (get_context (), ref);
    2049              : }
    2050              : 
    2051              : /* Construct a playback::lvalue instance (wrapping a tree) for a
    2052              :    dereferenced field access.  */
    2053              : 
    2054              : playback::lvalue *
    2055         1548 : playback::rvalue::
    2056              : dereference_field (location *loc,
    2057              :                    field *field)
    2058              : {
    2059         1548 :   tree ptr = as_tree ();
    2060         1548 :   tree datum = get_context ()->new_dereference (ptr, loc);
    2061         1548 :   if (!datum)
    2062              :     return NULL;
    2063         1548 :   tree ref = get_context ()->new_field_access (loc, datum, field);
    2064         1548 :   if (!ref)
    2065              :     return NULL;
    2066         1548 :   return new lvalue (get_context (), ref);
    2067              : }
    2068              : 
    2069              : /* Construct a playback::lvalue instance (wrapping a tree) for a
    2070              :    dereference.  */
    2071              : 
    2072              : playback::lvalue *
    2073          684 : playback::rvalue::
    2074              : dereference (location *loc)
    2075              : {
    2076          684 :   tree ptr = as_tree ();
    2077          684 :   tree datum = get_context ()->new_dereference (ptr, loc);
    2078          684 :   return new lvalue (get_context (), datum);
    2079              : }
    2080              : 
    2081              : /* Mark the lvalue saying that we need to be able to take the
    2082              :    address of it; it should not be allocated in a register.
    2083              :    Compare with e.g. c/c-typeck.cc: c_mark_addressable really_atomic_lvalue.
    2084              :    Returns false if a failure occurred (an error will already have been
    2085              :    added to the active context for this case).  */
    2086              : 
    2087              : bool
    2088          498 : playback::lvalue::
    2089              : mark_addressable (location *loc)
    2090              : {
    2091          498 :   tree x = as_tree ();
    2092              : 
    2093          558 :   while (1)
    2094          528 :     switch (TREE_CODE (x))
    2095              :       {
    2096            5 :       case COMPONENT_REF:
    2097            5 :         if (DECL_JIT_BIT_FIELD (TREE_OPERAND (x, 1)))
    2098              :           {
    2099            5 :             gcc_assert (gcc::jit::active_playback_ctxt);
    2100            5 :             gcc::jit::
    2101            5 :               active_playback_ctxt->add_error (loc,
    2102              :                                                "cannot take address of "
    2103              :                                                "bit-field");
    2104            5 :             return false;
    2105              :           }
    2106              :         /* fallthrough */
    2107           30 :       case ADDR_EXPR:
    2108           30 :       case ARRAY_REF:
    2109           30 :       case REALPART_EXPR:
    2110           30 :       case IMAGPART_EXPR:
    2111           30 :         x = TREE_OPERAND (x, 0);
    2112           30 :         break;
    2113              : 
    2114            0 :       case COMPOUND_LITERAL_EXPR:
    2115            0 :       case CONSTRUCTOR:
    2116            0 :         TREE_ADDRESSABLE (x) = 1;
    2117            0 :         return true;
    2118              : 
    2119          433 :       case VAR_DECL:
    2120          433 :       case CONST_DECL:
    2121          433 :       case PARM_DECL:
    2122          433 :       case RESULT_DECL:
    2123              :         /* (we don't have a concept of a "register" declaration) */
    2124              :         /* fallthrough */
    2125          433 :       case FUNCTION_DECL:
    2126          433 :         TREE_ADDRESSABLE (x) = 1;
    2127              :         /* fallthrough */
    2128              :       default:
    2129              :         return true;
    2130              :       }
    2131              : }
    2132              : 
    2133              : /* Construct a playback::rvalue instance (wrapping a tree) for an
    2134              :    address-lookup.  */
    2135              : 
    2136              : playback::rvalue *
    2137          498 : playback::lvalue::
    2138              : get_address (location *loc)
    2139              : {
    2140          498 :   tree t_lvalue = as_tree ();
    2141          498 :   tree t_thistype = TREE_TYPE (t_lvalue);
    2142          498 :   tree t_ptrtype = build_pointer_type (t_thistype);
    2143          498 :   tree ptr = fold_build1 (ADDR_EXPR, t_ptrtype, t_lvalue);
    2144          498 :   if (loc)
    2145            0 :     get_context ()->set_tree_location (ptr, loc);
    2146          498 :   if (mark_addressable (loc))
    2147          493 :     return new rvalue (get_context (), ptr);
    2148              :   else
    2149              :     return NULL;
    2150              : }
    2151              : 
    2152              : /* The wrapper subclasses are GC-managed, but can own non-GC memory.
    2153              :    Provide this finalization hook for calling then they are collected,
    2154              :    which calls the finalizer vfunc.  This allows them to call "release"
    2155              :    on any vec<> within them.  */
    2156              : 
    2157              : static void
    2158        76940 : wrapper_finalizer (void *ptr)
    2159              : {
    2160        76940 :   playback::wrapper *wrapper = reinterpret_cast <playback::wrapper *> (ptr);
    2161        76940 :   wrapper->finalizer ();
    2162        76940 : }
    2163              : 
    2164              : /* gcc::jit::playback::wrapper subclasses are GC-managed:
    2165              :    allocate them using ggc_internal_cleared_alloc.  */
    2166              : 
    2167              : void *
    2168        80714 : playback::wrapper::
    2169              : operator new (size_t sz)
    2170              : {
    2171        80714 :   return ggc_internal_cleared_alloc (sz, wrapper_finalizer, 0, 1);
    2172              : 
    2173              : }
    2174              : 
    2175              : /* Constructor for gcc:jit::playback::function.  */
    2176              : 
    2177        16667 : playback::function::
    2178              : function (context *ctxt,
    2179              :           tree fndecl,
    2180        16667 :           enum gcc_jit_function_kind kind)
    2181        16667 : : m_ctxt(ctxt),
    2182        16667 :   m_inner_fndecl (fndecl),
    2183        16667 :   m_inner_bind_expr (NULL),
    2184        16667 :   m_kind (kind),
    2185        16667 :   m_blocks ()
    2186              : {
    2187        16667 :   if (m_kind != GCC_JIT_FUNCTION_IMPORTED)
    2188              :     {
    2189              :       /* Create a BIND_EXPR, and within it, a statement list.  */
    2190         3346 :       m_stmt_list = alloc_stmt_list ();
    2191         3346 :       m_stmt_iter = tsi_start (m_stmt_list);
    2192         3346 :       m_inner_block = make_node (BLOCK);
    2193         3346 :       m_inner_bind_expr =
    2194         3346 :         build3 (BIND_EXPR, void_type_node, NULL, m_stmt_list, m_inner_block);
    2195              :     }
    2196              :   else
    2197              :     {
    2198        13321 :       m_inner_block = NULL;
    2199        13321 :       m_stmt_list = NULL;
    2200              :     }
    2201        16667 : }
    2202              : 
    2203              : /* Hand-written GC-marking hook for playback functions.  */
    2204              : 
    2205              : void
    2206     36309119 : playback::function::
    2207              : gt_ggc_mx ()
    2208              : {
    2209     36309119 :   gt_ggc_m_9tree_node (m_inner_fndecl);
    2210     36309119 :   gt_ggc_m_9tree_node (m_inner_bind_expr);
    2211     36309119 :   gt_ggc_m_9tree_node (m_stmt_list);
    2212     36309119 :   gt_ggc_m_9tree_node (m_inner_block);
    2213     36309119 : }
    2214              : 
    2215              : /* Don't leak vec's internal buffer (in non-GC heap) when we are
    2216              :    GC-ed.  */
    2217              : 
    2218              : void
    2219        14741 : playback::function::finalizer ()
    2220              : {
    2221        14741 :   m_blocks.release ();
    2222        14741 : }
    2223              : 
    2224              : /* Get the return type of a playback function, in tree form.  */
    2225              : 
    2226              : tree
    2227         3702 : playback::function::
    2228              : get_return_type_as_tree () const
    2229              : {
    2230         3702 :   return TREE_TYPE (TREE_TYPE(m_inner_fndecl));
    2231              : }
    2232              : 
    2233              : /* Construct a new local within this playback::function.  */
    2234              : 
    2235              : playback::lvalue *
    2236         2192 : playback::function::
    2237              : new_local (location *loc,
    2238              :            type *type,
    2239              :            const char *name,
    2240              :            const std::vector<std::pair<gcc_jit_variable_attribute,
    2241              :                                        std::string>> &attributes)
    2242              : {
    2243         2192 :   gcc_assert (type);
    2244         2192 :   tree inner;
    2245         2192 :   if (name)
    2246         2187 :     inner = build_decl (UNKNOWN_LOCATION, VAR_DECL,
    2247              :                            get_identifier (name),
    2248              :                            type->as_tree ());
    2249              :   else
    2250              :   {
    2251            5 :     inner = build_decl (UNKNOWN_LOCATION, VAR_DECL,
    2252              :                         create_tmp_var_name ("JITTMP"),
    2253              :                         type->as_tree ());
    2254            5 :     DECL_ARTIFICIAL (inner) = 1;
    2255            5 :     DECL_IGNORED_P (inner) = 1;
    2256            5 :     DECL_NAMELESS (inner) = 1;
    2257              :   }
    2258         2192 :   DECL_CONTEXT (inner) = this->m_inner_fndecl;
    2259              : 
    2260              :   /* Prepend to BIND_EXPR_VARS: */
    2261         2192 :   DECL_CHAIN (inner) = BIND_EXPR_VARS (m_inner_bind_expr);
    2262         2192 :   BIND_EXPR_VARS (m_inner_bind_expr) = inner;
    2263              : 
    2264         2192 :   set_variable_string_attribute (attributes, inner);
    2265              : 
    2266         2192 :   if (loc)
    2267           21 :     set_tree_location (inner, loc);
    2268         2192 :   return new lvalue (m_ctxt, inner);
    2269              : }
    2270              : 
    2271              : /* Construct a new block within this playback::function.  */
    2272              : 
    2273              : playback::block *
    2274         5833 : playback::function::
    2275              : new_block (const char *name)
    2276              : {
    2277         5833 :   gcc_assert (m_kind != GCC_JIT_FUNCTION_IMPORTED);
    2278              : 
    2279         5833 :   block *result = new playback::block (this, name);
    2280         5833 :   m_blocks.safe_push (result);
    2281         5833 :   return result;
    2282              : }
    2283              : 
    2284              : /* Construct a playback::rvalue instance wrapping an ADDR_EXPR for
    2285              :    this playback::function.  */
    2286              : 
    2287              : playback::rvalue *
    2288           15 : playback::function::get_address (location *loc)
    2289              : {
    2290           15 :   tree t_fndecl = as_fndecl ();
    2291           15 :   tree t_fntype = TREE_TYPE (t_fndecl);
    2292           15 :   tree t_fnptr = build1 (ADDR_EXPR, build_pointer_type (t_fntype), t_fndecl);
    2293           15 :   if (loc)
    2294            0 :     m_ctxt->set_tree_location (t_fnptr, loc);
    2295           15 :   return new rvalue (m_ctxt, t_fnptr);
    2296              : }
    2297              : 
    2298              : /* Build a statement list for the function as a whole out of the
    2299              :    lists of statements for the individual blocks, building labels
    2300              :    for each block.  */
    2301              : 
    2302              : void
    2303        16652 : playback::function::
    2304              : build_stmt_list ()
    2305              : {
    2306        16652 :   int i;
    2307        16652 :   block *b;
    2308              : 
    2309        16652 :   JIT_LOG_SCOPE (m_ctxt->get_logger ());
    2310              : 
    2311        22470 :   FOR_EACH_VEC_ELT (m_blocks, i, b)
    2312              :     {
    2313         5818 :       int j;
    2314         5818 :       tree stmt;
    2315              : 
    2316         5818 :       b->m_label_expr = build1 (LABEL_EXPR,
    2317              :                                 void_type_node,
    2318              :                                 b->as_label_decl ());
    2319         5818 :       tsi_link_after (&m_stmt_iter, b->m_label_expr, TSI_CONTINUE_LINKING);
    2320              : 
    2321        23162 :       FOR_EACH_VEC_ELT (b->m_stmts, j, stmt)
    2322        11526 :         tsi_link_after (&m_stmt_iter, stmt, TSI_CONTINUE_LINKING);
    2323              :     }
    2324        16652 : }
    2325              : 
    2326              : /* Finish compiling the given function, potentially running the
    2327              :    garbage-collector.
    2328              :    The function will have a statement list by now.
    2329              :    Amongst other things, this gimplifies the statement list,
    2330              :    and calls cgraph_node::finalize_function on the function.  */
    2331              : 
    2332              : void
    2333        16652 : playback::function::
    2334              : postprocess ()
    2335              : {
    2336        16652 :   JIT_LOG_SCOPE (m_ctxt->get_logger ());
    2337              : 
    2338        16652 :   if (m_ctxt->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE))
    2339            0 :     debug_tree (m_stmt_list);
    2340              : 
    2341              :   /* Do we need this to force cgraphunit.cc to output the function? */
    2342        16652 :   if (m_kind == GCC_JIT_FUNCTION_EXPORTED)
    2343              :     {
    2344         3191 :       DECL_EXTERNAL (m_inner_fndecl) = 0;
    2345         3191 :       DECL_PRESERVE_P (m_inner_fndecl) = 1;
    2346              :     }
    2347              : 
    2348        16652 :   if (m_kind == GCC_JIT_FUNCTION_INTERNAL
    2349        16652 :       ||m_kind == GCC_JIT_FUNCTION_ALWAYS_INLINE)
    2350              :     {
    2351          140 :       DECL_EXTERNAL (m_inner_fndecl) = 0;
    2352          140 :       TREE_PUBLIC (m_inner_fndecl) = 0;
    2353              :     }
    2354              : 
    2355        16652 :   if (m_kind != GCC_JIT_FUNCTION_IMPORTED)
    2356              :     {
    2357              :       /* Seem to need this in gimple-low.cc: */
    2358         3331 :       gcc_assert (m_inner_block);
    2359         3331 :       DECL_INITIAL (m_inner_fndecl) = m_inner_block;
    2360              : 
    2361              :       /* how to add to function? the following appears to be how to
    2362              :          set the body of a m_inner_fndecl: */
    2363         3331 :       DECL_SAVED_TREE(m_inner_fndecl) = m_inner_bind_expr;
    2364              : 
    2365              :       /* Ensure that locals appear in the debuginfo.  */
    2366         3331 :       BLOCK_VARS (m_inner_block) = BIND_EXPR_VARS (m_inner_bind_expr);
    2367              : 
    2368              :       //debug_tree (m_inner_fndecl);
    2369              : 
    2370              :       /* Convert to gimple: */
    2371              :       //printf("about to gimplify_function_tree\n");
    2372         3331 :       gimplify_function_tree (m_inner_fndecl);
    2373              :       //printf("finished gimplify_function_tree\n");
    2374              : 
    2375         3331 :       current_function_decl = m_inner_fndecl;
    2376         3331 :       if (m_ctxt->get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE))
    2377            0 :         dump_function_to_file (m_inner_fndecl, stderr, TDF_VOPS|TDF_MEMSYMS|TDF_LINENO);
    2378              :       //debug_tree (m_inner_fndecl);
    2379              : 
    2380              :       //printf("about to add to cgraph\n");
    2381              :       /* Add to cgraph: */
    2382         3331 :       cgraph_node::finalize_function (m_inner_fndecl, false);
    2383              :       /* This can trigger a collection, so we need to have all of
    2384              :          the funcs as roots.  */
    2385              : 
    2386         3331 :       current_function_decl = NULL;
    2387              :     }
    2388              :     else
    2389              :       /* Add to cgraph to output aliases: */
    2390        13321 :       rest_of_decl_compilation (m_inner_fndecl, true, 0);
    2391        16652 : }
    2392              : 
    2393              : /* Don't leak vec's internal buffer (in non-GC heap) when we are
    2394              :    GC-ed.  */
    2395              : 
    2396              : void
    2397         5731 : playback::block::finalizer ()
    2398              : {
    2399         5731 :   m_stmts.release ();
    2400         5731 : }
    2401              : 
    2402              : /* Add an eval of the rvalue to the function's statement list.  */
    2403              : 
    2404              : void
    2405          256 : playback::block::
    2406              : add_eval (location *loc,
    2407              :           rvalue *rvalue)
    2408              : {
    2409          256 :   gcc_assert (rvalue);
    2410              : 
    2411          256 :   if (loc)
    2412            9 :     set_tree_location (rvalue->as_tree (), loc);
    2413              : 
    2414          256 :   add_stmt (rvalue->as_tree ());
    2415          256 : }
    2416              : 
    2417              : /* Add an assignment to the function's statement list.  */
    2418              : 
    2419              : void
    2420         4929 : playback::block::
    2421              : add_assignment (location *loc,
    2422              :                 lvalue *lvalue,
    2423              :                 rvalue *rvalue)
    2424              : {
    2425         4929 :   gcc_assert (lvalue);
    2426         4929 :   gcc_assert (rvalue);
    2427              : 
    2428         4929 :   tree t_lvalue = lvalue->as_tree ();
    2429         4929 :   tree t_rvalue = rvalue->as_tree ();
    2430         4929 :   if (TREE_TYPE (t_rvalue) != TREE_TYPE (t_lvalue))
    2431              :     {
    2432          320 :       t_rvalue = build1 (CONVERT_EXPR,
    2433          320 :                          TREE_TYPE (t_lvalue),
    2434              :                          t_rvalue);
    2435          320 :       if (loc)
    2436            0 :         set_tree_location (t_rvalue, loc);
    2437              :     }
    2438              : 
    2439         4929 :   tree stmt =
    2440         4929 :     build2 (MODIFY_EXPR, TREE_TYPE (t_lvalue),
    2441              :             t_lvalue, t_rvalue);
    2442         4929 :   if (loc)
    2443          390 :     set_tree_location (stmt, loc);
    2444         4929 :   add_stmt (stmt);
    2445         4929 : }
    2446              : 
    2447              : /* Add a comment to the function's statement list.
    2448              :    For now this is done by adding a dummy label.  */
    2449              : 
    2450              : void
    2451          458 : playback::block::
    2452              : add_comment (location *loc,
    2453              :              const char *text)
    2454              : {
    2455              :   /* Wrap the text in C-style comment delimiters.  */
    2456          458 :   size_t sz =
    2457              :     (3 /* opening delim */
    2458          458 :      + strlen (text)
    2459              :      + 3 /* closing delim */
    2460              :      + 1 /* terminator */);
    2461          458 :   char *wrapped = (char *)ggc_internal_alloc (sz);
    2462          458 :   snprintf (wrapped, sz, "/* %s */", text);
    2463              : 
    2464              :   /* For now we simply implement this by adding a dummy label with a name
    2465              :      containing the given text.  */
    2466          458 :   tree identifier = get_identifier (wrapped);
    2467          458 :   tree label_decl = build_decl (UNKNOWN_LOCATION, LABEL_DECL,
    2468              :                                 identifier, void_type_node);
    2469          458 :   DECL_CONTEXT (label_decl) = m_func->as_fndecl ();
    2470              : 
    2471          458 :   tree label_expr = build1 (LABEL_EXPR, void_type_node, label_decl);
    2472          458 :   if (loc)
    2473          202 :     set_tree_location (label_expr, loc);
    2474          458 :   add_stmt (label_expr);
    2475          458 : }
    2476              : 
    2477              : /* Add a conditional jump statement to the function's statement list.  */
    2478              : 
    2479              : void
    2480          879 : playback::block::
    2481              : add_conditional (location *loc,
    2482              :                  rvalue *boolval,
    2483              :                  block *on_true,
    2484              :                  block *on_false)
    2485              : {
    2486          879 :   gcc_assert (boolval);
    2487          879 :   gcc_assert (on_true);
    2488          879 :   gcc_assert (on_false);
    2489              : 
    2490              :   /* COND_EXPR wants statement lists for the true/false operands, but we
    2491              :      want labels.
    2492              :      Shim it by creating jumps to the labels */
    2493          879 :   tree true_jump = build1 (GOTO_EXPR, void_type_node,
    2494              :                            on_true->as_label_decl ());
    2495          879 :   if (loc)
    2496           37 :     set_tree_location (true_jump, loc);
    2497              : 
    2498          879 :   tree false_jump = build1 (GOTO_EXPR, void_type_node,
    2499              :                             on_false->as_label_decl ());
    2500          879 :   if (loc)
    2501           37 :     set_tree_location (false_jump, loc);
    2502              : 
    2503          879 :   tree stmt =
    2504          879 :     build3 (COND_EXPR, void_type_node, boolval->as_tree (),
    2505              :             true_jump, false_jump);
    2506          879 :   if (loc)
    2507           37 :     set_tree_location (stmt, loc);
    2508          879 :   add_stmt (stmt);
    2509          879 : }
    2510              : 
    2511              : /* Add an unconditional jump statement to the function's statement list.  */
    2512              : 
    2513              : void
    2514         1222 : playback::block::
    2515              : add_jump (location *loc,
    2516              :           block *target)
    2517              : {
    2518         1222 :   gcc_assert (target);
    2519              : 
    2520              :   // see c_finish_loop
    2521              :   //tree top = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
    2522              :   //add_stmt (top);
    2523              : 
    2524              :   //tree stmt = build_and_jump (&LABEL_EXPR_LABEL (target->label_));
    2525         1222 :   TREE_USED (target->as_label_decl ()) = 1;
    2526         1222 :   tree stmt = build1 (GOTO_EXPR, void_type_node, target->as_label_decl ());
    2527         1222 :   if (loc)
    2528           48 :     set_tree_location (stmt, loc);
    2529         1222 :   add_stmt (stmt);
    2530              : 
    2531              :   /*
    2532              :   from c-typeck.cc:
    2533              : tree
    2534              : c_finish_goto_label (location_t loc, tree label)
    2535              : {
    2536              :   tree decl = lookup_label_for_goto (loc, label);
    2537              :   if (!decl)
    2538              :     return NULL_TREE;
    2539              :   TREE_USED (decl) = 1;
    2540              :   {
    2541              :     tree t = build1 (GOTO_EXPR, void_type_node, decl);
    2542              :     SET_EXPR_LOCATION (t, loc);
    2543              :     return add_stmt (t);
    2544              :   }
    2545              : }
    2546              :   */
    2547              : 
    2548         1222 : }
    2549              : 
    2550              : /* Add a return statement to the function's statement list.  */
    2551              : 
    2552              : void
    2553         3702 : playback::block::
    2554              : add_return (location *loc,
    2555              :             rvalue *rvalue)
    2556              : {
    2557         3702 :   tree modify_retval = NULL;
    2558         3702 :   tree return_type = m_func->get_return_type_as_tree ();
    2559         3702 :   if (rvalue)
    2560              :     {
    2561         3173 :       tree t_lvalue = DECL_RESULT (m_func->as_fndecl ());
    2562         3173 :       tree t_rvalue = rvalue->as_tree ();
    2563         3173 :       if (TREE_TYPE (t_rvalue) != TREE_TYPE (t_lvalue))
    2564          110 :         t_rvalue = build1 (CONVERT_EXPR,
    2565          110 :                            TREE_TYPE (t_lvalue),
    2566              :                            t_rvalue);
    2567         3173 :       modify_retval = build2 (MODIFY_EXPR, return_type,
    2568              :                               t_lvalue, t_rvalue);
    2569         3173 :       if (loc)
    2570           68 :         set_tree_location (modify_retval, loc);
    2571              :     }
    2572         3702 :   tree return_stmt = build1 (RETURN_EXPR, return_type,
    2573              :                              modify_retval);
    2574         3702 :   if (loc)
    2575           80 :     set_tree_location (return_stmt, loc);
    2576              : 
    2577         3702 :   add_stmt (return_stmt);
    2578         3702 : }
    2579              : 
    2580              : /* Helper function for playback::block::add_switch.
    2581              :    Construct a case label for the given range, followed by a goto stmt
    2582              :    to the given block, appending them to stmt list *ptr_t_switch_body.  */
    2583              : 
    2584              : static void
    2585          100 : add_case (tree *ptr_t_switch_body,
    2586              :           tree t_low_value,
    2587              :           tree t_high_value,
    2588              :           playback::block *dest_block)
    2589              : {
    2590          100 :   tree t_label = create_artificial_label (UNKNOWN_LOCATION);
    2591          100 :   DECL_CONTEXT (t_label) = dest_block->get_function ()->as_fndecl ();
    2592              : 
    2593          100 :   tree t_case_label =
    2594          100 :     build_case_label (t_low_value, t_high_value, t_label);
    2595          100 :   append_to_statement_list (t_case_label, ptr_t_switch_body);
    2596              : 
    2597          100 :   tree t_goto_stmt =
    2598          100 :     build1 (GOTO_EXPR, void_type_node, dest_block->as_label_decl ());
    2599          100 :   append_to_statement_list (t_goto_stmt, ptr_t_switch_body);
    2600          100 : }
    2601              : 
    2602              : /* Add a switch statement to the function's statement list.
    2603              : 
    2604              :    We create a switch body, and populate it with case labels, each
    2605              :    followed by a goto to the desired block.  */
    2606              : 
    2607              : void
    2608           20 : playback::block::
    2609              : add_switch (location *loc,
    2610              :             rvalue *expr,
    2611              :             block *default_block,
    2612              :             const auto_vec <case_> *cases)
    2613              : {
    2614              :   /* Compare with:
    2615              :      - c/c-typeck.cc: c_start_case
    2616              :      - c-family/c-common.cc:c_add_case_label
    2617              :      - java/expr.cc:expand_java_switch and expand_java_add_case
    2618              :      We've already rejected overlaps and duplicates in
    2619              :      libgccjit.cc:case_range_validator::validate.  */
    2620              : 
    2621           20 :   tree t_expr = expr->as_tree ();
    2622           20 :   tree t_type = TREE_TYPE (t_expr);
    2623              : 
    2624           20 :   tree t_switch_body = alloc_stmt_list ();
    2625              : 
    2626           20 :   int i;
    2627           20 :   case_ *c;
    2628          100 :   FOR_EACH_VEC_ELT (*cases, i, c)
    2629              :     {
    2630           80 :       tree t_low_value = c->m_min_value->as_tree ();
    2631           80 :       tree t_high_value = c->m_max_value->as_tree ();
    2632           80 :       add_case (&t_switch_body, t_low_value, t_high_value, c->m_dest_block);
    2633              :     }
    2634              :   /* Default label. */
    2635           20 :   add_case (&t_switch_body, NULL_TREE, NULL_TREE, default_block);
    2636              : 
    2637           20 :   tree switch_stmt = build2 (SWITCH_EXPR, t_type, t_expr, t_switch_body);
    2638           20 :   if (loc)
    2639            0 :     set_tree_location (switch_stmt, loc);
    2640           20 :   add_stmt (switch_stmt);
    2641           20 : }
    2642              : 
    2643              : /* Convert OPERANDS to a tree-based chain suitable for creating an
    2644              :    extended asm stmt.
    2645              :    Compare with c_parser_asm_operands.  */
    2646              : 
    2647              : static tree
    2648          140 : build_operand_chain (const auto_vec <playback::asm_operand> *operands)
    2649              : {
    2650          140 :   tree result = NULL_TREE;
    2651          140 :   unsigned i;
    2652          140 :   playback::asm_operand *asm_op;
    2653          240 :   FOR_EACH_VEC_ELT (*operands, i, asm_op)
    2654              :     {
    2655          100 :       tree name = build_string (asm_op->m_asm_symbolic_name);
    2656          100 :       tree str = build_string (asm_op->m_constraint);
    2657          100 :       tree value = asm_op->m_expr;
    2658          100 :       result = chainon (result,
    2659              :                         build_tree_list (build_tree_list (name, str),
    2660              :                                          value));
    2661              :     }
    2662          140 :   return result;
    2663              : }
    2664              : 
    2665              : /* Convert CLOBBERS to a tree-based list suitable for creating an
    2666              :    extended asm stmt.
    2667              :    Compare with c_parser_asm_clobbers.  */
    2668              : 
    2669              : static tree
    2670           70 : build_clobbers (const auto_vec <const char *> *clobbers)
    2671              : {
    2672           70 :   tree list = NULL_TREE;
    2673           70 :   unsigned i;
    2674           70 :   const char *clobber;
    2675          120 :   FOR_EACH_VEC_ELT (*clobbers, i, clobber)
    2676              :     {
    2677           50 :       tree str = build_string (clobber);
    2678           50 :       list = tree_cons (NULL_TREE, str, list);
    2679              :     }
    2680           70 :   return list;
    2681              : }
    2682              : 
    2683              : /* Convert BLOCKS to a tree-based list suitable for creating an
    2684              :    extended asm stmt.
    2685              :    Compare with c_parser_asm_goto_operands.  */
    2686              : 
    2687              : static tree
    2688           70 : build_goto_operands (const auto_vec <playback::block *> *blocks)
    2689              : {
    2690           70 :   tree list = NULL_TREE;
    2691           70 :   unsigned i;
    2692           70 :   playback::block *b;
    2693           90 :   FOR_EACH_VEC_ELT (*blocks, i, b)
    2694              :     {
    2695           20 :       tree label = b->as_label_decl ();
    2696           20 :       tree name = build_string (IDENTIFIER_POINTER (DECL_NAME (label)));
    2697           20 :       TREE_USED (label) = 1;
    2698           20 :       list = tree_cons (name, label, list);
    2699              :     }
    2700           70 :   return nreverse (list);
    2701              : }
    2702              : 
    2703              : /* Add an extended asm statement to this block.
    2704              : 
    2705              :    Compare with c_parser_asm_statement (in c/c-parser.cc)
    2706              :    and build_asm_expr (in c/c-typeck.cc).  */
    2707              : 
    2708              : void
    2709           70 : playback::block::add_extended_asm (location *loc,
    2710              :                                    const char *asm_template,
    2711              :                                    bool is_volatile,
    2712              :                                    bool is_inline,
    2713              :                                    const auto_vec <asm_operand> *outputs,
    2714              :                                    const auto_vec <asm_operand> *inputs,
    2715              :                                    const auto_vec <const char *> *clobbers,
    2716              :                                    const auto_vec <block *> *goto_blocks)
    2717              : {
    2718           70 :   tree t_string = build_string (asm_template);
    2719           70 :   tree t_outputs = build_operand_chain (outputs);
    2720           70 :   tree t_inputs = build_operand_chain (inputs);
    2721           70 :   tree t_clobbers = build_clobbers (clobbers);
    2722           70 :   tree t_labels = build_goto_operands (goto_blocks);
    2723           70 :   t_string
    2724           70 :     = resolve_asm_operand_names (t_string, t_outputs, t_inputs, t_labels);
    2725           70 :   tree asm_stmt
    2726           70 :     = build5 (ASM_EXPR, void_type_node,
    2727              :               t_string, t_outputs, t_inputs, t_clobbers, t_labels);
    2728              : 
    2729              :   /* asm statements without outputs, including simple ones, are treated
    2730              :      as volatile.  */
    2731          110 :   ASM_VOLATILE_P (asm_stmt) = (outputs->length () == 0);
    2732           70 :   ASM_BASIC_P (asm_stmt) = 0;
    2733           70 :   ASM_INLINE_P (asm_stmt) = is_inline;
    2734           70 :   if (is_volatile)
    2735           20 :     ASM_VOLATILE_P (asm_stmt) = 1;
    2736           70 :   if (loc)
    2737            0 :     set_tree_location (asm_stmt, loc);
    2738           70 :   add_stmt (asm_stmt);
    2739           70 : }
    2740              : 
    2741              : /* Constructor for gcc::jit::playback::block.  */
    2742              : 
    2743         5833 : playback::block::
    2744              : block (function *func,
    2745         5833 :        const char *name)
    2746         5833 : : m_func (func),
    2747         5833 :   m_stmts ()
    2748              : {
    2749         5833 :   tree identifier;
    2750              : 
    2751         5833 :   gcc_assert (func);
    2752              :   // name can be NULL
    2753         5833 :   if (name)
    2754         4876 :     identifier = get_identifier (name);
    2755              :   else
    2756              :     identifier = NULL;
    2757         5833 :   m_label_decl = build_decl (UNKNOWN_LOCATION, LABEL_DECL,
    2758              :                             identifier, void_type_node);
    2759         5833 :   DECL_CONTEXT (m_label_decl) = func->as_fndecl ();
    2760         5833 :   m_label_expr = NULL;
    2761         5833 : }
    2762              : 
    2763              : // This is basically std::lock_guard but it can call the private lock/unlock
    2764              : // members of playback::context.
    2765              : struct playback::context::scoped_lock
    2766              : {
    2767         1331 :   scoped_lock (context &ctx) : m_ctx (&ctx) { m_ctx->lock (); }
    2768         2662 :   ~scoped_lock () { m_ctx->unlock (); }
    2769              : 
    2770              :   context *m_ctx;
    2771              : 
    2772              :   // Not movable or copyable.
    2773              :   scoped_lock (scoped_lock &&) = delete;
    2774              :   scoped_lock &operator= (scoped_lock &&) = delete;
    2775              : };
    2776              : 
    2777              : /* Compile a playback::context:
    2778              : 
    2779              :    - Use the context's options to cconstruct command-line options, and
    2780              :      call into the rest of GCC (toplev::main).
    2781              :    - Assuming it succeeds, we have a .s file.
    2782              :    - We then run the "postprocess" vfunc:
    2783              : 
    2784              :      (A) In-memory compile ("gcc_jit_context_compile")
    2785              : 
    2786              :        For an in-memory compile we have the playback::compile_to_memory
    2787              :        subclass; "postprocess" will convert the .s file to a .so DSO,
    2788              :        and load it in memory (via dlopen), wrapping the result up as
    2789              :        a jit::result and returning it.
    2790              : 
    2791              :      (B) Compile to file ("gcc_jit_context_compile_to_file")
    2792              : 
    2793              :        When compiling to a file, we have the playback::compile_to_file
    2794              :        subclass; "postprocess" will either copy the .s file to the
    2795              :        destination (for GCC_JIT_OUTPUT_KIND_ASSEMBLER), or invoke
    2796              :        the driver to convert it as necessary, copying the result.  */
    2797              : 
    2798              : void
    2799         1331 : playback::context::
    2800              : compile ()
    2801              : {
    2802         1331 :   JIT_LOG_SCOPE (get_logger ());
    2803              : 
    2804         1331 :   const char *ctxt_progname;
    2805              : 
    2806         1331 :   int keep_intermediates =
    2807         1331 :     get_bool_option (GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES);
    2808              : 
    2809         1331 :   m_tempdir = new tempdir (get_logger (), keep_intermediates);
    2810         1331 :   if (!m_tempdir->create ())
    2811              :     return;
    2812              : 
    2813              :   /* Call into the rest of gcc.
    2814              :      For now, we have to assemble command-line options to pass into
    2815              :      toplev::main, so that they can be parsed. */
    2816              : 
    2817              :   /* Pass in user-provided program name as argv0, if any, so that it
    2818              :      makes it into GCC's "progname" global, used in various diagnostics. */
    2819         1331 :   ctxt_progname = get_str_option (GCC_JIT_STR_OPTION_PROGNAME);
    2820              : 
    2821         1331 :   if (!ctxt_progname)
    2822          119 :     ctxt_progname = "libgccjit.so";
    2823              : 
    2824         1331 :   auto_vec <recording::requested_dump> requested_dumps;
    2825         1331 :   m_recording_ctxt->get_all_requested_dumps (&requested_dumps);
    2826              : 
    2827              :   /* Acquire the JIT mutex and set "this" as the active playback ctxt.  */
    2828         1331 :   scoped_lock lock(*this);
    2829              : 
    2830         1331 :   auto_string_vec fake_args;
    2831         1331 :   make_fake_args (&fake_args, ctxt_progname, &requested_dumps);
    2832         1331 :   if (errors_occurred ())
    2833              :     return;
    2834              : 
    2835              :   /* This runs the compiler.  */
    2836         1331 :   toplev toplev (get_timer (), /* external_timer */
    2837         1331 :                  false); /* init_signals */
    2838         1331 :   enter_scope ("toplev::main");
    2839         1331 :   if (get_logger ())
    2840         7084 :     for (unsigned i = 0; i < fake_args.length (); i++)
    2841         6477 :       get_logger ()->log ("argv[%i]: %s", i, fake_args[i]);
    2842              : 
    2843              :   /* Add a trailing null to argvec; this is not counted in argc.  */
    2844         1331 :   fake_args.safe_push (nullptr);
    2845         2662 :   toplev.main (/* The trailing null is not counted in argv.  */
    2846         1331 :                fake_args.length () - 1,
    2847              :                const_cast <char **> (fake_args.address ()));
    2848         1331 :   exit_scope ("toplev::main");
    2849              : 
    2850              :   /* Extracting dumps makes use of the gcc::dump_manager, hence we
    2851              :      need to do it between toplev::main (which creates the dump manager)
    2852              :      and toplev::finalize (which deletes it).  */
    2853         1331 :   extract_any_requested_dumps (&requested_dumps);
    2854              : 
    2855              :   /* Clean up the compiler.  */
    2856         1331 :   enter_scope ("toplev::finalize");
    2857         1331 :   toplev.finalize ();
    2858         1331 :   exit_scope ("toplev::finalize");
    2859              : 
    2860              :   /* Ideally we would release the jit mutex here, but we can't yet since
    2861              :      followup activities use timevars, which are global state.  */
    2862              : 
    2863         1331 :   if (errors_occurred ())
    2864           55 :     return;
    2865              : 
    2866         1276 :   if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE))
    2867            0 :     dump_generated_code ();
    2868              : 
    2869              :   /* We now have a .s file.
    2870              : 
    2871              :      Run any postprocessing steps.  This will either convert the .s file to
    2872              :      a .so DSO, and load it in memory (playback::compile_to_memory), or
    2873              :      convert the .s file to the requested output format, and copy it to a
    2874              :      given file (playback::compile_to_file).  */
    2875         1276 :   postprocess (ctxt_progname);
    2876         1331 : }
    2877              : 
    2878              : /* Implementation of class gcc::jit::playback::compile_to_memory,
    2879              :    a subclass of gcc::jit::playback::context.  */
    2880              : 
    2881              : /*  playback::compile_to_memory's trivial constructor. */
    2882              : 
    2883         1173 : playback::compile_to_memory::compile_to_memory (recording::context *ctxt) :
    2884              :   playback::context (ctxt),
    2885         1173 :   m_result (NULL)
    2886              : {
    2887         1173 :   JIT_LOG_SCOPE (get_logger ());
    2888         1173 : }
    2889              : 
    2890              : /*  Implementation of the playback::context::process vfunc for compiling
    2891              :     to memory.
    2892              : 
    2893              :     Convert the .s file to a .so DSO, and load it in memory (via dlopen),
    2894              :     wrapping the result up as a jit::result and returning it.  */
    2895              : 
    2896              : void
    2897         1118 : playback::compile_to_memory::postprocess (const char *ctxt_progname)
    2898              : {
    2899         1118 :   JIT_LOG_SCOPE (get_logger ());
    2900         1118 :   convert_to_dso (ctxt_progname);
    2901         1118 :   if (errors_occurred ())
    2902            5 :     return;
    2903         1113 :   m_result = dlopen_built_dso ();
    2904         1118 : }
    2905              : 
    2906              : /* Implementation of class gcc::jit::playback::compile_to_file,
    2907              :    a subclass of gcc::jit::playback::context.  */
    2908              : 
    2909              : /*  playback::compile_to_file's trivial constructor. */
    2910              : 
    2911          126 : playback::compile_to_file::compile_to_file (recording::context *ctxt,
    2912              :                                             enum gcc_jit_output_kind output_kind,
    2913          126 :                                             const char *output_path) :
    2914              :   playback::context (ctxt),
    2915          126 :   m_output_kind (output_kind),
    2916          126 :   m_output_path (output_path)
    2917              : {
    2918          126 :   JIT_LOG_SCOPE (get_logger ());
    2919          126 : }
    2920              : 
    2921              : /*  Implementation of the playback::context::process vfunc for compiling
    2922              :     to a file.
    2923              : 
    2924              :     Either copy the .s file to the given destination (for
    2925              :     GCC_JIT_OUTPUT_KIND_ASSEMBLER), or invoke the driver to convert it
    2926              :     as necessary, copying the result.  */
    2927              : 
    2928              : void
    2929          126 : playback::compile_to_file::postprocess (const char *ctxt_progname)
    2930              : {
    2931          126 :   JIT_LOG_SCOPE (get_logger ());
    2932              : 
    2933              :   /* The driver takes different actions based on the filename, so
    2934              :      we provide a filename with an appropriate suffix for the
    2935              :      output kind, and then copy it up to the user-provided path,
    2936              :      rather than directly compiling it to the requested output path.  */
    2937              : 
    2938          126 :   switch (m_output_kind)
    2939              :     {
    2940            0 :     default:
    2941            0 :       gcc_unreachable ();
    2942              : 
    2943          105 :     case GCC_JIT_OUTPUT_KIND_ASSEMBLER:
    2944          105 :       copy_file (get_tempdir ()->get_path_s_file (),
    2945              :                  m_output_path);
    2946              :       /* The .s file is automatically unlinked by tempdir::~tempdir.  */
    2947          105 :       break;
    2948              : 
    2949            5 :     case GCC_JIT_OUTPUT_KIND_OBJECT_FILE:
    2950            5 :       {
    2951            5 :         char *tmp_o_path = ::concat (get_tempdir ()->get_path (),
    2952              :                                      "/fake.o",
    2953              :                                      NULL);
    2954            5 :         invoke_driver (ctxt_progname,
    2955              :                        get_tempdir ()->get_path_s_file (),
    2956              :                        tmp_o_path,
    2957              :                        TV_ASSEMBLE,
    2958              :                        false, /* bool shared, */
    2959              :                        false);/* bool run_linker */
    2960            5 :         if (!errors_occurred ())
    2961              :           {
    2962            5 :             copy_file (tmp_o_path,
    2963              :                        m_output_path);
    2964            5 :             get_tempdir ()->add_temp_file (tmp_o_path);
    2965              :           }
    2966              :         else
    2967            0 :           free (tmp_o_path);
    2968              :       }
    2969              :       break;
    2970              : 
    2971            5 :     case GCC_JIT_OUTPUT_KIND_DYNAMIC_LIBRARY:
    2972            5 :       invoke_driver (ctxt_progname,
    2973              :                      get_tempdir ()->get_path_s_file (),
    2974              :                      get_tempdir ()->get_path_so_file (),
    2975              :                      TV_ASSEMBLE,
    2976              :                      true, /* bool shared, */
    2977              :                      true);/* bool run_linker */
    2978            5 :       if (!errors_occurred ())
    2979            5 :         copy_file (get_tempdir ()->get_path_so_file (),
    2980              :                    m_output_path);
    2981              :       /* The .so file is automatically unlinked by tempdir::~tempdir.  */
    2982              :       break;
    2983              : 
    2984           11 :     case GCC_JIT_OUTPUT_KIND_EXECUTABLE:
    2985           11 :       {
    2986           11 :         char *tmp_exe_path = ::concat (get_tempdir ()->get_path (),
    2987              :                                      "/fake.exe",
    2988              :                                      NULL);
    2989           11 :         invoke_driver (ctxt_progname,
    2990              :                        get_tempdir ()->get_path_s_file (),
    2991              :                        tmp_exe_path,
    2992              :                        TV_ASSEMBLE,
    2993              :                        false, /* bool shared, */
    2994              :                        true);/* bool run_linker */
    2995           11 :         if (!errors_occurred ())
    2996              :           {
    2997           11 :             copy_file (tmp_exe_path,
    2998              :                        m_output_path);
    2999           11 :             get_tempdir ()->add_temp_file (tmp_exe_path);
    3000              :           }
    3001              :         else
    3002            0 :           free (tmp_exe_path);
    3003              :       }
    3004              :       break;
    3005              : 
    3006              :     }
    3007              : 
    3008          126 : }
    3009              : 
    3010              : /* Copy SRC_PATH to DST_PATH, preserving permission bits (in particular,
    3011              :    the "executable" bits).
    3012              : 
    3013              :    Any errors that occur are reported on the context and hence count as
    3014              :    a failure of the compile.
    3015              : 
    3016              :    We can't in general hardlink or use "rename" from the tempdir since
    3017              :    it might be on a different filesystem to the destination.  For example,
    3018              :    I get EXDEV: "Invalid cross-device link".  */
    3019              : 
    3020              : void
    3021          126 : playback::compile_to_file::copy_file (const char *src_path,
    3022              :                                       const char *dst_path)
    3023              : {
    3024          126 :   JIT_LOG_SCOPE (get_logger ());
    3025          126 :   if (get_logger ())
    3026              :     {
    3027          125 :       get_logger ()->log ("src_path: %s", src_path);
    3028          125 :       get_logger ()->log ("dst_path: %s", dst_path);
    3029              :     }
    3030              : 
    3031          126 :   FILE *f_in = NULL;
    3032          126 :   FILE *f_out = NULL;
    3033          126 :   size_t total_sz_in = 0;
    3034          126 :   size_t total_sz_out = 0;
    3035          126 :   char buf[4096];
    3036          126 :   size_t sz_in;
    3037          126 :   struct stat stat_buf;
    3038              : 
    3039          126 :   f_in = fopen (src_path, "rb");
    3040          126 :   if (!f_in)
    3041              :     {
    3042            0 :       add_error (NULL,
    3043              :                  "unable to open %s for reading: %s",
    3044              :                  src_path,
    3045            0 :                  xstrerror (errno));
    3046            0 :       return;
    3047              :     }
    3048              : 
    3049              :   /* Use stat on the filedescriptor to get the mode,
    3050              :      so that we can copy it over (in particular, the
    3051              :      "executable" bits).  */
    3052          126 :   if (fstat (fileno (f_in), &stat_buf) == -1)
    3053              :     {
    3054            0 :       add_error (NULL,
    3055              :                  "unable to fstat %s: %s",
    3056              :                  src_path,
    3057            0 :                  xstrerror (errno));
    3058            0 :       fclose (f_in);
    3059            0 :       return;
    3060              :     }
    3061              : 
    3062          126 :   f_out = fopen (dst_path, "wb");
    3063          126 :   if (!f_out)
    3064              :     {
    3065            0 :       add_error (NULL,
    3066              :                  "unable to open %s for writing: %s",
    3067              :                  dst_path,
    3068            0 :                  xstrerror (errno));
    3069            0 :       fclose (f_in);
    3070            0 :       return;
    3071              :     }
    3072              : 
    3073          327 :   while ( (sz_in = fread (buf, 1, sizeof (buf), f_in)) )
    3074              :     {
    3075          201 :       total_sz_in += sz_in;
    3076          201 :       size_t sz_out_remaining = sz_in;
    3077          201 :       size_t sz_out_so_far = 0;
    3078          402 :       while (sz_out_remaining)
    3079              :         {
    3080          201 :           size_t sz_out = fwrite (buf + sz_out_so_far,
    3081              :                                   1,
    3082              :                                   sz_out_remaining,
    3083              :                                   f_out);
    3084          201 :           gcc_assert (sz_out <= sz_out_remaining);
    3085          201 :           if (!sz_out)
    3086              :             {
    3087            0 :               add_error (NULL,
    3088              :                          "error writing to %s: %s",
    3089              :                          dst_path,
    3090            0 :                          xstrerror (errno));
    3091            0 :               fclose (f_in);
    3092            0 :               fclose (f_out);
    3093            0 :               return;
    3094              :             }
    3095          201 :           total_sz_out += sz_out;
    3096          201 :           sz_out_so_far += sz_out;
    3097          201 :           sz_out_remaining -= sz_out;
    3098              :         }
    3099          201 :       gcc_assert (sz_out_so_far == sz_in);
    3100              :     }
    3101              : 
    3102          126 :   if (!feof (f_in))
    3103            0 :     add_error (NULL,
    3104              :                "error reading from %s: %s",
    3105              :                src_path,
    3106            0 :                xstrerror (errno));
    3107              : 
    3108          126 :   fclose (f_in);
    3109              : 
    3110          126 :   gcc_assert (total_sz_in == total_sz_out);
    3111          126 :   if (get_logger ())
    3112          125 :     get_logger ()->log ("total bytes copied: %zu", total_sz_out);
    3113              : 
    3114              :   /* fchmod does not exist in Windows. */
    3115              : #ifndef _WIN32
    3116              :   /* Set the permissions of the copy to those of the original file,
    3117              :      in particular the "executable" bits.  */
    3118          126 :   if (fchmod (fileno (f_out), stat_buf.st_mode) == -1)
    3119            0 :     add_error (NULL,
    3120              :                "error setting mode of %s: %s",
    3121              :                dst_path,
    3122            0 :                xstrerror (errno));
    3123              : #endif
    3124              : 
    3125          126 :   fclose (f_out);
    3126          126 : }
    3127              : 
    3128              : /* Helper functions for gcc::jit::playback::context::compile.  */
    3129              : 
    3130              : /* This mutex guards gcc::jit::recording::context::compile, so that only
    3131              :    one thread can be accessing the bulk of GCC's state at once.  */
    3132              : 
    3133              : static std::mutex jit_mutex;
    3134              : 
    3135              : /* Acquire jit_mutex and set "this" as the active playback ctxt.  */
    3136              : 
    3137              : void
    3138         1331 : playback::context::lock ()
    3139              : {
    3140         1331 :   auto_timevar tv (get_timer (), TV_JIT_ACQUIRING_MUTEX);
    3141              : 
    3142              :   /* Acquire the big GCC mutex. */
    3143         1331 :   JIT_LOG_SCOPE (get_logger ());
    3144         1331 :   jit_mutex.lock ();
    3145         1331 :   gcc_assert (active_playback_ctxt == NULL);
    3146         1331 :   active_playback_ctxt = this;
    3147         1331 : }
    3148              : 
    3149              : /* Release jit_mutex and clear the active playback ctxt.  */
    3150              : 
    3151              : void
    3152         1331 : playback::context::unlock ()
    3153              : {
    3154              :   /* Release the big GCC mutex. */
    3155         1331 :   JIT_LOG_SCOPE (get_logger ());
    3156         1331 :   gcc_assert (active_playback_ctxt == this);
    3157         1331 :   active_playback_ctxt = NULL;
    3158         1331 :   jit_mutex.unlock ();
    3159         1331 : }
    3160              : 
    3161              : /* Callback used by gcc::jit::playback::context::make_fake_args when
    3162              :    invoking driver_get_configure_time_options.
    3163              :    Populate a vec <char * > with the configure-time options.  */
    3164              : 
    3165              : static void
    3166          262 : append_arg_from_driver (const char *option, void *user_data)
    3167              : {
    3168          262 :   gcc_assert (option);
    3169          262 :   gcc_assert (user_data);
    3170          262 :   vec <char *> *argvec = static_cast <vec <char *> *> (user_data);
    3171          262 :   argvec->safe_push (concat ("-", option, NULL));
    3172          262 : }
    3173              : 
    3174              : /* Build a fake argv for toplev::main from the options set
    3175              :    by the user on the context .  */
    3176              : 
    3177              : void
    3178         1331 : playback::context::
    3179              : make_fake_args (vec <char *> *argvec,
    3180              :                 const char *ctxt_progname,
    3181              :                 vec <recording::requested_dump> *requested_dumps)
    3182              : {
    3183         1331 :   JIT_LOG_SCOPE (get_logger ());
    3184              : 
    3185              : #define ADD_ARG(arg) argvec->safe_push (xstrdup (arg))
    3186              : #define ADD_ARG_TAKE_OWNERSHIP(arg) argvec->safe_push (arg)
    3187              : 
    3188         1331 :   ADD_ARG (ctxt_progname);
    3189         1331 :   ADD_ARG (get_path_c_file ());
    3190         1331 :   ADD_ARG ("-fPIC");
    3191              : 
    3192              :   /* Handle int options: */
    3193         1331 :   switch (get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL))
    3194              :     {
    3195            0 :     default:
    3196            0 :       add_error (NULL,
    3197              :                  "unrecognized optimization level: %i",
    3198              :                  get_int_option (GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL));
    3199            0 :       return;
    3200              : 
    3201          179 :     case 0:
    3202          179 :       ADD_ARG ("-O0");
    3203          179 :       break;
    3204              : 
    3205          105 :     case 1:
    3206          105 :       ADD_ARG ("-O1");
    3207          105 :       break;
    3208              : 
    3209          115 :     case 2:
    3210          115 :       ADD_ARG ("-O2");
    3211          115 :       break;
    3212              : 
    3213          932 :     case 3:
    3214          932 :       ADD_ARG ("-O3");
    3215          932 :       break;
    3216              :     }
    3217              :   /* What about -Os? */
    3218              : 
    3219              :   /* Handle bool options: */
    3220         1331 :   if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO))
    3221          827 :     ADD_ARG ("-g");
    3222              : 
    3223              :   /* Suppress timing (and other) info.  */
    3224         1331 :   if (!get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_SUMMARY))
    3225              :     {
    3226         1331 :       ADD_ARG ("-quiet");
    3227         1331 :       quiet_flag = 1;
    3228              :     }
    3229              : 
    3230              :   /* Aggressively garbage-collect, to shake out bugs: */
    3231         1331 :   if (get_bool_option (GCC_JIT_BOOL_OPTION_SELFCHECK_GC))
    3232              :     {
    3233          817 :       ADD_ARG ("--param=ggc-min-expand=0");
    3234          817 :       ADD_ARG ("--param=ggc-min-heapsize=0");
    3235              :     }
    3236              : 
    3237         1331 :   if (get_bool_option (GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING))
    3238              :     {
    3239            0 :       ADD_ARG ("-fdump-tree-all");
    3240            0 :       ADD_ARG ("-fdump-rtl-all");
    3241            0 :       ADD_ARG ("-fdump-ipa-all");
    3242              :     }
    3243              : 
    3244              :   /* Add "-fdump-" options for any calls to
    3245              :      gcc_jit_context_enable_dump.  */
    3246              :   {
    3247              :     int i;
    3248              :     recording::requested_dump *d;
    3249         1381 :     FOR_EACH_VEC_ELT (*requested_dumps, i, d)
    3250              :       {
    3251           50 :         char *arg = concat ("-fdump-", d->m_dumpname, NULL);
    3252           50 :         ADD_ARG_TAKE_OWNERSHIP (arg);
    3253              :       }
    3254              :   }
    3255              : 
    3256              :   /* PR jit/64810: Add any target-specific default options
    3257              :      from OPTION_DEFAULT_SPECS, normally provided by the driver
    3258              :      in the non-jit case.
    3259              : 
    3260              :      The target-specific code can define OPTION_DEFAULT_SPECS:
    3261              :      default command options in the form of spec macros for the
    3262              :      driver to expand ().
    3263              : 
    3264              :      For cc1 etc, the driver processes OPTION_DEFAULT_SPECS and,
    3265              :      if not overriden, injects the defaults as extra arguments to
    3266              :      cc1 etc.
    3267              :      For the jit case, we need to add these arguments here.  The
    3268              :      input format (using the specs language) means that we have to run
    3269              :      part of the driver code here (driver_get_configure_time_options).
    3270              : 
    3271              :      To avoid running the spec-expansion code every time, we just do
    3272              :      it the first time (via a function-static flag), saving the result
    3273              :      into a function-static vec.
    3274              :      This flag and vec are global state (i.e. per-process).
    3275              :      They are guarded by the jit mutex.  */
    3276         1331 :   {
    3277         1331 :     static bool have_configure_time_options = false;
    3278         1331 :     static vec <char *> configure_time_options;
    3279              : 
    3280         1331 :     if (have_configure_time_options)
    3281         1200 :       log ("reusing cached configure-time options");
    3282              :     else
    3283              :       {
    3284          131 :         have_configure_time_options = true;
    3285          131 :         log ("getting configure-time options from driver");
    3286          131 :         driver_get_configure_time_options (append_arg_from_driver,
    3287              :                                            &configure_time_options);
    3288              :       }
    3289              : 
    3290         1331 :     int i;
    3291         1331 :     char *opt;
    3292              : 
    3293         1331 :     if (get_logger ())
    3294         1821 :       FOR_EACH_VEC_ELT (configure_time_options, i, opt)
    3295         1214 :         log ("configure_time_options[%i]: %s", i, opt);
    3296              : 
    3297              :     /* configure_time_options should now contain the expanded options
    3298              :        from OPTION_DEFAULT_SPECS (if any).  */
    3299         3993 :     FOR_EACH_VEC_ELT (configure_time_options, i, opt)
    3300              :       {
    3301         2662 :         gcc_assert (opt);
    3302         2662 :         gcc_assert (opt[0] == '-');
    3303         2662 :         ADD_ARG (opt);
    3304              :       }
    3305              :   }
    3306              : 
    3307         1331 :   if (get_timer ())
    3308          400 :     ADD_ARG ("-ftime-report");
    3309              : 
    3310              :   /* Add any user-provided extra options, starting with any from
    3311              :      parent contexts.  */
    3312         1331 :   m_recording_ctxt->append_command_line_options (argvec);
    3313              : 
    3314              : #undef ADD_ARG
    3315              : #undef ADD_ARG_TAKE_OWNERSHIP
    3316         1331 : }
    3317              : 
    3318              : /* The second half of the implementation of gcc_jit_context_enable_dump.
    3319              :    Iterate through the requested dumps, reading the underlying files
    3320              :    into heap-allocated buffers, writing pointers to the buffers into
    3321              :    the char ** pointers provided by client code.
    3322              :    Client code is responsible for calling free on the results.  */
    3323              : 
    3324              : void
    3325         1331 : playback::context::
    3326              : extract_any_requested_dumps (vec <recording::requested_dump> *requested_dumps)
    3327              : {
    3328         1331 :   JIT_LOG_SCOPE (get_logger ());
    3329              : 
    3330         1331 :   int i;
    3331         1331 :   recording::requested_dump *d;
    3332         1381 :   FOR_EACH_VEC_ELT (*requested_dumps, i, d)
    3333              :     {
    3334           50 :       dump_file_info *dfi;
    3335           50 :       char *filename;
    3336           50 :       char *content;
    3337              : 
    3338           50 :       dfi = g->get_dumps ()->get_dump_file_info_by_switch (d->m_dumpname);
    3339           50 :       if (!dfi)
    3340              :         {
    3341            5 :           add_error (NULL, "unrecognized dump: %s", d->m_dumpname);
    3342            5 :           continue;
    3343              :         }
    3344              : 
    3345           45 :       filename = g->get_dumps ()->get_dump_file_name (dfi);
    3346           45 :       content = read_dump_file (filename);
    3347           45 :       *(d->m_out_ptr) = content;
    3348           45 :       m_tempdir->add_temp_file (filename);
    3349              :     }
    3350         1331 : }
    3351              : 
    3352              : /* Helper function for playback::context::extract_any_requested_dumps
    3353              :    (itself for use in implementation of gcc_jit_context_enable_dump).
    3354              : 
    3355              :    Attempt to read the complete file at the given path, returning the
    3356              :    bytes found there as a buffer.
    3357              :    The caller is responsible for calling free on the result.
    3358              :    Errors will be reported on the context, and lead to NULL being
    3359              :    returned; an out-of-memory error will terminate the process.  */
    3360              : 
    3361              : char *
    3362           45 : playback::context::read_dump_file (const char *path)
    3363              : {
    3364           45 :   char *result = NULL;
    3365           45 :   size_t total_sz = 0;
    3366           45 :   char buf[4096];
    3367           45 :   size_t sz;
    3368           45 :   FILE *f_in;
    3369              : 
    3370           45 :   f_in = fopen (path, "r");
    3371           45 :   if (!f_in)
    3372              :     {
    3373            0 :       add_error (NULL, "unable to open %s for reading", path);
    3374            0 :       return NULL;
    3375              :     }
    3376              : 
    3377         5310 :   while ( (sz = fread (buf, 1, sizeof (buf), f_in)) )
    3378              :     {
    3379         5265 :       size_t old_total_sz = total_sz;
    3380         5265 :       total_sz += sz;
    3381         5265 :       result = reinterpret_cast <char *> (xrealloc (result, total_sz + 1));
    3382         5265 :       memcpy (result + old_total_sz, buf, sz);
    3383              :     }
    3384              : 
    3385           45 :   if (!feof (f_in))
    3386              :     {
    3387            0 :       add_error (NULL, "error reading from %s", path);
    3388            0 :       free (result);
    3389            0 :       fclose (f_in);
    3390            0 :       return NULL;
    3391              :     }
    3392              : 
    3393           45 :   fclose (f_in);
    3394              : 
    3395           45 :   if (result)
    3396              :     {
    3397           45 :       result[total_sz] = '\0';
    3398           45 :       return result;
    3399              :     }
    3400              :   else
    3401            0 :     return xstrdup ("");
    3402              : }
    3403              : 
    3404              : /* Part of playback::context::compile ().
    3405              : 
    3406              :    We have a .s file; we want a .so file.
    3407              :    We could reuse parts of gcc/gcc.cc to do this.
    3408              :    For now, just use the driver binary from the install, as
    3409              :    named in gcc-driver-name.h
    3410              :    e.g. "x86_64-unknown-linux-gnu-gcc-5.0.0".  */
    3411              : 
    3412              : void
    3413         1118 : playback::context::
    3414              : convert_to_dso (const char *ctxt_progname)
    3415              : {
    3416         1118 :   JIT_LOG_SCOPE (get_logger ());
    3417              : 
    3418         1118 :   invoke_driver (ctxt_progname,
    3419         1118 :                  m_tempdir->get_path_s_file (),
    3420         1118 :                  m_tempdir->get_path_so_file (),
    3421              :                  TV_ASSEMBLE,
    3422              :                  true, /* bool shared, */
    3423              :                  true);/* bool run_linker */
    3424         1118 : }
    3425              : 
    3426              : static const char * const gcc_driver_name = GCC_DRIVER_NAME;
    3427              : 
    3428              : void
    3429         1139 : playback::context::
    3430              : invoke_driver (const char *ctxt_progname,
    3431              :                const char *input_file,
    3432              :                const char *output_file,
    3433              :                timevar_id_t tv_id,
    3434              :                bool shared,
    3435              :                bool run_linker)
    3436              : {
    3437         1139 :   JIT_LOG_SCOPE (get_logger ());
    3438              : 
    3439         1139 :   bool embedded_driver
    3440         1139 :     = !get_inner_bool_option (INNER_BOOL_OPTION_USE_EXTERNAL_DRIVER);
    3441              : 
    3442              :   /* Currently this lumps together both assembling and linking into
    3443              :      TV_ASSEMBLE.  */
    3444         1139 :   auto_timevar assemble_timevar (get_timer (), tv_id);
    3445         1139 :   auto_string_vec argvec;
    3446              : #define ADD_ARG(arg) argvec.safe_push (xstrdup (arg))
    3447              : 
    3448         1139 :   ADD_ARG (gcc_driver_name);
    3449              : 
    3450         1139 :   add_multilib_driver_arguments (&argvec);
    3451              : 
    3452         1139 :   if (shared)
    3453         1123 :     ADD_ARG ("-shared");
    3454              : 
    3455         1139 :   if (!run_linker)
    3456            5 :     ADD_ARG ("-c");
    3457              : 
    3458         1139 :   ADD_ARG (input_file);
    3459         1139 :   ADD_ARG ("-o");
    3460         1139 :   ADD_ARG (output_file);
    3461              : 
    3462              :   /* Don't use the linker plugin.
    3463              :      If running with just a "make" and not a "make install", then we'd
    3464              :      run into
    3465              :        "fatal error: -fuse-linker-plugin, but liblto_plugin.so not found"
    3466              :      libto_plugin is a .la at build time, with it becoming installed with
    3467              :      ".so" suffix: i.e. it doesn't exist with a .so suffix until install
    3468              :      time.  */
    3469         1139 :   ADD_ARG ("-fno-use-linker-plugin");
    3470              : 
    3471              : #if defined (DARWIN_X86) || defined (DARWIN_PPC)
    3472              :   /* macOS's linker defaults to treating undefined symbols as errors.
    3473              :      If the context has any imported functions or globals they will be
    3474              :      undefined until the .so is dynamically-linked into the process.
    3475              :      Ensure that the driver passes in "-undefined dynamic_lookup" to the
    3476              :      linker.  */
    3477              :   ADD_ARG ("-Wl,-undefined,dynamic_lookup");
    3478              : #endif
    3479              : 
    3480         1139 :   if (0)
    3481              :     ADD_ARG ("-v");
    3482              : 
    3483              :   /* Add any user-provided driver extra options.  */
    3484              : 
    3485         1139 :   m_recording_ctxt->append_driver_options (&argvec);
    3486              : 
    3487              : #undef ADD_ARG
    3488              : 
    3489              :   /* pex_one's error-handling requires pname to be non-NULL.  */
    3490         1139 :   gcc_assert (ctxt_progname);
    3491              : 
    3492         1139 :   if (get_logger ())
    3493         3581 :     for (unsigned i = 0; i < argvec.length (); i++)
    3494         3134 :       get_logger ()->log ("argv[%i]: %s", i, argvec[i]);
    3495              : 
    3496         1139 :   if (embedded_driver)
    3497         1134 :     invoke_embedded_driver (&argvec);
    3498              :   else
    3499            5 :     invoke_external_driver (ctxt_progname, &argvec);
    3500         1139 : }
    3501              : 
    3502              : void
    3503         1134 : playback::context::
    3504              : invoke_embedded_driver (const vec <char *> *argvec)
    3505              : {
    3506         1134 :   JIT_LOG_SCOPE (get_logger ());
    3507         1134 :   driver d (true, /* can_finalize */
    3508         1134 :             false); /* debug */
    3509         2268 :   int result = d.main (argvec->length (),
    3510         1134 :                        const_cast <char **> (argvec->address ()));
    3511         1134 :   d.finalize ();
    3512         1134 :   if (result)
    3513            0 :     add_error (NULL, "error invoking gcc driver");
    3514         1134 : }
    3515              : 
    3516              : void
    3517            5 : playback::context::
    3518              : invoke_external_driver (const char *ctxt_progname,
    3519              :                         vec <char *> *argvec)
    3520              : {
    3521            5 :   JIT_LOG_SCOPE (get_logger ());
    3522            5 :   const char *errmsg;
    3523            5 :   int exit_status = 0;
    3524            5 :   int err = 0;
    3525              : 
    3526              :   /* pex argv arrays are NULL-terminated.  */
    3527            5 :   argvec->safe_push (NULL);
    3528              : 
    3529            5 :   errmsg = pex_one (PEX_SEARCH, /* int flags, */
    3530              :                     gcc_driver_name,
    3531            5 :                     const_cast <char *const *> (argvec->address ()),
    3532              :                     ctxt_progname, /* const char *pname */
    3533              :                     NULL, /* const char *outname */
    3534              :                     NULL, /* const char *errname */
    3535              :                     &exit_status, /* int *status */
    3536              :                     &err); /* int *err*/
    3537            5 :   if (errmsg)
    3538              :     {
    3539            5 :       add_error (NULL, "error invoking gcc driver: %s", errmsg);
    3540            5 :       return;
    3541              :     }
    3542              : 
    3543              :   /* pex_one can return a NULL errmsg when the executable wasn't
    3544              :      found (or doesn't exist), so trap these cases also.  */
    3545            0 :   if (exit_status || err)
    3546              :     {
    3547            0 :       add_error (NULL,
    3548              :                  "error invoking gcc driver: exit_status: %i err: %i",
    3549              :                  exit_status, err);
    3550            0 :       add_error (NULL,
    3551              :                  "whilst attempting to run a driver named: %s",
    3552              :                  gcc_driver_name);
    3553            0 :       add_error (NULL,
    3554              :                  "PATH was: %s",
    3555              :                  getenv ("PATH"));
    3556            0 :       return;
    3557              :     }
    3558            5 : }
    3559              : 
    3560              : /* Extract the target-specific MULTILIB_DEFAULTS to
    3561              :    multilib_defaults_raw for use by
    3562              :    playback::context::add_multilib_driver_arguments ().  */
    3563              : 
    3564              : #ifndef MULTILIB_DEFAULTS
    3565              : #define MULTILIB_DEFAULTS { "" }
    3566              : #endif
    3567              : 
    3568              : static const char *const multilib_defaults_raw[] = MULTILIB_DEFAULTS;
    3569              : 
    3570              : /* Helper function for playback::context::invoke_driver ().
    3571              : 
    3572              :    32-bit and 64-bit multilib peer builds of libgccjit.so may share
    3573              :    a driver binary.  We need to pass in options to the shared driver
    3574              :    to get the appropriate assembler/linker options for this multilib
    3575              :    peer.  */
    3576              : 
    3577              : void
    3578         1139 : playback::context::
    3579              : add_multilib_driver_arguments (vec <char *> *argvec)
    3580              : {
    3581         1139 :   JIT_LOG_SCOPE (get_logger ());
    3582              : 
    3583              :   /* Add copies of the arguments in multilib_defaults_raw to argvec,
    3584              :      prepending each with a "-".  */
    3585         2278 :   for (size_t i = 0; i < ARRAY_SIZE (multilib_defaults_raw); i++)
    3586         1139 :     if (multilib_defaults_raw[i][0])
    3587         1139 :       argvec->safe_push (concat ("-", multilib_defaults_raw[i], NULL));
    3588         1139 : }
    3589              : 
    3590              : /* Dynamically-link the built DSO file into this process, using dlopen.
    3591              :    Wrap it up within a jit::result *, and return that.
    3592              :    Return NULL if any errors occur, reporting them on this context.  */
    3593              : 
    3594              : result *
    3595         1113 : playback::context::
    3596              : dlopen_built_dso ()
    3597              : {
    3598         1113 :   JIT_LOG_SCOPE (get_logger ());
    3599         1113 :   auto_timevar load_timevar (get_timer (), TV_LOAD);
    3600         1113 :   result::handle handle = NULL;
    3601         1113 :   result *result_obj = NULL;
    3602              : 
    3603              : #ifdef _WIN32
    3604              :   /* Clear any existing error.  */
    3605              :   SetLastError(0);
    3606              : 
    3607              :   handle = LoadLibrary(m_tempdir->get_path_so_file ());
    3608              :   if (GetLastError() != 0)  {
    3609              :     print_last_error();
    3610              :   }
    3611              : #else
    3612         1113 :   const char *error = NULL;
    3613              :   /* Clear any existing error.  */
    3614         1113 :   dlerror ();
    3615              : 
    3616         1113 :   handle = dlopen (m_tempdir->get_path_so_file (),
    3617              :                    RTLD_NOW | RTLD_LOCAL);
    3618         1113 :   if ((error = dlerror()) != NULL)  {
    3619            0 :     add_error (NULL, "%s", error);
    3620              :   }
    3621              : #endif
    3622              : 
    3623         1113 :   if (handle)
    3624              :     {
    3625              :       /* We've successfully dlopened the result; create a
    3626              :          jit::result object to wrap it.
    3627              : 
    3628              :          We're done with the tempdir for now, but if the user
    3629              :          has requested debugging, the user's debugger might not
    3630              :          be capable of dealing with the .so file being unlinked
    3631              :          immediately, so keep it around until after the result
    3632              :          is released.  We do this by handing over ownership of
    3633              :          the jit::tempdir to the result.  See PR jit/64206.  */
    3634         1113 :       tempdir *handover_tempdir;
    3635         1113 :       if (get_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO))
    3636              :         {
    3637          706 :           handover_tempdir = m_tempdir;
    3638          706 :           m_tempdir = NULL;
    3639              :           /* The tempdir will eventually be cleaned up in the
    3640              :              jit::result's dtor. */
    3641          706 :           log ("GCC_JIT_BOOL_OPTION_DEBUGINFO was set:"
    3642              :                " handing over tempdir to jit::result");
    3643              :         }
    3644              :       else
    3645              :         {
    3646          407 :           handover_tempdir = NULL;
    3647              :           /* ... and retain ownership of m_tempdir so we clean it
    3648              :              up it the playback::context's dtor. */
    3649          407 :           log ("GCC_JIT_BOOL_OPTION_DEBUGINFO was not set:"
    3650              :                " retaining ownership of tempdir");
    3651              :         }
    3652              : 
    3653         1113 :       result_obj = new result (get_logger (), handle, handover_tempdir);
    3654              :     }
    3655              :   else
    3656              :     result_obj = NULL;
    3657              : 
    3658         2226 :   return result_obj;
    3659         1113 : }
    3660              : 
    3661              : /* Top-level hook for playing back a recording context.
    3662              : 
    3663              :    This plays back m_recording_ctxt, and, if no errors
    3664              :    occurred builds statement lists for and then postprocesses
    3665              :    every function in the result.  */
    3666              : 
    3667              : void
    3668         1326 : playback::context::
    3669              : replay ()
    3670              : {
    3671         1326 :   JIT_LOG_SCOPE (get_logger ());
    3672              : 
    3673         1326 :   init_types ();
    3674         1326 :   jit_target_init ();
    3675              : 
    3676              :   /* Replay the recorded events:  */
    3677         1326 :   timevar_push (TV_JIT_REPLAY);
    3678              : 
    3679              :   /* Ensure that builtins that could be needed during optimization
    3680              :      get created ahead of time.  */
    3681         1326 :   builtins_manager *bm = m_recording_ctxt->get_builtins_manager ();
    3682         1326 :   bm->ensure_optimization_builtins_exist ();
    3683              : 
    3684         1326 :   m_recording_ctxt->replay_into (this);
    3685              : 
    3686              :   /* Clean away the temporary references from recording objects
    3687              :      to playback objects.  We have to do this now since the
    3688              :      latter are GC-allocated, but the former don't mark these
    3689              :      refs.  Hence we must stop using them before the GC can run.  */
    3690         1326 :   m_recording_ctxt->disassociate_from_playback ();
    3691              : 
    3692              :   /* The builtins_manager is associated with the recording::context
    3693              :      and might be reused for future compiles on other playback::contexts,
    3694              :      but its m_attributes array is not GTY-labeled and hence will become
    3695              :      nonsense if the GC runs.  Purge this state.  */
    3696         1326 :   bm->finish_playback ();
    3697              : 
    3698         1326 :   timevar_pop (TV_JIT_REPLAY);
    3699              : 
    3700         1326 :   if (!errors_occurred ())
    3701              :     {
    3702         1291 :       int i;
    3703         1291 :       function *func;
    3704         1291 :       tree global;
    3705              :       /* No GC can happen yet; process the cached source locations.  */
    3706         1291 :       handle_locations ();
    3707              : 
    3708              :       /* Finalize globals. See how FORTRAN 95 does it in gfc_be_parse_file()
    3709              :          for a simple reference. */
    3710         3613 :       FOR_EACH_VEC_ELT (m_globals, i, global)
    3711         1031 :         rest_of_decl_compilation (global, true, true);
    3712              : 
    3713         1427 :       wrapup_global_declarations (m_globals.address(), m_globals.length());
    3714              : 
    3715              :       /* We've now created tree nodes for the stmts in the various blocks
    3716              :          in each function, but we haven't built each function's single stmt
    3717              :          list yet.  Do so now.  */
    3718        19234 :       FOR_EACH_VEC_ELT (m_functions, i, func)
    3719        16652 :         func->build_stmt_list ();
    3720              : 
    3721              :       /* No GC can have happened yet.  */
    3722              : 
    3723              :       /* Postprocess the functions.  This could trigger GC.  */
    3724        17943 :       FOR_EACH_VEC_ELT (m_functions, i, func)
    3725              :         {
    3726        16652 :           gcc_assert (func);
    3727        16652 :           func->postprocess ();
    3728              :         }
    3729              :     }
    3730         1326 : }
    3731              : 
    3732              : /* Dump the generated .s file to stderr.  */
    3733              : 
    3734              : void
    3735            0 : playback::context::
    3736              : dump_generated_code ()
    3737              : {
    3738            0 :   JIT_LOG_SCOPE (get_logger ());
    3739            0 :   char buf[4096];
    3740            0 :   size_t sz;
    3741            0 :   FILE *f_in = fopen (get_path_s_file (), "r");
    3742            0 :   if (!f_in)
    3743            0 :     return;
    3744              : 
    3745            0 :   while ( (sz = fread (buf, 1, sizeof (buf), f_in)) )
    3746            0 :     fwrite (buf, 1, sz, stderr);
    3747              : 
    3748            0 :   fclose (f_in);
    3749            0 : }
    3750              : 
    3751              : /* Get the supposed path of the notional "fake.c" file within the
    3752              :    tempdir.  This file doesn't exist, but the rest of the compiler
    3753              :    needs a name.  */
    3754              : 
    3755              : const char *
    3756         1331 : playback::context::
    3757              : get_path_c_file () const
    3758              : {
    3759         1331 :   return m_tempdir->get_path_c_file ();
    3760              : }
    3761              : 
    3762              : /* Get the path of the assembler output file "fake.s" file within the
    3763              :    tempdir. */
    3764              : 
    3765              : const char *
    3766            0 : playback::context::
    3767              : get_path_s_file () const
    3768              : {
    3769            0 :   return m_tempdir->get_path_s_file ();
    3770              : }
    3771              : 
    3772              : /* Get the path of the DSO object file "fake.so" file within the
    3773              :    tempdir. */
    3774              : 
    3775              : const char *
    3776            0 : playback::context::
    3777              : get_path_so_file () const
    3778              : {
    3779            0 :   return m_tempdir->get_path_so_file ();
    3780              : }
    3781              : 
    3782              : /* qsort comparator for comparing pairs of playback::source_line *,
    3783              :    ordering them by line number.  */
    3784              : 
    3785              : static int
    3786         5518 : line_comparator (const void *lhs, const void *rhs)
    3787              : {
    3788         5518 :   const playback::source_line *line_lhs = \
    3789              :     *static_cast<const playback::source_line * const*> (lhs);
    3790         5518 :   const playback::source_line *line_rhs = \
    3791              :     *static_cast<const playback::source_line * const*> (rhs);
    3792         5518 :   return line_lhs->get_line_num () - line_rhs->get_line_num ();
    3793              : }
    3794              : 
    3795              : /* qsort comparator for comparing pairs of playback::location *,
    3796              :    ordering them by column number.  */
    3797              : 
    3798              : static int
    3799         6713 : location_comparator (const void *lhs, const void *rhs)
    3800              : {
    3801         6713 :   const playback::location *loc_lhs = \
    3802              :     *static_cast<const playback::location * const *> (lhs);
    3803         6713 :   const playback::location *loc_rhs = \
    3804              :     *static_cast<const playback::location * const *> (rhs);
    3805         6713 :   return loc_lhs->get_column_num () - loc_rhs->get_column_num ();
    3806              : }
    3807              : 
    3808              : /* Initialize the NAME_TYPE of the primitive types as well as some
    3809              :    others. */
    3810              : void
    3811         1326 : playback::context::
    3812              : init_types ()
    3813              : {
    3814              :   /* See lto_init () in lto-lang.cc or void visit (TypeBasic *t) in D's types.cc
    3815              :      for reference. If TYPE_NAME is not set, debug info will not contain types */
    3816              : #define NAME_TYPE(t,n) \
    3817              : if (t) \
    3818              :   TYPE_NAME (t) = build_decl (UNKNOWN_LOCATION, TYPE_DECL, \
    3819              :                               get_identifier (n), t)
    3820              : 
    3821         1326 :   NAME_TYPE (integer_type_node, "int");
    3822         1326 :   NAME_TYPE (char_type_node, "char");
    3823         1326 :   NAME_TYPE (long_integer_type_node, "long int");
    3824         1326 :   NAME_TYPE (unsigned_type_node, "unsigned int");
    3825         1326 :   NAME_TYPE (long_unsigned_type_node, "long unsigned int");
    3826         1326 :   NAME_TYPE (long_long_integer_type_node, "long long int");
    3827         1326 :   NAME_TYPE (long_long_unsigned_type_node, "long long unsigned int");
    3828         1326 :   NAME_TYPE (short_integer_type_node, "short int");
    3829         1326 :   NAME_TYPE (short_unsigned_type_node, "short unsigned int");
    3830         1326 :   if (signed_char_type_node != char_type_node)
    3831         1326 :     NAME_TYPE (signed_char_type_node, "signed char");
    3832         1326 :   if (unsigned_char_type_node != char_type_node)
    3833         1326 :     NAME_TYPE (unsigned_char_type_node, "unsigned char");
    3834         1326 :   NAME_TYPE (float_type_node, "float");
    3835         1326 :   NAME_TYPE (double_type_node, "double");
    3836         1326 :   NAME_TYPE (long_double_type_node, "long double");
    3837         1326 :   NAME_TYPE (void_type_node, "void");
    3838         1326 :   NAME_TYPE (boolean_type_node, "bool");
    3839         1326 :   NAME_TYPE (complex_float_type_node, "complex float");
    3840         1326 :   NAME_TYPE (complex_double_type_node, "complex double");
    3841         1326 :   NAME_TYPE (complex_long_double_type_node, "complex long double");
    3842              : 
    3843         1326 :   m_const_char_ptr = build_pointer_type(
    3844              :     build_qualified_type (char_type_node, TYPE_QUAL_CONST));
    3845              : 
    3846         1326 :   NAME_TYPE (m_const_char_ptr, "char");
    3847         1326 :   NAME_TYPE (size_type_node, "size_t");
    3848         1326 :   NAME_TYPE (fileptr_type_node, "FILE");
    3849              : #undef NAME_TYPE
    3850         1326 : }
    3851              : 
    3852              : /* Our API allows locations to be created in arbitrary orders, but the
    3853              :    linemap API requires locations to be created in ascending order
    3854              :    as if we were tokenizing files.
    3855              : 
    3856              :    This hook sorts all of the locations that have been created, and
    3857              :    calls into the linemap API, creating linemap entries in sorted order
    3858              :    for our locations.  */
    3859              : 
    3860              : void
    3861         1291 : playback::context::
    3862              : handle_locations ()
    3863              : {
    3864              :   /* Create the source code locations, following the ordering rules
    3865              :      imposed by the linemap API.
    3866              : 
    3867              :      line_table is a global.  */
    3868         1291 :   JIT_LOG_SCOPE (get_logger ());
    3869         1291 :   int i;
    3870         1291 :   source_file *file;
    3871              : 
    3872         1353 :   FOR_EACH_VEC_ELT (m_source_files, i, file)
    3873              :     {
    3874           62 :       linemap_add (line_table, LC_ENTER, false, file->get_filename (), 0);
    3875              : 
    3876              :       /* Sort lines by ascending line numbers.  */
    3877           62 :       file->m_source_lines.qsort (&line_comparator);
    3878              : 
    3879              :       int j;
    3880              :       source_line *line;
    3881          455 :       FOR_EACH_VEC_ELT (file->m_source_lines, j, line)
    3882              :         {
    3883          393 :           int k;
    3884          393 :           location *loc;
    3885              : 
    3886              :           /* Sort locations in line by ascending column numbers.  */
    3887          393 :           line->m_locations.qsort (&location_comparator);
    3888              : 
    3889              :           /* Determine maximum column within this line.  */
    3890          393 :           gcc_assert (line->m_locations.length () > 0);
    3891          393 :           location *final_column =
    3892          393 :             line->m_locations[line->m_locations.length () - 1];
    3893          393 :           int max_col = final_column->get_column_num ();
    3894              : 
    3895          393 :           linemap_line_start (line_table, line->get_line_num (), max_col);
    3896         1916 :           FOR_EACH_VEC_ELT (line->m_locations, k, loc)
    3897              :             {
    3898          737 :               loc->m_srcloc =                                           \
    3899          737 :                 linemap_position_for_column (line_table, loc->get_column_num ());
    3900              :             }
    3901              :         }
    3902              : 
    3903           62 :       linemap_add (line_table, LC_LEAVE, false, NULL, 0);
    3904              :     }
    3905              : 
    3906              :   /* line_table should now be populated; every playback::location should
    3907              :      now have an m_srcloc.  */
    3908              : 
    3909              :   /* Now assign them to tree nodes as appropriate.  */
    3910              :   std::pair<tree, location *> *cached_location;
    3911              : 
    3912         2851 :   FOR_EACH_VEC_ELT (m_cached_locations, i, cached_location)
    3913              :     {
    3914         1560 :       tree t = cached_location->first;
    3915         1560 :       location_t srcloc = cached_location->second->m_srcloc;
    3916              : 
    3917              :       /* This covers expressions: */
    3918         1560 :       if (CAN_HAVE_LOCATION_P (t))
    3919         1449 :         SET_EXPR_LOCATION (t, srcloc);
    3920          111 :       else if (CODE_CONTAINS_STRUCT(TREE_CODE(t), TS_DECL_MINIMAL))
    3921          111 :         DECL_SOURCE_LOCATION (t) = srcloc;
    3922              :       else
    3923              :         {
    3924              :           /* Don't know how to set location on this node.  */
    3925              :         }
    3926              :     }
    3927         1291 : }
    3928              : 
    3929              : /* We handle errors on a playback::context by adding them to the
    3930              :    corresponding recording::context.  */
    3931              : 
    3932              : void
    3933           45 : playback::context::
    3934              : add_error (location *loc, const char *fmt, ...)
    3935              : {
    3936           45 :   va_list ap;
    3937           45 :   va_start (ap, fmt);
    3938           45 :   m_recording_ctxt->add_error_va (loc ? loc->get_recording_loc () : NULL,
    3939              :                                   diagnostics::kind::error, fmt, ap);
    3940           45 :   va_end (ap);
    3941           45 : }
    3942              : 
    3943              : /* We handle errors on a playback::context by adding them to the
    3944              :    corresponding recording::context.  */
    3945              : 
    3946              : void
    3947            0 : playback::context::
    3948              : add_error_va (location *loc, const char *fmt, va_list ap)
    3949              : {
    3950            0 :   m_recording_ctxt->add_error_va (loc ? loc->get_recording_loc () : NULL,
    3951              :                                   diagnostics::kind::error, fmt, ap);
    3952            0 : }
    3953              : 
    3954              : /* Report a diagnostic up to the jit context, so that the
    3955              :    compilation is treated as a failure if the diagnostic
    3956              :    is an error.  */
    3957              : 
    3958              : void
    3959           25 : playback::context::
    3960              : add_diagnostic (const char *text,
    3961              :                 const diagnostics::diagnostic_info &diagnostic)
    3962              : {
    3963              :   /* Get location information (if any) from the diagnostic.
    3964              :      The recording::context::add_error[_va] methods require a
    3965              :      recording::location.  We can't lookup the playback::location
    3966              :      from the file/line/column since any playback location instances
    3967              :      may have been garbage-collected away by now, so instead we create
    3968              :      another recording::location directly.  */
    3969           25 :   location_t gcc_loc = diagnostic_location (&diagnostic);
    3970           25 :   recording::location *rec_loc = NULL;
    3971           25 :   if (gcc_loc)
    3972              :     {
    3973           10 :       expanded_location exploc = expand_location (gcc_loc);
    3974           10 :       if (exploc.file)
    3975            5 :         rec_loc = m_recording_ctxt->new_location (exploc.file,
    3976              :                                                   exploc.line,
    3977              :                                                   exploc.column,
    3978              :                                                   false);
    3979              :     }
    3980              : 
    3981           25 :   m_recording_ctxt->add_diagnostic (rec_loc, diagnostic.m_kind, "%s", text);
    3982           25 : }
    3983              : 
    3984              : /* Dealing with the linemap API.  */
    3985              : 
    3986              : /* Construct a playback::location for a recording::location, if it
    3987              :    doesn't exist already.  */
    3988              : 
    3989              : playback::location *
    3990          965 : playback::context::
    3991              : new_location (recording::location *rloc,
    3992              :               const char *filename,
    3993              :               int line,
    3994              :               int column)
    3995              : {
    3996              :   /* Get the source_file for filename, creating if necessary.  */
    3997          965 :   source_file *src_file = get_source_file (filename);
    3998              :   /* Likewise for the line within the file.  */
    3999          965 :   source_line *src_line = src_file->get_source_line (line);
    4000              :   /* Likewise for the column within the line.  */
    4001          965 :   location *loc = src_line->get_location (rloc, column);
    4002          965 :   return loc;
    4003              : }
    4004              : 
    4005              : /* Deferred setting of the location for a given tree, by adding the
    4006              :    (tree, playback::location) pair to a list of deferred associations.
    4007              :    We will actually set the location on the tree later on once
    4008              :    the location_t for the playback::location exists.  */
    4009              : 
    4010              : void
    4011         1560 : playback::context::
    4012              : set_tree_location (tree t, location *loc)
    4013              : {
    4014         1560 :   gcc_assert (loc);
    4015         1560 :   m_cached_locations.safe_push (std::make_pair (t, loc));
    4016         1560 : }
    4017              : 
    4018              : 
    4019              : /* Construct a playback::source_file for the given source
    4020              :    filename, if it doesn't exist already.  */
    4021              : 
    4022              : playback::source_file *
    4023          965 : playback::context::
    4024              : get_source_file (const char *filename)
    4025              : {
    4026              :   /* Locate the file.
    4027              :      For simplicitly, this is currently a linear search.
    4028              :      Replace with a hash if this shows up in the profile.  */
    4029          965 :   int i;
    4030          965 :   source_file *file;
    4031          965 :   tree ident_filename = get_identifier (filename);
    4032              : 
    4033         2698 :   FOR_EACH_VEC_ELT (m_source_files, i, file)
    4034         1671 :     if (file->filename_as_tree () == ident_filename)
    4035              :       return file;
    4036              : 
    4037              :   /* Not found.  */
    4038           62 :   file = new source_file (ident_filename);
    4039           62 :   m_source_files.safe_push (file);
    4040           62 :   return file;
    4041              : }
    4042              : 
    4043              : /* Constructor for gcc::jit::playback::source_file.  */
    4044              : 
    4045           62 : playback::source_file::source_file (tree filename) :
    4046           62 :   m_source_lines (),
    4047           62 :   m_filename (filename)
    4048              : {
    4049           62 : }
    4050              : 
    4051              : /* Don't leak vec's internal buffer (in non-GC heap) when we are
    4052              :    GC-ed.  */
    4053              : 
    4054              : void
    4055           56 : playback::source_file::finalizer ()
    4056              : {
    4057           56 :   m_source_lines.release ();
    4058           56 : }
    4059              : 
    4060              : /* Construct a playback::source_line for the given line
    4061              :    within this source file, if one doesn't exist already.  */
    4062              : 
    4063              : playback::source_line *
    4064          965 : playback::source_file::
    4065              : get_source_line (int line_num)
    4066              : {
    4067              :   /* Locate the line.
    4068              :      For simplicitly, this is currently a linear search.
    4069              :      Replace with a hash if this shows up in the profile.  */
    4070          965 :   int i;
    4071          965 :   source_line *line;
    4072              : 
    4073         7404 :   FOR_EACH_VEC_ELT (m_source_lines, i, line)
    4074         7011 :     if (line->get_line_num () == line_num)
    4075              :       return line;
    4076              : 
    4077              :   /* Not found.  */
    4078          393 :   line = new source_line (this, line_num);
    4079          393 :   m_source_lines.safe_push (line);
    4080          393 :   return line;
    4081              : }
    4082              : 
    4083              : /* Constructor for gcc::jit::playback::source_line.  */
    4084              : 
    4085          393 : playback::source_line::source_line (source_file *file, int line_num) :
    4086          393 :   m_locations (),
    4087          393 :   m_source_file (file),
    4088          393 :   m_line_num (line_num)
    4089              : {
    4090          393 : }
    4091              : 
    4092              : /* Don't leak vec's internal buffer (in non-GC heap) when we are
    4093              :    GC-ed.  */
    4094              : 
    4095              : void
    4096          324 : playback::source_line::finalizer ()
    4097              : {
    4098          324 :   m_locations.release ();
    4099          324 : }
    4100              : 
    4101              : /* Construct a playback::location for the given column
    4102              :    within this line of a specific source file, if one doesn't exist
    4103              :    already.  */
    4104              : 
    4105              : playback::location *
    4106          965 : playback::source_line::
    4107              : get_location (recording::location *rloc, int column_num)
    4108              : {
    4109          965 :   int i;
    4110          965 :   location *loc;
    4111              : 
    4112              :   /* Another linear search that probably should be a hash table.  */
    4113         5376 :   FOR_EACH_VEC_ELT (m_locations, i, loc)
    4114         4639 :     if (loc->get_column_num () == column_num)
    4115              :       return loc;
    4116              : 
    4117              :   /* Not found.  */
    4118          737 :   loc = new location (rloc, this, column_num);
    4119          737 :   m_locations.safe_push (loc);
    4120          737 :   return loc;
    4121              : }
    4122              : 
    4123              : /* Constructor for gcc::jit::playback::location.  */
    4124              : 
    4125          737 : playback::location::location (recording::location *loc,
    4126              :                               source_line *line,
    4127          737 :                               int column_num) :
    4128          737 :   m_srcloc (UNKNOWN_LOCATION),
    4129          737 :   m_recording_loc (loc),
    4130          737 :   m_line (line),
    4131          737 :   m_column_num(column_num)
    4132              : {
    4133          737 : }
    4134              : 
    4135              : /* The active gcc::jit::playback::context instance.  This is a singleton,
    4136              :    guarded by jit_mutex.  */
    4137              : 
    4138              : playback::context *active_playback_ctxt;
    4139              : 
    4140              : } // namespace gcc::jit
    4141              : 
    4142              : } // namespace gcc
        

Generated by: LCOV version 2.4-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.