aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Hubicka <jh@suse.cz>2003-04-18 01:31:41 +0200
committerJan Hubicka <hubicka@gcc.gnu.org>2003-04-17 23:31:41 +0000
commit04c5580f371b08c0cccb05a520b69097512e3f62 (patch)
tree0bb84f63ed128b54b740a46b5532d57a1116b085
parentc409ea0d30ef28e68ff6b4fcb699ba013ee947f1 (diff)
downloadgcc-04c5580f371b08c0cccb05a520b69097512e3f62.zip
gcc-04c5580f371b08c0cccb05a520b69097512e3f62.tar.gz
gcc-04c5580f371b08c0cccb05a520b69097512e3f62.tar.bz2
emit-rtl.c (subreg_hard_regno): Check that register is representable.
* emit-rtl.c (subreg_hard_regno): Check that register is representable. * reload.c (reload_inner_reg_of_subreg): When register is not representable, reload the whole thing. (find_reloads): Likewsie. * rtlanal.c (subreg_representable_p): New function. * profile.c (compute_branch_probabilities): Cleanup sanity checking; allow negative probabilities for edges from the call to exit. (branch_prob): Do not add fake edges for functions that may return twice From-SVN: r65757
-rw-r--r--gcc/ChangeLog12
-rw-r--r--gcc/emit-rtl.c6
-rw-r--r--gcc/profile.c82
-rw-r--r--gcc/reload.c39
-rw-r--r--gcc/rtl.h4
-rw-r--r--gcc/rtlanal.c71
6 files changed, 154 insertions, 60 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 71135ae..7c393c5 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,15 @@
+Fri Apr 18 01:28:51 CEST 2003 Jan Hubicka <jh@suse.cz>
+
+ * emit-rtl.c (subreg_hard_regno): Check that register is representable.
+ * reload.c (reload_inner_reg_of_subreg): When register is not
+ representable, reload the whole thing.
+ (find_reloads): Likewsie.
+ * rtlanal.c (subreg_representable_p): New function.
+
+ * profile.c (compute_branch_probabilities): Cleanup sanity checking;
+ allow negative probabilities for edges from the call to exit.
+ (branch_prob): Do not add fake edges for functions that may return twice
+
2003-04-17 DJ Delorie <dj@redhat.com>
* toplev.c (target_options): Add value field.
diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c
index 058100c..7048aee 100644
--- a/gcc/emit-rtl.c
+++ b/gcc/emit-rtl.c
@@ -1081,7 +1081,11 @@ subreg_hard_regno (x, check_mode)
abort ();
if (check_mode && ! HARD_REGNO_MODE_OK (base_regno, GET_MODE (reg)))
abort ();
-
+#ifdef ENABLE_CHECKING
+ if (!subreg_offset_representable_p (REGNO (reg), GET_MODE (reg),
+ SUBREG_BYTE (x), mode))
+ abort ();
+#endif
/* Catch non-congruent offsets too. */
byte_offset = SUBREG_BYTE (x);
if ((byte_offset % GET_MODE_SIZE (mode)) != 0)
diff --git a/gcc/profile.c b/gcc/profile.c
index 99ddd3b..afabe20 100644
--- a/gcc/profile.c
+++ b/gcc/profile.c
@@ -674,22 +674,47 @@ compute_branch_probabilities ()
FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
{
edge e;
- gcov_type total;
rtx note;
- total = bb->count;
- if (total)
+ if (bb->count < 0)
{
- for (e = bb->succ; e; e = e->succ_next)
+ error ("corrupted profile info: number of iterations for basic block %d thought to be %i",
+ bb->index, (int)bb->count);
+ bb->count = 0;
+ }
+ for (e = bb->succ; e; e = e->succ_next)
+ {
+ /* Function may return twice in the cased the called fucntion is
+ setjmp or calls fork, but we can't represent this by extra
+ edge from the entry, since extra edge from the exit is
+ already present. We get negative frequency from the entry
+ point. */
+ if ((e->count < 0
+ && e->dest == EXIT_BLOCK_PTR)
+ || (e->count > bb->count
+ && e->dest != EXIT_BLOCK_PTR))
{
- e->probability = (e->count * REG_BR_PROB_BASE + total / 2) / total;
- if (e->probability < 0 || e->probability > REG_BR_PROB_BASE)
- {
- error ("corrupted profile info: prob for %d-%d thought to be %d",
- e->src->index, e->dest->index, e->probability);
- e->probability = REG_BR_PROB_BASE / 2;
- }
+ rtx insn = bb->end;
+
+ while (GET_CODE (insn) != CALL_INSN
+ && insn != bb->head
+ && keep_with_call_p (insn))
+ insn = PREV_INSN (insn);
+ if (GET_CODE (insn) == CALL_INSN)
+ e->count = e->count < 0 ? 0 : bb->count;
}
+ if (e->count < 0 || e->count > bb->count)
+ {
+ error ("corrupted profile info: number of executions for edge %d-%d thought to be %i",
+ e->src->index, e->dest->index,
+ (int)e->count);
+ e->count = bb->count / 2;
+ }
+ }
+ if (bb->count)
+ {
+ for (e = bb->succ; e; e = e->succ_next)
+ e->probability = (e->count * REG_BR_PROB_BASE + bb->count / 2) / bb->count;
if (bb->index >= 0
&& any_condjump_p (bb->end)
&& bb->succ->succ_next)
@@ -730,6 +755,8 @@ compute_branch_probabilities ()
calls). */
else
{
+ int total = 0;
+
for (e = bb->succ; e; e = e->succ_next)
if (!(e->flags & (EDGE_COMPLEX | EDGE_FAKE)))
total ++;
@@ -873,36 +900,13 @@ branch_prob ()
{
int need_exit_edge = 0, need_entry_edge = 0;
int have_exit_edge = 0, have_entry_edge = 0;
- rtx insn;
edge e;
- /* Add fake edges from entry block to the call insns that may return
- twice. The CFG is not quite correct then, as call insn plays more
- role of CODE_LABEL, but for our purposes, everything should be OK,
- as we never insert code to the beginning of basic block. */
- for (insn = bb->head; insn != NEXT_INSN (bb->end);
- insn = NEXT_INSN (insn))
- {
- if (GET_CODE (insn) == CALL_INSN
- && find_reg_note (insn, REG_SETJMP, NULL))
- {
- if (GET_CODE (bb->head) == CODE_LABEL
- || insn != NEXT_INSN (bb->head))
- {
- e = split_block (bb, PREV_INSN (insn));
- make_edge (ENTRY_BLOCK_PTR, e->dest, EDGE_FAKE);
- break;
- }
- else
- {
- /* We should not get abort here, as call to setjmp should not
- be the very first instruction of function. */
- if (bb == ENTRY_BLOCK_PTR)
- abort ();
- make_edge (ENTRY_BLOCK_PTR, bb, EDGE_FAKE);
- }
- }
- }
+ /* Functions returning multiple times are not handled by extra edges.
+ Instead we simply allow negative counts on edges from exit to the
+ block past call and corresponding probabilities. We can't go
+ with the extra edges because that would result in flowgraph that
+ needs to have fake edges outside the spanning tree. */
for (e = bb->succ; e; e = e->succ_next)
{
diff --git a/gcc/reload.c b/gcc/reload.c
index e360e26..bc3c177 100644
--- a/gcc/reload.c
+++ b/gcc/reload.c
@@ -2880,6 +2880,12 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
if (GET_CODE (SUBREG_REG (operand)) == REG
&& REGNO (SUBREG_REG (operand)) < FIRST_PSEUDO_REGISTER)
{
+ if (!subreg_offset_representable_p
+ (REGNO (SUBREG_REG (operand)),
+ GET_MODE (SUBREG_REG (operand)),
+ SUBREG_BYTE (operand),
+ GET_MODE (operand)))
+ force_reload = 1;
offset += subreg_regno_offset (REGNO (SUBREG_REG (operand)),
GET_MODE (SUBREG_REG (operand)),
SUBREG_BYTE (operand),
@@ -2935,26 +2941,6 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
)
#endif
)
- /* This following hunk of code should no longer be
- needed at all with SUBREG_BYTE. If you need this
- code back, please explain to me why so I can
- fix the real problem. -DaveM */
-#if 0
- /* Subreg of a hard reg which can't handle the subreg's mode
- or which would handle that mode in the wrong number of
- registers for subregging to work. */
- || (GET_CODE (operand) == REG
- && REGNO (operand) < FIRST_PSEUDO_REGISTER
- && ((GET_MODE_SIZE (operand_mode[i]) <= UNITS_PER_WORD
- && (GET_MODE_SIZE (GET_MODE (operand))
- > UNITS_PER_WORD)
- && ((GET_MODE_SIZE (GET_MODE (operand))
- / UNITS_PER_WORD)
- != HARD_REGNO_NREGS (REGNO (operand),
- GET_MODE (operand))))
- || ! HARD_REGNO_MODE_OK (REGNO (operand) + offset,
- operand_mode[i])))
-#endif
)
force_reload = 1;
}
@@ -5272,6 +5258,19 @@ find_reloads_address_1 (mode, x, context, loc, opnum, type, ind_levels, insn)
SUBREG_BYTE (orig_op1),
GET_MODE (orig_op1))));
}
+ /* Plus in the index register may be created only as a result of
+ register remateralization for expresion like &localvar*4. Reload it.
+ It may be possible to combine the displacement on the outer level,
+ but it is probably not worthwhile to do so. */
+ if (context)
+ {
+ find_reloads_address (GET_MODE (x), loc, XEXP (x, 0), &XEXP (x, 0),
+ opnum, ADDR_TYPE (type), ind_levels, insn);
+ push_reload (*loc, NULL_RTX, loc, (rtx*) 0,
+ (context ? INDEX_REG_CLASS : MODE_BASE_REG_CLASS (mode)),
+ GET_MODE (x), VOIDmode, 0, 0, opnum, type);
+ return 1;
+ }
if (code0 == MULT || code0 == SIGN_EXTEND || code0 == TRUNCATE
|| code0 == ZERO_EXTEND || code1 == MEM)
diff --git a/gcc/rtl.h b/gcc/rtl.h
index eb78ba6..b78e9e7 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -1038,6 +1038,10 @@ extern unsigned int subreg_regno_offset PARAMS ((unsigned int,
enum machine_mode,
unsigned int,
enum machine_mode));
+extern bool subreg_offset_representable_p PARAMS ((unsigned int,
+ enum machine_mode,
+ unsigned int,
+ enum machine_mode));
extern unsigned int subreg_regno PARAMS ((rtx));
/* 1 if RTX is a subreg containing a reg that is already known to be
diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c
index f7923c2..3b024ad 100644
--- a/gcc/rtlanal.c
+++ b/gcc/rtlanal.c
@@ -3387,6 +3387,77 @@ subreg_regno_offset (xregno, xmode, offset, ymode)
return (y_offset / (mode_multiple / nregs_multiple)) * nregs_ymode;
}
+/* This function returns true when the offset is representable via
+ subreg_offset in the given regno.
+ xregno - A regno of an inner hard subreg_reg (or what will become one).
+ xmode - The mode of xregno.
+ offset - The byte offset.
+ ymode - The mode of a top level SUBREG (or what may become one).
+ RETURN - The regno offset which would be used. */
+bool
+subreg_offset_representable_p (xregno, xmode, offset, ymode)
+ unsigned int xregno;
+ enum machine_mode xmode;
+ unsigned int offset;
+ enum machine_mode ymode;
+{
+ int nregs_xmode, nregs_ymode;
+ int mode_multiple, nregs_multiple;
+ int y_offset;
+
+ if (xregno >= FIRST_PSEUDO_REGISTER)
+ abort ();
+
+ nregs_xmode = HARD_REGNO_NREGS (xregno, xmode);
+ nregs_ymode = HARD_REGNO_NREGS (xregno, ymode);
+
+ /* paradoxical subregs are always valid. */
+ if (offset == 0
+ && nregs_ymode > nregs_xmode
+ && (GET_MODE_SIZE (ymode) > UNITS_PER_WORD
+ ? WORDS_BIG_ENDIAN : BYTES_BIG_ENDIAN))
+ return true;
+
+ /* Lowpart subregs are always valid. */
+ if (offset == subreg_lowpart_offset (ymode, xmode))
+ return true;
+
+#ifdef ENABLE_CHECKING
+ /* This should always pass, otherwise we don't know how to verify the
+ constraint.
+
+ These conditions may be relaxed but subreg_offset would need to be
+ redesigned. */
+ if (GET_MODE_SIZE (xmode) % GET_MODE_SIZE (ymode)
+ || GET_MODE_SIZE (ymode) % nregs_ymode
+ || mode_for_size (GET_MODE_SIZE (ymode) / nregs_ymode,
+ MODE_INT, 0) == VOIDmode
+ || nregs_xmode % nregs_ymode)
+ abort ();
+#endif
+
+ /* The XMODE value can be seen as an vector of NREGS_XMODE
+ values. The subreg must represent an lowpart of given field.
+ Compute what field it is. */
+ offset -= subreg_lowpart_offset (mode_for_size (GET_MODE_SIZE (ymode)
+ / nregs_ymode,
+ MODE_INT, 0), xmode);
+
+ /* size of ymode must not be greater than the size of xmode. */
+ mode_multiple = GET_MODE_SIZE (xmode) / GET_MODE_SIZE (ymode);
+ if (mode_multiple == 0)
+ abort ();
+
+ y_offset = offset / GET_MODE_SIZE (ymode);
+ nregs_multiple = nregs_xmode / nregs_ymode;
+#ifdef ENABLE_CHECKING
+ if (offset % GET_MODE_SIZE (ymode)
+ || mode_multiple % nregs_multiple)
+ abort ();
+#endif
+ return (!(y_offset % (mode_multiple / nregs_multiple)));
+}
+
/* Return the final regno that a subreg expression refers to. */
unsigned int
subreg_regno (x)