1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306
|
/* Routines for reading GIMPLE from a file stream.
Copyright (C) 2011-2018 Free Software Foundation, Inc.
Contributed by Diego Novillo <dnovillo@google.com>
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "backend.h"
#include "tree.h"
#include "gimple.h"
#include "ssa.h"
#include "gimple-streamer.h"
#include "tree-eh.h"
#include "gimple-iterator.h"
#include "cgraph.h"
#include "value-prof.h"
/* Read a PHI function for basic block BB in function FN. DATA_IN is
the file being read. IB is the input block to use for reading. */
static gphi *
input_phi (struct lto_input_block *ib, basic_block bb, struct data_in *data_in,
struct function *fn)
{
unsigned HOST_WIDE_INT ix;
tree phi_result;
int i, len;
gphi *result;
ix = streamer_read_uhwi (ib);
phi_result = (*SSANAMES (fn))[ix];
len = EDGE_COUNT (bb->preds);
result = create_phi_node (phi_result, bb);
/* We have to go through a lookup process here because the preds in the
reconstructed graph are generally in a different order than they
were in the original program. */
for (i = 0; i < len; i++)
{
tree def = stream_read_tree (ib, data_in);
int src_index = streamer_read_uhwi (ib);
bitpack_d bp = streamer_read_bitpack (ib);
/* Do not cache a location - we do not have API to get pointer to the
location in PHI statement and we may trigger reallocation. */
location_t arg_loc = stream_input_location_now (&bp, data_in);
basic_block sbb = BASIC_BLOCK_FOR_FN (fn, src_index);
edge e = NULL;
int j;
for (j = 0; j < len; j++)
if (EDGE_PRED (bb, j)->src == sbb)
{
e = EDGE_PRED (bb, j);
break;
}
add_phi_arg (result, def, e, arg_loc);
}
return result;
}
/* Read a statement with tag TAG in function FN from block IB using
descriptors in DATA_IN. */
static gimple *
input_gimple_stmt (struct lto_input_block *ib, struct data_in *data_in,
enum LTO_tags tag)
{
gimple *stmt;
enum gimple_code code;
unsigned HOST_WIDE_INT num_ops;
size_t i;
struct bitpack_d bp;
bool has_hist;
code = lto_tag_to_gimple_code (tag);
/* Read the tuple header. */
bp = streamer_read_bitpack (ib);
num_ops = bp_unpack_var_len_unsigned (&bp);
stmt = gimple_alloc (code, num_ops);
stmt->no_warning = bp_unpack_value (&bp, 1);
if (is_gimple_assign (stmt))
stmt->nontemporal_move = bp_unpack_value (&bp, 1);
stmt->has_volatile_ops = bp_unpack_value (&bp, 1);
has_hist = bp_unpack_value (&bp, 1);
stmt->subcode = bp_unpack_var_len_unsigned (&bp);
/* Read location information. Caching here makes no sense until streamer
cache can handle the following gimple_set_block. */
gimple_set_location (stmt, stream_input_location_now (&bp, data_in));
/* Read lexical block reference. */
gimple_set_block (stmt, stream_read_tree (ib, data_in));
/* Read in all the operands. */
switch (code)
{
case GIMPLE_RESX:
gimple_resx_set_region (as_a <gresx *> (stmt),
streamer_read_hwi (ib));
break;
case GIMPLE_EH_MUST_NOT_THROW:
gimple_eh_must_not_throw_set_fndecl (
as_a <geh_mnt *> (stmt),
stream_read_tree (ib, data_in));
break;
case GIMPLE_EH_DISPATCH:
gimple_eh_dispatch_set_region (as_a <geh_dispatch *> (stmt),
streamer_read_hwi (ib));
break;
case GIMPLE_ASM:
{
/* FIXME lto. Move most of this into a new gimple_asm_set_string(). */
gasm *asm_stmt = as_a <gasm *> (stmt);
tree str;
asm_stmt->ni = streamer_read_uhwi (ib);
asm_stmt->no = streamer_read_uhwi (ib);
asm_stmt->nc = streamer_read_uhwi (ib);
asm_stmt->nl = streamer_read_uhwi (ib);
str = streamer_read_string_cst (data_in, ib);
asm_stmt->string = TREE_STRING_POINTER (str);
}
/* Fallthru */
case GIMPLE_ASSIGN:
case GIMPLE_CALL:
case GIMPLE_RETURN:
case GIMPLE_SWITCH:
case GIMPLE_LABEL:
case GIMPLE_COND:
case GIMPLE_GOTO:
case GIMPLE_DEBUG:
for (i = 0; i < num_ops; i++)
{
tree *opp, op = stream_read_tree (ib, data_in);
gimple_set_op (stmt, i, op);
if (!op)
continue;
opp = gimple_op_ptr (stmt, i);
if (TREE_CODE (*opp) == ADDR_EXPR)
opp = &TREE_OPERAND (*opp, 0);
while (handled_component_p (*opp))
opp = &TREE_OPERAND (*opp, 0);
/* At LTO output time we wrap all global decls in MEM_REFs to
allow seamless replacement with prevailing decls. Undo this
here if the prevailing decl allows for this.
??? Maybe we should simply fold all stmts. */
if (TREE_CODE (*opp) == MEM_REF
&& TREE_CODE (TREE_OPERAND (*opp, 0)) == ADDR_EXPR
&& integer_zerop (TREE_OPERAND (*opp, 1))
&& (TREE_THIS_VOLATILE (*opp)
== TREE_THIS_VOLATILE
(TREE_OPERAND (TREE_OPERAND (*opp, 0), 0)))
&& !TYPE_REF_CAN_ALIAS_ALL (TREE_TYPE (TREE_OPERAND (*opp, 1)))
&& (TREE_TYPE (*opp)
== TREE_TYPE (TREE_TYPE (TREE_OPERAND (*opp, 1))))
&& (TREE_TYPE (*opp)
== TREE_TYPE (TREE_OPERAND (TREE_OPERAND (*opp, 0), 0))))
*opp = TREE_OPERAND (TREE_OPERAND (*opp, 0), 0);
}
if (gcall *call_stmt = dyn_cast <gcall *> (stmt))
{
if (gimple_call_internal_p (call_stmt))
gimple_call_set_internal_fn
(call_stmt, streamer_read_enum (ib, internal_fn, IFN_LAST));
else
gimple_call_set_fntype (call_stmt, stream_read_tree (ib, data_in));
}
break;
case GIMPLE_NOP:
case GIMPLE_PREDICT:
break;
case GIMPLE_TRANSACTION:
gimple_transaction_set_label_norm (as_a <gtransaction *> (stmt),
stream_read_tree (ib, data_in));
gimple_transaction_set_label_uninst (as_a <gtransaction *> (stmt),
stream_read_tree (ib, data_in));
gimple_transaction_set_label_over (as_a <gtransaction *> (stmt),
stream_read_tree (ib, data_in));
break;
default:
internal_error ("bytecode stream: unknown GIMPLE statement tag %s",
lto_tag_name (tag));
}
/* Update the properties of symbols, SSA names and labels associated
with STMT. */
if (code == GIMPLE_ASSIGN || code == GIMPLE_CALL)
{
tree lhs = gimple_get_lhs (stmt);
if (lhs && TREE_CODE (lhs) == SSA_NAME)
SSA_NAME_DEF_STMT (lhs) = stmt;
}
else if (code == GIMPLE_ASM)
{
gasm *asm_stmt = as_a <gasm *> (stmt);
unsigned i;
for (i = 0; i < gimple_asm_noutputs (asm_stmt); i++)
{
tree op = TREE_VALUE (gimple_asm_output_op (asm_stmt, i));
if (TREE_CODE (op) == SSA_NAME)
SSA_NAME_DEF_STMT (op) = stmt;
}
}
/* Reset alias information. */
if (code == GIMPLE_CALL)
gimple_call_reset_alias_info (as_a <gcall *> (stmt));
/* Mark the statement modified so its operand vectors can be filled in. */
gimple_set_modified (stmt, true);
if (has_hist)
stream_in_histogram_value (ib, stmt);
return stmt;
}
/* Read a basic block with tag TAG from DATA_IN using input block IB.
FN is the function being processed. */
void
input_bb (struct lto_input_block *ib, enum LTO_tags tag,
struct data_in *data_in, struct function *fn,
int count_materialization_scale)
{
unsigned int index;
basic_block bb;
gimple_stmt_iterator bsi;
/* This routine assumes that CFUN is set to FN, as it needs to call
basic GIMPLE routines that use CFUN. */
gcc_assert (cfun == fn);
index = streamer_read_uhwi (ib);
bb = BASIC_BLOCK_FOR_FN (fn, index);
bb->count = profile_count::stream_in (ib);
if (count_materialization_scale != REG_BR_PROB_BASE
&& bb->count.ipa ().nonzero_p ())
bb->count
= bb->count.apply_scale (count_materialization_scale, REG_BR_PROB_BASE);
bb->flags = streamer_read_hwi (ib);
/* LTO_bb1 has statements. LTO_bb0 does not. */
if (tag == LTO_bb0)
return;
bsi = gsi_start_bb (bb);
tag = streamer_read_record_start (ib);
while (tag)
{
gimple *stmt = input_gimple_stmt (ib, data_in, tag);
gsi_insert_after (&bsi, stmt, GSI_NEW_STMT);
/* After the statement, expect a 0 delimiter or the EH region
that the previous statement belongs to. */
tag = streamer_read_record_start (ib);
lto_tag_check_set (tag, 2, LTO_eh_region, LTO_null);
if (tag == LTO_eh_region)
{
HOST_WIDE_INT region = streamer_read_hwi (ib);
gcc_assert (region == (int) region);
add_stmt_to_eh_lp (stmt, region);
}
tag = streamer_read_record_start (ib);
}
tag = streamer_read_record_start (ib);
while (tag)
{
input_phi (ib, bb, data_in, fn);
tag = streamer_read_record_start (ib);
}
}
|