/* Infrastructure for tracking user variable locations and values
throughout compilation.
- Copyright (C) 2010, 2011, 2012 Free Software Foundation, Inc.
+ Copyright (C) 2010-2015 Free Software Foundation, Inc.
Contributed by Alexandre Oliva <aoliva@redhat.com>.
This file is part of GCC.
#include "coretypes.h"
#include "tm.h"
#include "rtl.h"
+#include "predict.h"
+#include "basic-block.h"
#include "valtrack.h"
+#include "hard-reg-set.h"
#include "function.h"
#include "regs.h"
#include "emit-rtl.h"
+/* gen_lowpart_no_emit hook implementation for DEBUG_INSNs. In DEBUG_INSNs,
+ all lowpart SUBREGs are valid, despite what the machine requires for
+ instructions. */
+
+static rtx
+gen_lowpart_for_debug (machine_mode mode, rtx x)
+{
+ rtx result = gen_lowpart_if_possible (mode, x);
+ if (result)
+ return result;
+
+ if (GET_MODE (x) != VOIDmode)
+ return gen_rtx_raw_SUBREG (mode, x,
+ subreg_lowpart_offset (mode, GET_MODE (x)));
+
+ return NULL_RTX;
+}
+
/* Replace auto-increment addressing modes with explicit operations to access
the same addresses without modifying the corresponding registers. */
static rtx
-cleanup_auto_inc_dec (rtx src, enum machine_mode mem_mode ATTRIBUTE_UNUSED)
+cleanup_auto_inc_dec (rtx src, machine_mode mem_mode ATTRIBUTE_UNUSED)
{
rtx x = src;
#ifdef AUTO_INC_DEC
/* SCRATCH must be shared because they represent distinct values. */
return x;
case CLOBBER:
- if (REG_P (XEXP (x, 0)) && REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER)
+ /* Share clobbers of hard registers (like cc0), but do not share pseudo reg
+ clobbers or clobbers of hard registers that originated as pseudos.
+ This is needed to allow safe register renaming. */
+ if (REG_P (XEXP (x, 0)) && REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER
+ && ORIGINAL_REGNO (XEXP (x, 0)) == REGNO (XEXP (x, 0)))
return x;
break;
gcc_assert (mem_mode != VOIDmode && mem_mode != BLKmode);
return gen_rtx_PLUS (GET_MODE (x),
cleanup_auto_inc_dec (XEXP (x, 0), mem_mode),
- GEN_INT (code == PRE_INC
- ? GET_MODE_SIZE (mem_mode)
- : -GET_MODE_SIZE (mem_mode)));
+ gen_int_mode (code == PRE_INC
+ ? GET_MODE_SIZE (mem_mode)
+ : -GET_MODE_SIZE (mem_mode),
+ GET_MODE (x)));
case POST_INC:
case POST_DEC:
of THIS_BASIC_BLOCK. */
void
-propagate_for_debug (rtx insn, rtx last, rtx dest, rtx src,
+propagate_for_debug (rtx_insn *insn, rtx_insn *last, rtx dest, rtx src,
basic_block this_basic_block)
{
- rtx next, loc, end = NEXT_INSN (BB_END (this_basic_block));
+ rtx_insn *next, *end = NEXT_INSN (BB_END (this_basic_block));
+ rtx loc;
+ rtx (*saved_rtl_hook_no_emit) (machine_mode, rtx);
struct rtx_subst_pair p;
p.to = src;
next = NEXT_INSN (insn);
last = NEXT_INSN (last);
+ saved_rtl_hook_no_emit = rtl_hooks.gen_lowpart_no_emit;
+ rtl_hooks.gen_lowpart_no_emit = gen_lowpart_for_debug;
while (next != last && next != end)
{
insn = next;
df_insn_rescan (insn);
}
}
+ rtl_hooks.gen_lowpart_no_emit = saved_rtl_hook_no_emit;
}
/* Initialize DEBUG to an empty list, and clear USED, if given. */
dead_debug_global_init (struct dead_debug_global *debug, bitmap used)
{
debug->used = used;
+ debug->htab = NULL;
if (used)
bitmap_clear (used);
}
dead_debug_global_entry temp_entry;
temp_entry.reg = reg;
- dead_debug_global_entry *entry = global->htab.find (&temp_entry);
+ dead_debug_global_entry *entry = global->htab->find (&temp_entry);
gcc_checking_assert (entry && entry->reg == temp_entry.reg);
return entry;
temp_entry.reg = reg;
temp_entry.dtemp = dtemp;
- if (!global->htab.is_created ())
- global->htab.create (31);
+ if (!global->htab)
+ global->htab = new hash_table<dead_debug_hash_descr> (31);
- dead_debug_global_entry **slot = global->htab.find_slot (&temp_entry, INSERT);
+ dead_debug_global_entry **slot = global->htab->find_slot (&temp_entry,
+ INSERT);
gcc_checking_assert (!*slot);
*slot = XNEW (dead_debug_global_entry);
**slot = temp_entry;
while (head)
{
struct dead_debug_use *next = head->next;
- rtx insn;
+ rtx_insn *insn;
insn = DF_REF_INSN (head->use);
if (!next || DF_REF_INSN (next->use) != insn)
if (!debug->global->used)
debug->global->used = BITMAP_ALLOC (NULL);
- if (bitmap_set_bit (debug->global->used, REGNO (reg)))
- entry = dead_debug_global_insert (debug->global, reg,
- make_debug_expr_from_rtl (reg));
+ bool added = bitmap_set_bit (debug->global->used, REGNO (reg));
+ gcc_checking_assert (added);
+
+ entry = dead_debug_global_insert (debug->global, reg,
+ make_debug_expr_from_rtl (reg));
gcc_checking_assert (entry->dtemp);
REGNO (reg),
&debug->to_rescan))
{
- rtx insn = DF_REF_INSN (ref);
+ rtx_insn *insn = DF_REF_INSN (ref);
INSN_VAR_LOCATION_LOC (insn) = gen_rtx_UNKNOWN_VAR_LOC ();
bitmap_set_bit (debug->to_rescan, INSN_UID (insn));
}
DEBUG_EXPR_TREE_DECL (entry->dtemp),
gen_rtx_UNKNOWN_VAR_LOC (),
VAR_INIT_STATUS_INITIALIZED);
- rtx insn = emit_debug_insn_before (bind, DF_REF_INSN (ref));
+ rtx_insn *insn = emit_debug_insn_before (bind, DF_REF_INSN (ref));
bitmap_set_bit (debug->to_rescan, INSN_UID (insn));
}
if (global->used != used)
BITMAP_FREE (global->used);
- if (global->htab.is_created ())
- global->htab.dispose ();
+ delete global->htab;
+ global->htab = NULL;
}
/* Add USE to DEBUG, or substitute it right away if it's a pseudo in
bitmap_set_bit (debug->used, uregno);
}
+/* Like lowpart_subreg, but if a subreg is not valid for machine, force
+ it anyway - for use in debug insns. */
+
+static rtx
+debug_lowpart_subreg (machine_mode outer_mode, rtx expr,
+ machine_mode inner_mode)
+{
+ if (inner_mode == VOIDmode)
+ inner_mode = GET_MODE (expr);
+ int offset = subreg_lowpart_offset (outer_mode, inner_mode);
+ rtx ret = simplify_gen_subreg (outer_mode, expr, inner_mode, offset);
+ if (ret)
+ return ret;
+ return gen_rtx_raw_SUBREG (outer_mode, expr, offset);
+}
+
/* If UREGNO is referenced by any entry in DEBUG, emit a debug insn
before or after INSN (depending on WHERE), that binds a (possibly
global) debug temp to the widest-mode use of UREGNO, if WHERE is
int
dead_debug_insert_temp (struct dead_debug_local *debug, unsigned int uregno,
- rtx insn, enum debug_temp_where where)
+ rtx_insn *insn, enum debug_temp_where where)
{
struct dead_debug_use **tailp = &debug->head;
struct dead_debug_use *cur;
the debug temp to. ??? We could bind the debug_expr to a
CONCAT or PARALLEL with the split multi-registers, and
replace them as we found the corresponding sets. */
- else if (REGNO (reg) < FIRST_PSEUDO_REGISTER
- && (hard_regno_nregs[REGNO (reg)][GET_MODE (reg)]
- != hard_regno_nregs[REGNO (reg)][GET_MODE (dest)]))
+ else if (REG_NREGS (reg) != REG_NREGS (dest))
breg = NULL;
/* Ok, it's the same (hardware) REG, but with a different
mode, so SUBREG it. */
else
- breg = lowpart_subreg (GET_MODE (reg),
- cleanup_auto_inc_dec (src, VOIDmode),
- GET_MODE (dest));
+ breg = debug_lowpart_subreg (GET_MODE (reg),
+ cleanup_auto_inc_dec (src, VOIDmode),
+ GET_MODE (dest));
}
else if (GET_CODE (dest) == SUBREG)
{
setting REG in its mode would, we won't know what to bind
the debug temp to. */
else if (REGNO (reg) < FIRST_PSEUDO_REGISTER
- && (hard_regno_nregs[REGNO (reg)][GET_MODE (reg)]
+ && (REG_NREGS (reg)
!= hard_regno_nregs[REGNO (reg)][GET_MODE (dest)]))
breg = NULL;
/* Yay, we can use SRC, just adjust its mode. */
else
- breg = lowpart_subreg (GET_MODE (reg),
- cleanup_auto_inc_dec (src, VOIDmode),
- GET_MODE (dest));
+ breg = debug_lowpart_subreg (GET_MODE (reg),
+ cleanup_auto_inc_dec (src, VOIDmode),
+ GET_MODE (dest));
}
/* Oh well, we're out of luck. */
else
probably doesn't make sense to introduce a new debug temp. */
if (where == DEBUG_TEMP_AFTER_WITH_REG && !uses->next)
{
- rtx next = DF_REF_INSN (uses->use);
+ rtx_insn *next = DF_REF_INSN (uses->use);
if (DEBUG_INSN_P (next) && reg == INSN_VAR_LOCATION_LOC (next))
{
DEBUG_EXPR_TREE_DECL (dval), breg,
VAR_INIT_STATUS_INITIALIZED);
- if (where == DEBUG_TEMP_AFTER_WITH_REG)
+ if (where == DEBUG_TEMP_AFTER_WITH_REG
+ || where == DEBUG_TEMP_AFTER_WITH_REG_FORCE)
bind = emit_debug_insn_after (bind, insn);
else
bind = emit_debug_insn_before (bind, insn);
*DF_REF_REAL_LOC (cur->use) = dval;
else
*DF_REF_REAL_LOC (cur->use)
- = gen_lowpart_SUBREG (GET_MODE (*DF_REF_REAL_LOC (cur->use)), dval);
+ = debug_lowpart_subreg (GET_MODE (*DF_REF_REAL_LOC (cur->use)), dval,
+ GET_MODE (dval));
/* ??? Should we simplify subreg of subreg? */
bitmap_set_bit (debug->to_rescan, INSN_UID (DF_REF_INSN (cur->use)));
uses = cur->next;