From patchwork Thu May 28 12:06:37 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Martin Jambor X-Patchwork-Id: 1299739 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=sourceware.org; envelope-from=gcc-patches-bounces@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=suse.cz Received: from sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 49Xn2d08Fpz9sSF for ; Thu, 28 May 2020 22:24:57 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 61338397A4AB; Thu, 28 May 2020 12:24:39 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mx2.suse.de (mx2.suse.de [195.135.220.15]) by sourceware.org (Postfix) with ESMTPS id EAE6139730C2 for ; Thu, 28 May 2020 12:24:34 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org EAE6139730C2 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=suse.cz Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=mjambor@suse.cz X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.220.254]) by mx2.suse.de (Postfix) with ESMTP id 7FE16ACE3 for ; Thu, 28 May 2020 12:24:33 +0000 (UTC) Resent-From: Martin Jambor Resent-Date: Thu, 28 May 2020 14:24:33 +0200 Resent-Message-ID: <20200528122433.GD22804@alvy> Resent-To: GCC Patches Message-Id: In-Reply-To: References: From: Martin Jambor Date: Thu, 28 May 2020 14:06:37 +0200 Subject: [PATCH 3/4] ipa-sra: Improve debug info for removed parameters (PR 93385) To: GCC Patches X-Spam-Status: No, score=-3043.3 required=5.0 tests=BAYES_00, GIT_PATCH_0, KAM_DMARC_STATUS, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Richard Biener , Jan Hubicka Errors-To: gcc-patches-bounces@gcc.gnu.org Sender: "Gcc-patches" Whereas the previous patch fixed issues with code left behind after IPA-SRA removed a parameter but only reset all affected debug bind statements, this one updates them with expressions which can allow the debugger to print the removed value - see the added test-case. Even though I originally did not want to create DEBUG_EXPR_DECLs for intermediate values, I ended up doing so, because otherwise the code started creating statements like # DEBUG __aD.198693 => &MEM[(const struct _Alloc_nodeD.171110 *)D#195]._M_tD.184726->_M_implD.171154 which not only is a bit scary but gimple-fold also ICEs on it. Therefore I decided they are probably quite necessary and have them. The patch simply notes each removed SSA name present in a debug statement and then works from it backwards, looking if it can reconstruct the expression it represents (which can fail if a non-degenerate PHI node is in the way). If it can, it populates two hash maps with those expressions so that 1) removed assignments are replaced with a debug bind defining a new intermediate debug_decl_expr and 2) existing debug binds that refer to SSA names that are bing removed now refer to corresponding debug_decl_exprs. If a removed parameter is passed to another function, the debugging information still cannot describe its value there - see the xfailed test in the testcase. This will is addressed in the following patch which removes the xfail. --- gcc/ipa-param-manipulation.c | 271 ++++++++++++++++++----- gcc/ipa-param-manipulation.h | 12 +- gcc/testsuite/gcc.dg/guality/ipa-sra-1.c | 45 ++++ gcc/tree-inline.c | 45 ++-- 4 files changed, 302 insertions(+), 71 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/guality/ipa-sra-1.c diff --git a/gcc/ipa-param-manipulation.c b/gcc/ipa-param-manipulation.c index 1f47f3a4268..0a265e26c4f 100644 --- a/gcc/ipa-param-manipulation.c +++ b/gcc/ipa-param-manipulation.c @@ -40,6 +40,8 @@ along with GCC; see the file COPYING3. If not see #include "builtins.h" #include "tree-ssa.h" #include "tree-inline.h" +#include "tree-phinodes.h" +#include "cfgexpand.h" /* Actual prefixes of different newly synthetized parameters. Keep in sync @@ -979,7 +981,8 @@ phi_arg_will_live_p (gphi *phi, bitmap blocks_to_copy, tree arg) any replacement or splitting. */ void -ipa_param_body_adjustments::mark_dead_statements (tree dead_param) +ipa_param_body_adjustments::mark_dead_statements (tree dead_param, + vec *debugstack) { if (!is_gimple_reg (dead_param)) return; @@ -988,6 +991,7 @@ ipa_param_body_adjustments::mark_dead_statements (tree dead_param) return; auto_vec stack; + hash_set used_in_debug; m_dead_ssas.add (parm_ddef); stack.safe_push (parm_ddef); while (!stack.is_empty ()) @@ -1010,6 +1014,11 @@ ipa_param_body_adjustments::mark_dead_statements (tree dead_param) { m_dead_stmts.add (stmt); gcc_assert (gimple_debug_bind_p (stmt)); + if (!used_in_debug.contains (t)) + { + used_in_debug.add (t); + debugstack->safe_push (t); + } } else if (gimple_code (stmt) == GIMPLE_PHI) { @@ -1044,6 +1053,155 @@ ipa_param_body_adjustments::mark_dead_statements (tree dead_param) gcc_unreachable (); } } + + if (!MAY_HAVE_DEBUG_STMTS) + { + gcc_assert (debugstack->is_empty ()); + return; + } + + tree dp_ddecl = make_node (DEBUG_EXPR_DECL); + DECL_ARTIFICIAL (dp_ddecl) = 1; + TREE_TYPE (dp_ddecl) = TREE_TYPE (dead_param); + SET_DECL_MODE (dp_ddecl, DECL_MODE (dead_param)); + m_dead_ssa_debug_equiv.put (parm_ddef, dp_ddecl); +} + +/* Callback to walk_tree. If REMAP is an SSA_NAME that is present in hash_map + passed in DATA, replace it with unshared version of what it was mapped + to. */ + +static tree +replace_with_mapped_expr (tree *remap, int *walk_subtrees, void *data) +{ + if (TYPE_P (*remap)) + { + *walk_subtrees = 0; + return 0; + } + if (TREE_CODE (*remap) != SSA_NAME) + return 0; + + *walk_subtrees = 0; + + hash_map *equivs = (hash_map *) data; + if (tree *p = equivs->get (*remap)) + *remap = unshare_expr (*p); + return 0; +} + +/* Replace all occurances of SSAs in m_dead_ssa_debug_equiv in t with what they + are mapped to. */ + +void +ipa_param_body_adjustments::remap_with_debug_expressions (tree *t) +{ + /* If *t is an SSA_NAME which should have its debug statements reset, it is + mapped to NULL in the hash_map. We need to handle that case separately or + otherwise the walker would segfault. No expression that is more + complicated than that can have its operands mapped to NULL. */ + if (TREE_CODE (*t) == SSA_NAME) + { + if (tree *p = m_dead_ssa_debug_equiv.get (*t)) + *t = *p; + } + else + walk_tree (t, replace_with_mapped_expr, &m_dead_ssa_debug_equiv, NULL); +} + +/* For an SSA_NAME DEAD_SSA which is about to be DCEd because it is based on a + useless parameter, prepare an expression that should represent it in + debug_binds in the cloned function and add a mapping from DEAD_SSA to + m_dead_ssa_debug_equiv. That mapping is to NULL when the associated + debug_statement has to be reset instead. In such case return false, + ottherwise return true. If DEAD_SSA comes from a basic block which is not + about to be copied, ignore it and return true. */ + +bool +ipa_param_body_adjustments::prepare_debug_expressions (tree dead_ssa) +{ + gcc_checking_assert (m_dead_ssas.contains (dead_ssa)); + if (tree *d = m_dead_ssa_debug_equiv.get (dead_ssa)) + return (*d != NULL_TREE); + + gcc_assert (!SSA_NAME_IS_DEFAULT_DEF (dead_ssa)); + gimple *def = SSA_NAME_DEF_STMT (dead_ssa); + if (m_id->blocks_to_copy + && !bitmap_bit_p (m_id->blocks_to_copy, gimple_bb (def)->index)) + return true; + + if (gimple_code (def) == GIMPLE_PHI) + { + /* In theory, we could ignore all SSAs coming from BBs not in + m_id->blocks_to_copy but at the time of the writing this code that + should never really be the case because only fnsplit uses that bitmap, + so don't bother. */ + tree value = degenerate_phi_result (as_a (def)); + if (!value + || (m_dead_ssas.contains (value) + && !prepare_debug_expressions (value))) + { + m_dead_ssa_debug_equiv.put (dead_ssa, NULL_TREE); + return false; + } + + /* PHI operand can be either an invariant or an SSA_NAME, but we are + looking at a degenarete phi node having value from a removed + parameter, so it has to be the latter. */ + gcc_assert (TREE_CODE (value) == SSA_NAME); + + tree *d = m_dead_ssa_debug_equiv.get (value); + m_dead_ssa_debug_equiv.put (dead_ssa, *d); + return true; + } + + bool lost = false; + use_operand_p use_p; + ssa_op_iter oi; + FOR_EACH_PHI_OR_STMT_USE (use_p, def, oi, SSA_OP_USE) + { + tree use = USE_FROM_PTR (use_p); + if (m_dead_ssas.contains (use) + && !prepare_debug_expressions (use)) + { + lost = true; + break; + } + } + + if (lost) + { + m_dead_ssa_debug_equiv.put (dead_ssa, NULL_TREE); + return false; + } + + if (is_gimple_assign (def)) + { + gcc_checking_assert (!gimple_clobber_p (def) + && gimple_assign_lhs (def) == dead_ssa); + + if (gimple_assign_copy_p (def) + && TREE_CODE (gimple_assign_rhs1 (def)) == SSA_NAME) + { + tree *d = m_dead_ssa_debug_equiv.get (gimple_assign_rhs1 (def)); + m_dead_ssa_debug_equiv.put (dead_ssa, *d); + return (*d != NULL_TREE); + } + + tree val = gimple_assign_rhs_to_tree (def); + SET_EXPR_LOCATION (val, UNKNOWN_LOCATION); + remap_with_debug_expressions (&val); + + tree vexpr = make_node (DEBUG_EXPR_DECL); + DECL_ARTIFICIAL (vexpr) = 1; + TREE_TYPE (vexpr) = TREE_TYPE (val); + SET_DECL_MODE (vexpr, TYPE_MODE (TREE_TYPE (val))); + m_dead_stmt_debug_equiv.put (def, val); + m_dead_ssa_debug_equiv.put (dead_ssa, vexpr); + return true; + } + else + gcc_unreachable (); } /* Common initialization performed by all ipa_param_body_adjustments @@ -1161,6 +1319,30 @@ ipa_param_body_adjustments::common_initialization (tree old_fndecl, gcc_unreachable (); } + if (tree_map) + { + /* Do not treat parameters which were replaced with a constant as + completely vanished. */ + auto_vec index_mapping; + bool need_remap = false; + + if (m_id && m_id->src_node->clone.param_adjustments) + { + ipa_param_adjustments *prev_adjustments + = m_id->src_node->clone.param_adjustments; + prev_adjustments->get_updated_indices (&index_mapping); + need_remap = true; + } + + for (unsigned i = 0; i < tree_map->length (); i++) + { + int parm_num = (*tree_map)[i]->parm_num; + gcc_assert (parm_num >= 0); + if (need_remap) + parm_num = index_mapping[parm_num]; + kept[parm_num] = true; + } + } /* As part of body modifications, we will also have to replace remaining uses of remaining uses of removed PARM_DECLs (which do not however use the @@ -1173,70 +1355,43 @@ ipa_param_body_adjustments::common_initialization (tree old_fndecl, replace_removed_params_ssa_names or perform_cfun_body_modifications when you construct with ID not equal to NULL. */ + auto_vec ssas_to_process_debug; unsigned op_len = m_oparms.length (); for (unsigned i = 0; i < op_len; i++) if (!kept[i]) { if (m_id) { - if (!m_id->decl_map->get (m_oparms[i])) - { - /* TODO: Perhaps at least aggregate-type params could re-use - their isra_dummy_decl here? */ - tree var = copy_decl_to_var (m_oparms[i], m_id); - insert_decl_map (m_id, m_oparms[i], var); - /* Declare this new variable. */ - DECL_CHAIN (var) = *vars; - *vars = var; - - /* If this is not a split but a real removal, init hash sets - that will guide what not to copy to the new body. */ - if (!isra_dummy_decls[i]) - mark_dead_statements (m_oparms[i]); - } + gcc_assert (!m_id->decl_map->get (m_oparms[i])); + /* TODO: Perhaps at least aggregate-type params could re-use + their isra_dummy_decl here? */ + tree var = copy_decl_to_var (m_oparms[i], m_id); + insert_decl_map (m_id, m_oparms[i], var); + /* Declare this new variable. */ + DECL_CHAIN (var) = *vars; + *vars = var; + + /* If this is not a split but a real removal, init hash sets + that will guide what not to copy to the new body. */ + if (!isra_dummy_decls[i]) + mark_dead_statements (m_oparms[i], &ssas_to_process_debug); + if (MAY_HAVE_DEBUG_STMTS + && is_gimple_reg (m_oparms[i])) + m_reset_debug_decls.safe_push (m_oparms[i]); } else { m_removed_decls.safe_push (m_oparms[i]); m_removed_map.put (m_oparms[i], m_removed_decls.length () - 1); + if (MAY_HAVE_DEBUG_STMTS + && !kept[i] + && is_gimple_reg (m_oparms[i])) + m_reset_debug_decls.safe_push (m_oparms[i]); } } - if (!MAY_HAVE_DEBUG_STMTS) - return; - - /* Finally, when generating debug info, we fill vector m_reset_debug_decls - with removed parameters declarations. We do this in order to re-map their - debug bind statements and create debug decls for them. */ - - if (tree_map) - { - /* Do not output debuginfo for parameter declarations as if they vanished - when they were in fact replaced by a constant. */ - auto_vec index_mapping; - bool need_remap = false; - - if (m_id && m_id->src_node->clone.param_adjustments) - { - ipa_param_adjustments *prev_adjustments - = m_id->src_node->clone.param_adjustments; - prev_adjustments->get_updated_indices (&index_mapping); - need_remap = true; - } - - for (unsigned i = 0; i < tree_map->length (); i++) - { - int parm_num = (*tree_map)[i]->parm_num; - gcc_assert (parm_num >= 0); - if (need_remap) - parm_num = index_mapping[parm_num]; - kept[parm_num] = true; - } - } - - for (unsigned i = 0; i < op_len; i++) - if (!kept[i] && is_gimple_reg (m_oparms[i])) - m_reset_debug_decls.safe_push (m_oparms[i]); + while (!ssas_to_process_debug.is_empty ()) + prepare_debug_expressions (ssas_to_process_debug.pop ()); } /* Constructor of ipa_param_body_adjustments from a simple list of @@ -1250,9 +1405,9 @@ ipa_param_body_adjustments tree fndecl) : m_adj_params (adj_params), m_adjustments (NULL), m_reset_debug_decls (), m_split_modifications_p (false), m_dead_stmts (), m_dead_ssas (), - m_fndecl (fndecl), m_id (NULL), m_oparms (), m_new_decls (), - m_new_types (), m_replacements (), m_removed_decls (), m_removed_map (), - m_method2func (false) + m_dead_ssa_debug_equiv (), m_dead_stmt_debug_equiv (), m_fndecl (fndecl), + m_id (NULL), m_oparms (), m_new_decls (), m_new_types (), m_replacements (), + m_removed_decls (), m_removed_map (), m_method2func (false) { common_initialization (fndecl, NULL, NULL); } @@ -1267,7 +1422,8 @@ ipa_param_body_adjustments tree fndecl) : m_adj_params (adjustments->m_adj_params), m_adjustments (adjustments), m_reset_debug_decls (), m_split_modifications_p (false), m_dead_stmts (), - m_dead_ssas (), m_fndecl (fndecl), m_id (NULL), m_oparms (), m_new_decls (), + m_dead_ssas (), m_dead_ssa_debug_equiv (), m_dead_stmt_debug_equiv (), + m_fndecl (fndecl), m_id (NULL), m_oparms (), m_new_decls (), m_new_types (), m_replacements (), m_removed_decls (), m_removed_map (), m_method2func (false) { @@ -1290,8 +1446,9 @@ ipa_param_body_adjustments vec *tree_map) : m_adj_params (adjustments->m_adj_params), m_adjustments (adjustments), m_reset_debug_decls (), m_split_modifications_p (false), m_dead_stmts (), - m_dead_ssas (),m_fndecl (fndecl), m_id (id), m_oparms (), m_new_decls (), - m_new_types (), m_replacements (), m_removed_decls (), m_removed_map (), + m_dead_ssas (), m_dead_ssa_debug_equiv (), m_dead_stmt_debug_equiv (), + m_fndecl (fndecl), m_id (id), m_oparms (), m_new_decls (), m_new_types (), + m_replacements (), m_removed_decls (), m_removed_map (), m_method2func (false) { common_initialization (old_fndecl, vars, tree_map); diff --git a/gcc/ipa-param-manipulation.h b/gcc/ipa-param-manipulation.h index 59060ae5dcc..240cc1583ea 100644 --- a/gcc/ipa-param-manipulation.h +++ b/gcc/ipa-param-manipulation.h @@ -356,6 +356,9 @@ public: bool modify_gimple_stmt (gimple **stmt, gimple_seq *extra_stmts); /* Return the new chain of parameters. */ tree get_new_param_chain (); + /* Replace all occurances of SSAs in m_dead_ssa_debug_equiv in t with what + they are mapped to. */ + void remap_with_debug_expressions (tree *t); /* Pointers to data structures defining how the function should be modified. */ @@ -376,6 +379,12 @@ public: hash_set m_dead_stmts; hash_set m_dead_ssas; + /* Mapping from DCEd SSAs to what their potential debug_binds should be. */ + hash_map m_dead_ssa_debug_equiv; + /* Mapping from DCEd statements to debug expressions that will be placed on + the RHS of debug statement that will replace this one. */ + hash_map m_dead_stmt_debug_equiv; + private: void common_initialization (tree old_fndecl, tree *vars, vec *tree_map); @@ -389,7 +398,8 @@ private: bool modify_call_stmt (gcall **stmt_p); bool modify_cfun_body (); void reset_debug_stmts (); - void mark_dead_statements (tree dead_param); + void mark_dead_statements (tree dead_param, vec *debugstack); + bool prepare_debug_expressions (tree dead_ssa); tree get_removed_call_arg_placeholder (tree arg); /* Declaration of the function that is being transformed. */ diff --git a/gcc/testsuite/gcc.dg/guality/ipa-sra-1.c b/gcc/testsuite/gcc.dg/guality/ipa-sra-1.c new file mode 100644 index 00000000000..5434b3d7665 --- /dev/null +++ b/gcc/testsuite/gcc.dg/guality/ipa-sra-1.c @@ -0,0 +1,45 @@ +/* { dg-do run } */ +/* { dg-options "-g -fno-ipa-icf" } */ + + +void __attribute__((noipa)) +use (int x) +{ + asm volatile ("" : : "r" (x) : "memory"); +} + +static int __attribute__((noinline)) +bar (int i, int k) +{ + asm ("" : "+r" (i)); + use (i); /* { dg-final { gdb-test . "k" "3" { xfail *-*-* } } } */ + return 6; +} + +volatile int v; + +static int __attribute__((noinline)) +foo (int i, int k) +{ + int r; + v = 9; + k = (k + 14)/k; + r = bar (i, k); /* { dg-final { gdb-test . "k" "3" } } */ + return r; +} + +volatile int v; + +int __attribute__((noipa)) +get_val1 (void) {return 20;} +int __attribute__((noipa)) +get_val2 (void) {return 7;} + +int +main (void) +{ + int k = get_val2 (); + int r = foo (get_val1 (), k); + v = r + k; /* k has to live accross the call or all is probably lost */ + return 0; +} diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c index 60087dd5e7b..33995eaa9b5 100644 --- a/gcc/tree-inline.c +++ b/gcc/tree-inline.c @@ -1527,7 +1527,21 @@ remap_gimple_stmt (gimple *stmt, copy_body_data *id) if (!is_gimple_debug (stmt) && id->param_body_adjs && id->param_body_adjs->m_dead_stmts.contains (stmt)) - return NULL; + { + tree *dval = id->param_body_adjs->m_dead_stmt_debug_equiv.get (stmt); + if (!dval) + return NULL; + + gcc_assert (is_gimple_assign (stmt)); + tree lhs = gimple_assign_lhs (stmt); + tree *dvar = id->param_body_adjs->m_dead_ssa_debug_equiv.get (lhs); + gdebug *bind = gimple_build_debug_bind (*dvar, *dval, stmt); + if (id->reset_location) + gimple_set_location (bind, input_location); + id->debug_stmts.safe_push (bind); + gimple_seq_add_stmt (&stmts, bind); + return stmts; + } /* Begin by recognizing trees that we'll completely rewrite for the inlining context. Our output for these trees is completely @@ -1793,15 +1807,13 @@ remap_gimple_stmt (gimple *stmt, copy_body_data *id) if (gimple_debug_bind_p (stmt)) { - tree value; + tree var = gimple_debug_bind_get_var (stmt); + tree value = gimple_debug_bind_get_value (stmt); if (id->param_body_adjs && id->param_body_adjs->m_dead_stmts.contains (stmt)) - value = NULL_TREE; - else - value = gimple_debug_bind_get_value (stmt); - gdebug *copy - = gimple_build_debug_bind (gimple_debug_bind_get_var (stmt), - value, stmt); + id->param_body_adjs->remap_with_debug_expressions (&value); + + gdebug *copy = gimple_build_debug_bind (var, value, stmt); if (id->reset_location) gimple_set_location (copy, input_location); id->debug_stmts.safe_push (copy); @@ -6468,7 +6480,6 @@ tree_function_versioning (tree old_decl, tree new_decl, in the debug info that var (whole DECL_ORIGIN is the parm PARM_DECL) is optimized away, but could be looked up at the call site as value of D#X there. */ - tree vexpr; gimple_stmt_iterator cgsi = gsi_after_labels (single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun))); gimple *def_temp; @@ -6476,17 +6487,25 @@ tree_function_versioning (tree old_decl, tree new_decl, i = vec_safe_length (*debug_args); do { + tree vexpr = NULL_TREE; i -= 2; while (var != NULL_TREE && DECL_ABSTRACT_ORIGIN (var) != (**debug_args)[i]) var = TREE_CHAIN (var); if (var == NULL_TREE) break; - vexpr = make_node (DEBUG_EXPR_DECL); tree parm = (**debug_args)[i]; - DECL_ARTIFICIAL (vexpr) = 1; - TREE_TYPE (vexpr) = TREE_TYPE (parm); - SET_DECL_MODE (vexpr, DECL_MODE (parm)); + if (tree parm_ddef = ssa_default_def (id.src_cfun, parm)) + if (tree *d + = param_body_adjs->m_dead_ssa_debug_equiv.get (parm_ddef)) + vexpr = *d; + if (!vexpr) + { + vexpr = make_node (DEBUG_EXPR_DECL); + DECL_ARTIFICIAL (vexpr) = 1; + TREE_TYPE (vexpr) = TREE_TYPE (parm); + SET_DECL_MODE (vexpr, DECL_MODE (parm)); + } def_temp = gimple_build_debug_bind (var, vexpr, NULL); gsi_insert_before (&cgsi, def_temp, GSI_NEW_STMT); def_temp = gimple_build_debug_source_bind (vexpr, parm, NULL);