From 04c5580f371b08c0cccb05a520b69097512e3f62 Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Fri, 18 Apr 2003 01:31:41 +0200 Subject: [PATCH] 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 --- gcc/ChangeLog | 12 +++++++++ gcc/emit-rtl.c | 6 ++++- gcc/profile.c | 82 ++++++++++++++++++++++++++++++---------------------------- gcc/reload.c | 39 ++++++++++++++-------------- gcc/rtl.h | 4 +++ gcc/rtlanal.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++ 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 + + * 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 * 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) -- 2.7.4