aboutsummaryrefslogtreecommitdiff
path: root/gcc/regclass.c
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2007-02-01 01:09:35 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2007-02-01 01:09:35 +0000
commite53a16e75f3cbaaa46e5ce2fc1ed449a18eef7d9 (patch)
treeef18ae23759d8cebf30524fd23a40023979adb9e /gcc/regclass.c
parent15c48c45f552564d65a3cc869b2a8f896492f05f (diff)
downloadgcc-e53a16e75f3cbaaa46e5ce2fc1ed449a18eef7d9.zip
gcc-e53a16e75f3cbaaa46e5ce2fc1ed449a18eef7d9.tar.gz
gcc-e53a16e75f3cbaaa46e5ce2fc1ed449a18eef7d9.tar.bz2
lower-subreg.c: New file.
gcc/: * lower-subreg.c: New file. * rtl.def (CONCATN): Define. * passes.c (init_optimization_passes): Add pass_lower_subreg and pass_lower_subreg2. * emit-rtl.c (update_reg_offset): New static function, broken out of gen_rtx_REG_offset. (gen_rtx_REG_offset): Call update_reg_offset. (gen_reg_rtx_offset): New function. * regclass.c: Revert patch of 2006-03-05, restoring reg_scan_update. (clear_reg_info_regno): New function. * dwarf2out.c (concatn_loc_descriptor): New static function. (loc_descriptor): Handle CONCATN. * common.opt (fsplit_wide_types): New option. * opts.c (decode_options): Set flag_split_wide_types when optimizing. * timevar.def (TV_LOWER_SUBREG): Define. * rtl.h (gen_reg_rtx_offset): Declare. (reg_scan_update): Declare. * regs.h (clear_reg_info_regno): Declare. * tree-pass.h (pass_lower_subreg): Declare. (pass_lower_subreg2): Declare. * doc/invoke.texi (Option Summary): List -fno-split-wide-types. (Optimize Options): Add -fsplit-wide-types to -O1 list. Document -fsplit-wide-types. * doc/rtl.texi (Regs and Memory): Document concat and concatn. * Makefile.in (OBJS-common): Add lower-subreg.o. (lower-subreg.o): New target. gcc/testsuite/: * gcc.dg/lower-subreg-1.c (test): New test. From-SVN: r121453
Diffstat (limited to 'gcc/regclass.c')
-rw-r--r--gcc/regclass.c82
1 files changed, 64 insertions, 18 deletions
diff --git a/gcc/regclass.c b/gcc/regclass.c
index 7726ea1..0a1114d 100644
--- a/gcc/regclass.c
+++ b/gcc/regclass.c
@@ -1,6 +1,6 @@
/* Compute register class preferences for pseudo-registers.
Copyright (C) 1987, 1988, 1991, 1992, 1993, 1994, 1995, 1996
- 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+ 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
Free Software Foundation, Inc.
This file is part of GCC.
@@ -859,7 +859,7 @@ static void record_address_regs (enum machine_mode, rtx, int, enum rtx_code,
#ifdef FORBIDDEN_INC_DEC_CLASSES
static int auto_inc_dec_reg_p (rtx, enum machine_mode);
#endif
-static void reg_scan_mark_refs (rtx, rtx, int);
+static void reg_scan_mark_refs (rtx, rtx, int, unsigned int);
/* Wrapper around REGNO_OK_FOR_INDEX_P, to allow pseudo registers. */
@@ -2292,6 +2292,14 @@ free_reg_info (void)
regno_allocated = 0;
reg_n_max = 0;
}
+
+/* Clear the information stored for REGNO. */
+void
+clear_reg_info_regno (unsigned int regno)
+{
+ if (regno < regno_allocated)
+ memset (VEC_index (reg_info_p, reg_n_info, regno), 0, sizeof (reg_info));
+}
/* This is the `regscan' pass of the compiler, run just before cse
and again just before loop.
@@ -2333,10 +2341,10 @@ reg_scan (rtx f, unsigned int nregs)
if (GET_CODE (pat) == PARALLEL
&& XVECLEN (pat, 0) > max_parallel)
max_parallel = XVECLEN (pat, 0);
- reg_scan_mark_refs (pat, insn, 0);
+ reg_scan_mark_refs (pat, insn, 0, 0);
if (REG_NOTES (insn))
- reg_scan_mark_refs (REG_NOTES (insn), insn, 1);
+ reg_scan_mark_refs (REG_NOTES (insn), insn, 1, 0);
}
max_parallel += max_set_parallel;
@@ -2344,11 +2352,39 @@ reg_scan (rtx f, unsigned int nregs)
timevar_pop (TV_REG_SCAN);
}
+/* Update 'regscan' information by looking at the insns
+ from FIRST to LAST. Some new REGs have been created,
+ and any REG with number greater than OLD_MAX_REGNO is
+ such a REG. We only update information for those. */
+
+void
+reg_scan_update (rtx first, rtx last, unsigned int old_max_regno)
+{
+ rtx insn;
+
+ allocate_reg_info (max_reg_num (), FALSE, FALSE);
+
+ for (insn = first; insn != last; insn = NEXT_INSN (insn))
+ if (INSN_P (insn))
+ {
+ rtx pat = PATTERN (insn);
+ if (GET_CODE (pat) == PARALLEL
+ && XVECLEN (pat, 0) > max_parallel)
+ max_parallel = XVECLEN (pat, 0);
+ reg_scan_mark_refs (pat, insn, 0, old_max_regno);
+
+ if (REG_NOTES (insn))
+ reg_scan_mark_refs (REG_NOTES (insn), insn, 1, old_max_regno);
+ }
+}
+
/* X is the expression to scan. INSN is the insn it appears in.
- NOTE_FLAG is nonzero if X is from INSN's notes rather than its body. */
+ NOTE_FLAG is nonzero if X is from INSN's notes rather than its body.
+ We should only record information for REGs with numbers
+ greater than or equal to MIN_REGNO. */
static void
-reg_scan_mark_refs (rtx x, rtx insn, int note_flag)
+reg_scan_mark_refs (rtx x, rtx insn, int note_flag, unsigned int min_regno)
{
enum rtx_code code;
rtx dest;
@@ -2375,35 +2411,43 @@ reg_scan_mark_refs (rtx x, rtx insn, int note_flag)
{
unsigned int regno = REGNO (x);
- if (!note_flag)
- REGNO_LAST_UID (regno) = INSN_UID (insn);
- if (REGNO_FIRST_UID (regno) == 0)
- REGNO_FIRST_UID (regno) = INSN_UID (insn);
+ if (regno >= min_regno)
+ {
+ if (!note_flag)
+ REGNO_LAST_UID (regno) = INSN_UID (insn);
+ if (REGNO_FIRST_UID (regno) == 0)
+ REGNO_FIRST_UID (regno) = INSN_UID (insn);
+ /* If we are called by reg_scan_update() (indicated by min_regno
+ being set), we also need to update the reference count. */
+ if (min_regno)
+ REG_N_REFS (regno)++;
+ }
}
break;
case EXPR_LIST:
if (XEXP (x, 0))
- reg_scan_mark_refs (XEXP (x, 0), insn, note_flag);
+ reg_scan_mark_refs (XEXP (x, 0), insn, note_flag, min_regno);
if (XEXP (x, 1))
- reg_scan_mark_refs (XEXP (x, 1), insn, note_flag);
+ reg_scan_mark_refs (XEXP (x, 1), insn, note_flag, min_regno);
break;
case INSN_LIST:
if (XEXP (x, 1))
- reg_scan_mark_refs (XEXP (x, 1), insn, note_flag);
+ reg_scan_mark_refs (XEXP (x, 1), insn, note_flag, min_regno);
break;
case CLOBBER:
{
rtx reg = XEXP (x, 0);
- if (REG_P (reg))
+ if (REG_P (reg)
+ && REGNO (reg) >= min_regno)
{
REG_N_SETS (REGNO (reg))++;
REG_N_REFS (REGNO (reg))++;
}
else if (MEM_P (reg))
- reg_scan_mark_refs (XEXP (reg, 0), insn, note_flag);
+ reg_scan_mark_refs (XEXP (reg, 0), insn, note_flag, min_regno);
}
break;
@@ -2420,7 +2464,8 @@ reg_scan_mark_refs (rtx x, rtx insn, int note_flag)
if (GET_CODE (dest) == PARALLEL)
max_set_parallel = MAX (max_set_parallel, XVECLEN (dest, 0) - 1);
- if (REG_P (dest))
+ if (REG_P (dest)
+ && REGNO (dest) >= min_regno)
{
REG_N_SETS (REGNO (dest))++;
REG_N_REFS (REGNO (dest))++;
@@ -2440,6 +2485,7 @@ reg_scan_mark_refs (rtx x, rtx insn, int note_flag)
if (REG_P (SET_DEST (x))
&& REGNO (SET_DEST (x)) >= FIRST_PSEUDO_REGISTER
+ && REGNO (SET_DEST (x)) >= min_regno
/* If the destination pseudo is set more than once, then other
sets might not be to a pointer value (consider access to a
union in two threads of control in the presence of global
@@ -2500,12 +2546,12 @@ reg_scan_mark_refs (rtx x, rtx insn, int note_flag)
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (fmt[i] == 'e')
- reg_scan_mark_refs (XEXP (x, i), insn, note_flag);
+ reg_scan_mark_refs (XEXP (x, i), insn, note_flag, min_regno);
else if (fmt[i] == 'E' && XVEC (x, i) != 0)
{
int j;
for (j = XVECLEN (x, i) - 1; j >= 0; j--)
- reg_scan_mark_refs (XVECEXP (x, i, j), insn, note_flag);
+ reg_scan_mark_refs (XVECEXP (x, i, j), insn, note_flag, min_regno);
}
}
}