/* Routines for emitting GIMPLE to a file stream. Copyright (C) 2011-2020 Free Software Foundation, Inc. Contributed by Diego Novillo 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 . */ #include "config.h" #include "system.h" #include "coretypes.h" #include "backend.h" #include "tree.h" #include "gimple.h" #include "gimple-ssa.h" #include "gimple-streamer.h" #include "tree-eh.h" #include "gimple-iterator.h" #include "cgraph.h" #include "value-prof.h" #include "gimple-pretty-print.h" /* Output PHI function PHI to the main stream in OB. */ static void output_phi (struct output_block *ob, gphi *phi) { unsigned i, len = gimple_phi_num_args (phi); streamer_write_record_start (ob, lto_gimple_code_to_tag (GIMPLE_PHI)); streamer_write_uhwi (ob, SSA_NAME_VERSION (PHI_RESULT (phi))); for (i = 0; i < len; i++) { stream_write_tree (ob, gimple_phi_arg_def (phi, i), true); streamer_write_uhwi (ob, gimple_phi_arg_edge (phi, i)->src->index); bitpack_d bp = bitpack_create (ob->main_stream); stream_output_location (ob, &bp, gimple_phi_arg_location (phi, i)); streamer_write_bitpack (&bp); } } /* Emit statement STMT on the main stream of output block OB. */ static void output_gimple_stmt (struct output_block *ob, struct function *fn, gimple *stmt) { unsigned i; enum gimple_code code; enum LTO_tags tag; struct bitpack_d bp; histogram_value hist; /* Emit identifying tag. */ code = gimple_code (stmt); tag = lto_gimple_code_to_tag (code); streamer_write_record_start (ob, tag); /* Emit the tuple header. */ bp = bitpack_create (ob->main_stream); bp_pack_var_len_unsigned (&bp, gimple_num_ops (stmt)); bp_pack_value (&bp, gimple_no_warning_p (stmt), 1); if (is_gimple_assign (stmt)) bp_pack_value (&bp, gimple_assign_nontemporal_move_p ( as_a (stmt)), 1); bp_pack_value (&bp, gimple_has_volatile_ops (stmt), 1); hist = gimple_histogram_value (fn, stmt); bp_pack_value (&bp, hist != NULL, 1); bp_pack_var_len_unsigned (&bp, stmt->subcode); /* Emit location information for the statement. */ stream_output_location (ob, &bp, LOCATION_LOCUS (gimple_location (stmt))); streamer_write_bitpack (&bp); /* Emit the lexical block holding STMT. */ stream_write_tree (ob, gimple_block (stmt), true); /* Emit the operands. */ switch (gimple_code (stmt)) { case GIMPLE_RESX: streamer_write_hwi (ob, gimple_resx_region (as_a (stmt))); break; case GIMPLE_EH_MUST_NOT_THROW: stream_write_tree (ob, gimple_eh_must_not_throw_fndecl ( as_a (stmt)), true); break; case GIMPLE_EH_DISPATCH: streamer_write_hwi (ob, gimple_eh_dispatch_region ( as_a (stmt))); break; case GIMPLE_ASM: { gasm *asm_stmt = as_a (stmt); streamer_write_uhwi (ob, gimple_asm_ninputs (asm_stmt)); streamer_write_uhwi (ob, gimple_asm_noutputs (asm_stmt)); streamer_write_uhwi (ob, gimple_asm_nclobbers (asm_stmt)); streamer_write_uhwi (ob, gimple_asm_nlabels (asm_stmt)); streamer_write_string (ob, ob->main_stream, gimple_asm_string (asm_stmt), true); } /* 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 < gimple_num_ops (stmt); i++) { tree op = gimple_op (stmt, i); tree *basep = NULL; /* Wrap all uses of non-automatic variables inside MEM_REFs so that we do not have to deal with type mismatches on merged symbols during IL read in. The first operand of GIMPLE_DEBUG must be a decl, not MEM_REF, though. */ if (!flag_wpa && op && (i || !is_gimple_debug (stmt))) { basep = &op; if (TREE_CODE (*basep) == ADDR_EXPR) basep = &TREE_OPERAND (*basep, 0); while (handled_component_p (*basep)) basep = &TREE_OPERAND (*basep, 0); if (VAR_P (*basep) && !auto_var_in_fn_p (*basep, fn->decl) && !DECL_REGISTER (*basep)) { bool volatilep = TREE_THIS_VOLATILE (*basep); tree ptrtype = build_pointer_type (TREE_TYPE (*basep)); *basep = build2 (MEM_REF, TREE_TYPE (*basep), build1 (ADDR_EXPR, ptrtype, *basep), build_int_cst (ptrtype, 0)); TREE_THIS_VOLATILE (*basep) = volatilep; } else basep = NULL; } stream_write_tree (ob, op, true); /* Restore the original base if we wrapped it inside a MEM_REF. */ if (basep) *basep = TREE_OPERAND (TREE_OPERAND (*basep, 0), 0); } if (is_gimple_call (stmt)) { if (gimple_call_internal_p (stmt)) streamer_write_enum (ob->main_stream, internal_fn, IFN_LAST, gimple_call_internal_fn (stmt)); else stream_write_tree (ob, gimple_call_fntype (stmt), true); } break; case GIMPLE_NOP: case GIMPLE_PREDICT: break; case GIMPLE_TRANSACTION: { gtransaction *txn = as_a (stmt); gcc_assert (gimple_transaction_body (txn) == NULL); stream_write_tree (ob, gimple_transaction_label_norm (txn), true); stream_write_tree (ob, gimple_transaction_label_uninst (txn), true); stream_write_tree (ob, gimple_transaction_label_over (txn), true); } break; default: gcc_unreachable (); } if (hist) stream_out_histogram_value (ob, hist); } /* Output a basic block BB to the main stream in OB for this FN. */ void output_bb (struct output_block *ob, basic_block bb, struct function *fn) { gimple_stmt_iterator bsi = gsi_start_bb (bb); streamer_write_record_start (ob, (!gsi_end_p (bsi)) || phi_nodes (bb) ? LTO_bb1 : LTO_bb0); streamer_write_uhwi (ob, bb->index); bb->count.stream_out (ob); streamer_write_hwi (ob, bb->flags); streamer_write_hwi (ob, bb->discriminator); if (!gsi_end_p (bsi) || phi_nodes (bb)) { /* Output the statements. The list of statements is terminated with a zero. */ for (bsi = gsi_start_bb (bb); !gsi_end_p (bsi); gsi_next (&bsi)) { int region; gimple *stmt = gsi_stmt (bsi); if (streamer_dump_file) { fprintf (streamer_dump_file, " Streaming gimple stmt "); print_gimple_stmt (streamer_dump_file, stmt, 0, TDF_SLIM); } output_gimple_stmt (ob, fn, stmt); /* Emit the EH region holding STMT. */ region = lookup_stmt_eh_lp_fn (fn, stmt); if (region != 0) { streamer_write_record_start (ob, LTO_eh_region); streamer_write_hwi (ob, region); } else streamer_write_record_start (ob, LTO_null); } streamer_write_record_start (ob, LTO_null); for (gphi_iterator psi = gsi_start_phis (bb); !gsi_end_p (psi); gsi_next (&psi)) { gphi *phi = psi.phi (); /* Only emit PHIs for gimple registers. PHI nodes for .MEM will be filled in on reading when the SSA form is updated. */ if (!virtual_operand_p (gimple_phi_result (phi))) output_phi (ob, phi); } streamer_write_record_start (ob, LTO_null); } }