static unsigned get_relative_location_for_stmt (gimple *stmt) { location_t locus = gimple_location (stmt); if (LOCATION_LOCUS (locus) == UNKNOWN_LOCATION) return UNKNOWN_LOCATION; for (tree block = gimple_block (stmt); block && (TREE_CODE (block) == BLOCK); block = BLOCK_SUPERCONTEXT (block)) if (LOCATION_LOCUS (BLOCK_SOURCE_LOCATION (block)) != UNKNOWN_LOCATION) return get_combined_location (locus, get_function_decl_from_block (block)); return get_combined_location (locus, current_function_decl); }
static void set_location_for_edge (edge e) { if (e->goto_locus) { set_curr_insn_source_location (e->goto_locus); set_curr_insn_block (e->goto_block); } else { basic_block bb = e->src; gimple_stmt_iterator gsi; do { for (gsi = gsi_last_bb (bb); !gsi_end_p (gsi); gsi_prev (&gsi)) { gimple stmt = gsi_stmt (gsi); if (is_gimple_debug (stmt)) continue; if (gimple_has_location (stmt) || gimple_block (stmt)) { set_curr_insn_source_location (gimple_location (stmt)); set_curr_insn_block (gimple_block (stmt)); return; } } /* Nothing found in this basic block. Make a half-assed attempt to continue with another block. */ if (single_pred_p (bb)) bb = single_pred (bb); else bb = e->src; } while (bb != e->src); } }
static void lower_gimple_return (gimple_stmt_iterator *gsi, struct lower_data *data) { gimple stmt = gsi_stmt (*gsi); gimple t; int i; return_statements_t tmp_rs; /* Match this up with an existing return statement that's been created. */ for (i = data->return_statements.length () - 1; i >= 0; i--) { tmp_rs = data->return_statements[i]; if (gimple_return_retval (stmt) == gimple_return_retval (tmp_rs.stmt)) { /* Remove the line number from the representative return statement. It now fills in for many such returns. Failure to remove this will result in incorrect results for coverage analysis. */ gimple_set_location (tmp_rs.stmt, UNKNOWN_LOCATION); goto found; } } /* Not found. Create a new label and record the return statement. */ tmp_rs.label = create_artificial_label (cfun->function_end_locus); tmp_rs.stmt = stmt; data->return_statements.safe_push (tmp_rs); /* Generate a goto statement and remove the return statement. */ found: /* When not optimizing, make sure user returns are preserved. */ if (!optimize && gimple_has_location (stmt)) DECL_ARTIFICIAL (tmp_rs.label) = 0; t = gimple_build_goto (tmp_rs.label); gimple_set_location (t, gimple_location (stmt)); gimple_set_block (t, gimple_block (stmt)); gsi_insert_before (gsi, t, GSI_SAME_STMT); gsi_remove (gsi, false); }
static void output_gimple_stmt (struct output_block *ob, 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 (stmt), 1); bp_pack_value (&bp, gimple_has_volatile_ops (stmt), 1); hist = gimple_histogram_value (cfun, stmt); bp_pack_value (&bp, hist != NULL, 1); bp_pack_var_len_unsigned (&bp, stmt->gsbase.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 (stmt)); break; case GIMPLE_EH_MUST_NOT_THROW: stream_write_tree (ob, gimple_eh_must_not_throw_fndecl (stmt), true); break; case GIMPLE_EH_DISPATCH: streamer_write_hwi (ob, gimple_eh_dispatch_region (stmt)); break; case GIMPLE_ASM: streamer_write_uhwi (ob, gimple_asm_ninputs (stmt)); streamer_write_uhwi (ob, gimple_asm_noutputs (stmt)); streamer_write_uhwi (ob, gimple_asm_nclobbers (stmt)); streamer_write_uhwi (ob, gimple_asm_nlabels (stmt)); streamer_write_string (ob, ob->main_stream, gimple_asm_string (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 (op && (i || !is_gimple_debug (stmt))) { basep = &op; while (handled_component_p (*basep)) basep = &TREE_OPERAND (*basep, 0); if (TREE_CODE (*basep) == VAR_DECL && !auto_var_in_fn_p (*basep, current_function_decl) && !DECL_REGISTER (*basep)) { bool volatilep = TREE_THIS_VOLATILE (*basep); *basep = build2 (MEM_REF, TREE_TYPE (*basep), build_fold_addr_expr (*basep), build_int_cst (build_pointer_type (TREE_TYPE (*basep)), 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: gcc_assert (gimple_transaction_body (stmt) == NULL); stream_write_tree (ob, gimple_transaction_label (stmt), true); break; default: gcc_unreachable (); } if (hist) stream_out_histogram_value (ob, hist); }
static void lower_builtin_setjmp (gimple_stmt_iterator *gsi) { gimple stmt = gsi_stmt (*gsi); location_t loc = gimple_location (stmt); tree cont_label = create_artificial_label (loc); tree next_label = create_artificial_label (loc); tree dest, t, arg; gimple g; /* NEXT_LABEL is the label __builtin_longjmp will jump to. Its address is passed to both __builtin_setjmp_setup and __builtin_setjmp_receiver. */ FORCED_LABEL (next_label) = 1; dest = gimple_call_lhs (stmt); /* Build '__builtin_setjmp_setup (BUF, NEXT_LABEL)' and insert. */ arg = build_addr (next_label, current_function_decl); t = builtin_decl_implicit (BUILT_IN_SETJMP_SETUP); g = gimple_build_call (t, 2, gimple_call_arg (stmt, 0), arg); gimple_set_location (g, loc); gimple_set_block (g, gimple_block (stmt)); gsi_insert_before (gsi, g, GSI_SAME_STMT); /* Build 'DEST = 0' and insert. */ if (dest) { g = gimple_build_assign (dest, build_zero_cst (TREE_TYPE (dest))); gimple_set_location (g, loc); gimple_set_block (g, gimple_block (stmt)); gsi_insert_before (gsi, g, GSI_SAME_STMT); } /* Build 'goto CONT_LABEL' and insert. */ g = gimple_build_goto (cont_label); gsi_insert_before (gsi, g, GSI_SAME_STMT); /* Build 'NEXT_LABEL:' and insert. */ g = gimple_build_label (next_label); gsi_insert_before (gsi, g, GSI_SAME_STMT); /* Build '__builtin_setjmp_receiver (NEXT_LABEL)' and insert. */ arg = build_addr (next_label, current_function_decl); t = builtin_decl_implicit (BUILT_IN_SETJMP_RECEIVER); g = gimple_build_call (t, 1, arg); gimple_set_location (g, loc); gimple_set_block (g, gimple_block (stmt)); gsi_insert_before (gsi, g, GSI_SAME_STMT); /* Build 'DEST = 1' and insert. */ if (dest) { g = gimple_build_assign (dest, fold_convert_loc (loc, TREE_TYPE (dest), integer_one_node)); gimple_set_location (g, loc); gimple_set_block (g, gimple_block (stmt)); gsi_insert_before (gsi, g, GSI_SAME_STMT); } /* Build 'CONT_LABEL:' and insert. */ g = gimple_build_label (cont_label); gsi_insert_before (gsi, g, GSI_SAME_STMT); /* Remove the call to __builtin_setjmp. */ gsi_remove (gsi, false); }
static inline bool is_replaceable_p (gimple stmt) { use_operand_p use_p; tree def; gimple use_stmt; location_t locus1, locus2; tree block1, block2; /* Only consider modify stmts. */ if (!is_gimple_assign (stmt)) return false; /* If the statement may throw an exception, it cannot be replaced. */ if (stmt_could_throw_p (stmt)) return false; /* Punt if there is more than 1 def. */ def = SINGLE_SSA_TREE_OPERAND (stmt, SSA_OP_DEF); if (!def) return false; /* Only consider definitions which have a single use. */ if (!single_imm_use (def, &use_p, &use_stmt)) return false; /* If the use isn't in this block, it wont be replaced either. */ if (gimple_bb (use_stmt) != gimple_bb (stmt)) return false; locus1 = gimple_location (stmt); block1 = gimple_block (stmt); if (gimple_code (use_stmt) == GIMPLE_PHI) { locus2 = 0; block2 = NULL_TREE; } else { locus2 = gimple_location (use_stmt); block2 = gimple_block (use_stmt); } if (!optimize && ((locus1 && locus1 != locus2) || (block1 && block1 != block2))) return false; /* Used in this block, but at the TOP of the block, not the end. */ if (gimple_code (use_stmt) == GIMPLE_PHI) return false; /* There must be no VDEFs. */ if (!(ZERO_SSA_OPERANDS (stmt, SSA_OP_VDEF))) return false; /* Without alias info we can't move around loads. */ if (gimple_references_memory_p (stmt) && !optimize) return false; /* Float expressions must go through memory if float-store is on. */ if (flag_float_store && FLOAT_TYPE_P (gimple_expr_type (stmt))) return false; /* An assignment with a register variable on the RHS is not replaceable. */ if (gimple_assign_rhs_code (stmt) == VAR_DECL && DECL_HARD_REGISTER (gimple_assign_rhs1 (stmt))) return false; /* No function calls can be replaced. */ if (is_gimple_call (stmt)) return false; /* Leave any stmt with volatile operands alone as well. */ if (gimple_has_volatile_ops (stmt)) return false; return true; }
static void lower_builtin_setjmp (gimple_stmt_iterator *gsi) { gimple *stmt = gsi_stmt (*gsi); location_t loc = gimple_location (stmt); tree cont_label = create_artificial_label (loc); tree next_label = create_artificial_label (loc); tree dest, t, arg; gimple *g; /* __builtin_setjmp_{setup,receiver} aren't ECF_RETURNS_TWICE and for RTL these builtins are modelled as non-local label jumps to the label that is passed to these two builtins, so pretend we have a non-local label during GIMPLE passes too. See PR60003. */ cfun->has_nonlocal_label = 1; /* NEXT_LABEL is the label __builtin_longjmp will jump to. Its address is passed to both __builtin_setjmp_setup and __builtin_setjmp_receiver. */ FORCED_LABEL (next_label) = 1; tree orig_dest = dest = gimple_call_lhs (stmt); if (orig_dest && TREE_CODE (orig_dest) == SSA_NAME) dest = create_tmp_reg (TREE_TYPE (orig_dest)); /* Build '__builtin_setjmp_setup (BUF, NEXT_LABEL)' and insert. */ arg = build_addr (next_label); t = builtin_decl_implicit (BUILT_IN_SETJMP_SETUP); g = gimple_build_call (t, 2, gimple_call_arg (stmt, 0), arg); gimple_set_location (g, loc); gimple_set_block (g, gimple_block (stmt)); gsi_insert_before (gsi, g, GSI_SAME_STMT); /* Build 'DEST = 0' and insert. */ if (dest) { g = gimple_build_assign (dest, build_zero_cst (TREE_TYPE (dest))); gimple_set_location (g, loc); gimple_set_block (g, gimple_block (stmt)); gsi_insert_before (gsi, g, GSI_SAME_STMT); } /* Build 'goto CONT_LABEL' and insert. */ g = gimple_build_goto (cont_label); gsi_insert_before (gsi, g, GSI_SAME_STMT); /* Build 'NEXT_LABEL:' and insert. */ g = gimple_build_label (next_label); gsi_insert_before (gsi, g, GSI_SAME_STMT); /* Build '__builtin_setjmp_receiver (NEXT_LABEL)' and insert. */ arg = build_addr (next_label); t = builtin_decl_implicit (BUILT_IN_SETJMP_RECEIVER); g = gimple_build_call (t, 1, arg); gimple_set_location (g, loc); gimple_set_block (g, gimple_block (stmt)); gsi_insert_before (gsi, g, GSI_SAME_STMT); /* Build 'DEST = 1' and insert. */ if (dest) { g = gimple_build_assign (dest, fold_convert_loc (loc, TREE_TYPE (dest), integer_one_node)); gimple_set_location (g, loc); gimple_set_block (g, gimple_block (stmt)); gsi_insert_before (gsi, g, GSI_SAME_STMT); } /* Build 'CONT_LABEL:' and insert. */ g = gimple_build_label (cont_label); gsi_insert_before (gsi, g, GSI_SAME_STMT); /* Build orig_dest = dest if necessary. */ if (dest != orig_dest) { g = gimple_build_assign (orig_dest, dest); gsi_insert_before (gsi, g, GSI_SAME_STMT); } /* Remove the call to __builtin_setjmp. */ gsi_remove (gsi, false); }