if (inner_mode == VOIDmode)
{
- inner_mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
+ if (TREE_CODE (exp) == SSA_NAME)
+ inner_mode = TYPE_MODE (TREE_TYPE (exp));
+ else
+ inner_mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
if (mode == inner_mode)
return op0;
}
}
else if (FLOAT_MODE_P (mode))
{
+ gcc_assert (TREE_CODE (exp) != SSA_NAME);
if (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))))
op0 = simplify_gen_unary (UNSIGNED_FLOAT, mode, op0, inner_mode);
else
case SSA_NAME:
{
- int part = var_to_partition (SA.map, exp);
+ gimple g = get_gimple_for_ssa_name (exp);
+ if (g)
+ {
+ op0 = expand_debug_expr (gimple_assign_rhs_to_tree (g));
+ if (!op0)
+ return NULL;
+ }
+ else
+ {
+ int part = var_to_partition (SA.map, exp);
- if (part == NO_PARTITION)
- return NULL;
+ if (part == NO_PARTITION)
+ return NULL;
- gcc_assert (part >= 0 && (unsigned)part < SA.map->num_partitions);
+ gcc_assert (part >= 0 && (unsigned)part < SA.map->num_partitions);
- op0 = SA.partition_to_pseudo[part];
+ op0 = SA.partition_to_pseudo[part];
+ }
goto adjust_mode;
}
basic_block new_bb;
stmt = gsi_stmt (gsi);
+
+ /* If this statement is a non-debug one, and we generate debug
+ insns, then this one might be the last real use of a TERed
+ SSA_NAME, but where there are still some debug uses further
+ down. Expanding the current SSA name in such further debug
+ uses by their RHS might lead to wrong debug info, as coalescing
+ might make the operands of such RHS be placed into the same
+ pseudo as something else. Like so:
+ a_1 = a_0 + 1; // Assume a_1 is TERed and a_0 is dead
+ use(a_1);
+ a_2 = ...
+ #DEBUG ... => a_1
+ As a_0 and a_2 don't overlap in lifetime, assume they are coalesced.
+ If we now would expand a_1 by it's RHS (a_0 + 1) in the debug use,
+ the write to a_2 would actually have clobbered the place which
+ formerly held a_0.
+
+ So, instead of that, we recognize the situation, and generate
+ debug temporaries at the last real use of TERed SSA names:
+ a_1 = a_0 + 1;
+ #DEBUG #D1 => a_1
+ use(a_1);
+ a_2 = ...
+ #DEBUG ... => #D1
+ */
+ if (MAY_HAVE_DEBUG_INSNS
+ && SA.values
+ && !is_gimple_debug (stmt))
+ {
+ ssa_op_iter iter;
+ tree op;
+ gimple def;
+
+ location_t sloc = get_curr_insn_source_location ();
+ tree sblock = get_curr_insn_block ();
+
+ /* Look for SSA names that have their last use here (TERed
+ names always have only one real use). */
+ FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_USE)
+ if ((def = get_gimple_for_ssa_name (op)))
+ {
+ imm_use_iterator imm_iter;
+ use_operand_p use_p;
+ bool have_debug_uses = false;
+
+ FOR_EACH_IMM_USE_FAST (use_p, imm_iter, op)
+ {
+ if (gimple_debug_bind_p (USE_STMT (use_p)))
+ {
+ have_debug_uses = true;
+ break;
+ }
+ }
+
+ if (have_debug_uses)
+ {
+ /* OP is a TERed SSA name, with DEF it's defining
+ statement, and where OP is used in further debug
+ instructions. Generate a debug temporary, and
+ replace all uses of OP in debug insns with that
+ temporary. */
+ gimple debugstmt;
+ tree value = gimple_assign_rhs_to_tree (def);
+ tree vexpr = make_node (DEBUG_EXPR_DECL);
+ rtx val;
+ enum machine_mode mode;
+
+ set_curr_insn_source_location (gimple_location (def));
+ set_curr_insn_block (gimple_block (def));
+
+ DECL_ARTIFICIAL (vexpr) = 1;
+ TREE_TYPE (vexpr) = TREE_TYPE (value);
+ if (DECL_P (value))
+ mode = DECL_MODE (value);
+ else
+ mode = TYPE_MODE (TREE_TYPE (value));
+ DECL_MODE (vexpr) = mode;
+
+ val = gen_rtx_VAR_LOCATION
+ (mode, vexpr, (rtx)value, VAR_INIT_STATUS_INITIALIZED);
+
+ val = emit_debug_insn (val);
+
+ FOR_EACH_IMM_USE_STMT (debugstmt, imm_iter, op)
+ {
+ if (!gimple_debug_bind_p (debugstmt))
+ continue;
+
+ FOR_EACH_IMM_USE_ON_STMT (use_p, imm_iter)
+ SET_USE (use_p, vexpr);
+
+ update_stmt (debugstmt);
+ }
+ }
+ }
+ set_curr_insn_source_location (sloc);
+ set_curr_insn_block (sblock);
+ }
+
currently_expanding_gimple_stmt = stmt;
/* Expand this statement, then evaluate the resulting RTL and
INSN_VAR_LOCATION_LOC (val) = (rtx)value;
}
+ /* In order not to generate too many debug temporaries,
+ we delink all uses of debug statements we already expanded.
+ Therefore debug statements between definition and real
+ use of TERed SSA names will continue to use the SSA name,
+ and not be replaced with debug temps. */
+ delink_stmt_imm_use (stmt);
+
gsi = nsi;
gsi_next (&nsi);
if (gsi_end_p (nsi))
--- /dev/null
+/* PR debug/43077 */
+/* { dg-do run } */
+/* { dg-options "-g" } */
+
+int varb;
+
+int __attribute__((noinline))
+fn1 (void)
+{
+ int vara = (varb == 3); /* { dg-final { gdb-test 11 "vara" "0" } } */
+ asm volatile ("" : : "g" (vara)); /* { dg-final { gdb-test 11 "varb" "2" } } */
+ return 0;
+}
+
+int __attribute__((noinline))
+fn2 (void)
+{
+ int vara = (varb == 3); /* { dg-final { gdb-test 19 "vara" "1" } } */
+ asm volatile ("" : : "g" (vara)); /* { dg-final { gdb-test 19 "varb" "3" } } */
+ return 0;
+}
+
+int __attribute__((noinline))
+foo (unsigned long *p, unsigned long *q)
+{
+ int ret;
+ asm volatile ("" : "=r" (ret), "=r" (*p), "=r" (*q) : "0" (1), "1" (2), "2" (3));
+ return ret;
+}
+
+int __attribute__((noinline))
+fn3 (void)
+{
+ unsigned long a = 0, b = 0, c = 0;
+ a = foo (&b, &c);
+ /* { dg-final { gdb-test 42 "a" "1" } } */
+ /* { dg-final { gdb-test 42 "b" "2" } } */
+ /* { dg-final { gdb-test 42 "c" "3" } } */
+ unsigned long vara = a; /* { dg-final { gdb-test 42 "vara" "1" } } */
+ unsigned long varb = b; /* { dg-final { gdb-test 42 "varb" "2" } } */
+ unsigned long varc = c; /* { dg-final { gdb-test 42 "varc" "3" } } */
+ asm volatile ("" : : "g" (vara), "g" (varb), "g" (varc));
+ return a;
+}
+
+int
+main (void)
+{
+ asm volatile ("" : "=r" (varb) : "0" (2));
+ fn1 ();
+ asm volatile ("" : "=r" (varb) : "0" (3));
+ fn2 ();
+ fn3 ();
+ return 0;
+}