static gimple input_gimple_stmt (struct lto_input_block *ib, struct data_in *data_in, struct function *fn, enum LTO_tags tag) { gimple stmt; enum gimple_code code; unsigned HOST_WIDE_INT num_ops; size_t i; struct bitpack_d bp; 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->gsbase.no_warning = bp_unpack_value (&bp, 1); if (is_gimple_assign (stmt)) stmt->gsbase.nontemporal_move = bp_unpack_value (&bp, 1); stmt->gsbase.has_volatile_ops = bp_unpack_value (&bp, 1); stmt->gsbase.subcode = bp_unpack_var_len_unsigned (&bp); /* Read location information. */ gimple_set_location (stmt, lto_input_location (ib, 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 (stmt, streamer_read_hwi (ib)); break; case GIMPLE_EH_MUST_NOT_THROW: gimple_eh_must_not_throw_set_fndecl (stmt, stream_read_tree (ib, data_in)); break; case GIMPLE_EH_DISPATCH: gimple_eh_dispatch_set_region (stmt, streamer_read_hwi (ib)); break; case GIMPLE_ASM: { /* FIXME lto. Move most of this into a new gimple_asm_set_string(). */ tree str; stmt->gimple_asm.ni = streamer_read_uhwi (ib); stmt->gimple_asm.no = streamer_read_uhwi (ib); stmt->gimple_asm.nc = streamer_read_uhwi (ib); stmt->gimple_asm.nl = streamer_read_uhwi (ib); str = streamer_read_string_cst (data_in, ib); stmt->gimple_asm.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 op = stream_read_tree (ib, data_in); gimple_set_op (stmt, i, op); if (!op) continue; /* Fixup FIELD_DECLs in COMPONENT_REFs, they are not handled by decl merging. */ if (TREE_CODE (op) == ADDR_EXPR) op = TREE_OPERAND (op, 0); while (handled_component_p (op)) { if (TREE_CODE (op) == COMPONENT_REF) { tree field, type, tem; tree closest_match = NULL_TREE; field = TREE_OPERAND (op, 1); type = DECL_CONTEXT (field); for (tem = TYPE_FIELDS (type); tem; tem = TREE_CHAIN (tem)) { if (TREE_CODE (tem) != FIELD_DECL) continue; if (tem == field) break; if (DECL_NONADDRESSABLE_P (tem) == DECL_NONADDRESSABLE_P (field) && gimple_compare_field_offset (tem, field)) { if (types_compatible_p (TREE_TYPE (tem), TREE_TYPE (field))) break; else closest_match = tem; } } /* In case of type mismatches across units we can fail to unify some types and thus not find a proper field-decl here. */ if (tem == NULL_TREE) { /* Thus, emit a ODR violation warning. */ if (warning_at (gimple_location (stmt), 0, "use of type %<%E%> with two mismatching " "declarations at field %<%E%>", type, TREE_OPERAND (op, 1))) { if (TYPE_FIELDS (type)) inform (DECL_SOURCE_LOCATION (TYPE_FIELDS (type)), "original type declared here"); inform (DECL_SOURCE_LOCATION (TREE_OPERAND (op, 1)), "field in mismatching type declared here"); if (TYPE_NAME (TREE_TYPE (field)) && (TREE_CODE (TYPE_NAME (TREE_TYPE (field))) == TYPE_DECL)) inform (DECL_SOURCE_LOCATION (TYPE_NAME (TREE_TYPE (field))), "type of field declared here"); if (closest_match && TYPE_NAME (TREE_TYPE (closest_match)) && (TREE_CODE (TYPE_NAME (TREE_TYPE (closest_match))) == TYPE_DECL)) inform (DECL_SOURCE_LOCATION (TYPE_NAME (TREE_TYPE (closest_match))), "type of mismatching field declared here"); } /* And finally fixup the types. */ TREE_OPERAND (op, 0) = build1 (VIEW_CONVERT_EXPR, type, TREE_OPERAND (op, 0)); } else TREE_OPERAND (op, 1) = tem; } op = TREE_OPERAND (op, 0); } } if (is_gimple_call (stmt)) { if (gimple_call_internal_p (stmt)) gimple_call_set_internal_fn (stmt, streamer_read_enum (ib, internal_fn, IFN_LAST)); else gimple_call_set_fntype (stmt, stream_read_tree (ib, data_in)); } break; case GIMPLE_NOP: case GIMPLE_PREDICT: break; case GIMPLE_TRANSACTION: gimple_transaction_set_label (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_LABEL) gcc_assert (emit_label_in_global_context_p (gimple_label_label (stmt)) || DECL_CONTEXT (gimple_label_label (stmt)) == fn->decl); else if (code == GIMPLE_ASM) { unsigned i; for (i = 0; i < gimple_asm_noutputs (stmt); i++) { tree op = TREE_VALUE (gimple_asm_output_op (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 (stmt); /* Mark the statement modified so its operand vectors can be filled in. */ gimple_set_modified (stmt, true); return stmt; }
tree streamer_alloc_tree (struct lto_input_block *ib, struct data_in *data_in, enum LTO_tags tag) { enum tree_code code; tree result; #ifdef LTO_STREAMER_DEBUG HOST_WIDE_INT orig_address_in_writer; #endif result = NULL_TREE; #ifdef LTO_STREAMER_DEBUG /* Read the word representing the memory address for the tree as it was written by the writer. This is useful when debugging differences between the writer and reader. */ orig_address_in_writer = streamer_read_hwi (ib); gcc_assert ((intptr_t) orig_address_in_writer == orig_address_in_writer); #endif code = lto_tag_to_tree_code (tag); /* We should never see an SSA_NAME tree. Only the version numbers of SSA names are ever written out. See input_ssa_names. */ gcc_assert (code != SSA_NAME); /* Instantiate a new tree using the header data. */ if (CODE_CONTAINS_STRUCT (code, TS_STRING)) result = streamer_read_string_cst (data_in, ib); else if (CODE_CONTAINS_STRUCT (code, TS_IDENTIFIER)) result = input_identifier (data_in, ib); else if (CODE_CONTAINS_STRUCT (code, TS_VEC)) { HOST_WIDE_INT len = streamer_read_hwi (ib); result = make_tree_vec (len); } else if (CODE_CONTAINS_STRUCT (code, TS_VECTOR)) { HOST_WIDE_INT len = streamer_read_hwi (ib); result = make_vector (len); } else if (CODE_CONTAINS_STRUCT (code, TS_BINFO)) { unsigned HOST_WIDE_INT len = streamer_read_uhwi (ib); result = make_tree_binfo (len); } else if (CODE_CONTAINS_STRUCT (code, TS_INT_CST)) { unsigned HOST_WIDE_INT len = streamer_read_uhwi (ib); unsigned HOST_WIDE_INT ext_len = streamer_read_uhwi (ib); result = make_int_cst (len, ext_len); } else if (code == CALL_EXPR) { unsigned HOST_WIDE_INT nargs = streamer_read_uhwi (ib); return build_vl_exp (CALL_EXPR, nargs + 3); } else if (code == OMP_CLAUSE) { enum omp_clause_code subcode = (enum omp_clause_code) streamer_read_uhwi (ib); return build_omp_clause (UNKNOWN_LOCATION, subcode); } else { /* For all other nodes, materialize the tree with a raw make_node call. */ result = make_node (code); } #ifdef LTO_STREAMER_DEBUG /* Store the original address of the tree as seen by the writer in RESULT's aux field. This is useful when debugging streaming problems. This way, a debugging session can be started on both writer and reader with a breakpoint using this address value in both. */ lto_orig_address_map (result, (intptr_t) orig_address_in_writer); #endif return result; }
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 (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; }