diff options
author | Bernd Schmidt <bernds@codesourcery.com> | 2012-08-09 13:18:05 +0000 |
---|---|---|
committer | Bernd Schmidt <bernds@gcc.gnu.org> | 2012-08-09 13:18:05 +0000 |
commit | 82ad0aaf6e6d671b8dab3fd9ae3b496f1c70aea7 (patch) | |
tree | dc0e08837a77bf368d263bcde301c676189919de /gcc | |
parent | 62d6a5bbc851e99b69cf6899e02ac46e66a3b50c (diff) | |
download | gcc-82ad0aaf6e6d671b8dab3fd9ae3b496f1c70aea7.zip gcc-82ad0aaf6e6d671b8dab3fd9ae3b496f1c70aea7.tar.gz gcc-82ad0aaf6e6d671b8dab3fd9ae3b496f1c70aea7.tar.bz2 |
reload.c (find_valid_class_1): New static function.
* reload.c (find_valid_class_1): New static function.
(push_reload): Use it when reloading a SYMBOL_REG as the inner
of a subreg. Keep better track of needed classes for the
secondary memory case.
* config/i386/i386.h (LIMIT_RELOAD_CLASS): Limit INT_SSE_REGS to
GENERAL_REGS.
* reload1.c (replaced_subreg): New static function.
(gen_reload): Use it when deciding whether to use secondary
memory.
* gcc.c-torture/compile/20120727-1.c: New test.
From-SVN: r190252
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 12 | ||||
-rw-r--r-- | gcc/config/i386/i386.h | 3 | ||||
-rw-r--r-- | gcc/reload.c | 73 | ||||
-rw-r--r-- | gcc/reload1.c | 28 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 4 | ||||
-rw-r--r-- | gcc/testsuite/gcc.c-torture/compile/20120727-1.c | 11 |
6 files changed, 112 insertions, 19 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 36302bf..2a00c31 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,15 @@ +2012-08-09 Bernd Schmidt <bernds@codesourcery.com> + + * reload.c (find_valid_class_1): New static function. + (push_reload): Use it when reloading a SYMBOL_REG as the inner + of a subreg. Keep better track of needed classes for the + secondary memory case. + * config/i386/i386.h (LIMIT_RELOAD_CLASS): Limit INT_SSE_REGS to + GENERAL_REGS. + * reload1.c (replaced_subreg): New static function. + (gen_reload): Use it when deciding whether to use secondary + memory. + 2012-08-09 Richard Guenther <rguenther@suse.de> * tree.h (SSA_VAR_P): Simplify. diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h index c2b4460..de7b82a 100644 --- a/gcc/config/i386/i386.h +++ b/gcc/config/i386/i386.h @@ -1384,7 +1384,8 @@ enum reg_class ((MODE) == QImode && !TARGET_64BIT \ && ((CLASS) == ALL_REGS || (CLASS) == GENERAL_REGS \ || (CLASS) == LEGACY_REGS || (CLASS) == INDEX_REGS) \ - ? Q_REGS : (CLASS)) + ? Q_REGS \ + : (CLASS) == INT_SSE_REGS ? GENERAL_REGS : (CLASS)) /* If we are copying between general and FP registers, we need a memory location. The same is true for SSE and MMX registers. */ diff --git a/gcc/reload.c b/gcc/reload.c index 39178d8..201f475 100644 --- a/gcc/reload.c +++ b/gcc/reload.c @@ -707,6 +707,55 @@ find_valid_class (enum machine_mode outer ATTRIBUTE_UNUSED, return best_class; } + +/* We are trying to reload a subreg of something that is not a register. + Find the largest class which has at least one register valid in + mode MODE. OUTER is the mode of the subreg, DEST_CLASS the class in + which we would eventually like to obtain the object. */ + +static enum reg_class +find_valid_class_1 (enum machine_mode outer ATTRIBUTE_UNUSED, + enum machine_mode mode ATTRIBUTE_UNUSED, + enum reg_class dest_class ATTRIBUTE_UNUSED) +{ + int best_cost = -1; + int rclass; + int regno; + enum reg_class best_class = NO_REGS; + unsigned int best_size = 0; + int cost; + + for (rclass = 1; rclass < N_REG_CLASSES; rclass++) + { + int bad = 0; + for (regno = 0; regno < FIRST_PSEUDO_REGISTER && !bad; regno++) + if (TEST_HARD_REG_BIT (reg_class_contents[rclass], regno) + && !HARD_REGNO_MODE_OK (regno, mode)) + bad = 1; + + if (bad) + continue; + + cost = register_move_cost (outer, (enum reg_class) rclass, dest_class); + + if ((reg_class_size[rclass] > best_size + && (best_cost < 0 || best_cost >= cost)) + || best_cost > cost) + { + best_class = (enum reg_class) rclass; + best_size = reg_class_size[rclass]; + best_cost = register_move_cost (outer, (enum reg_class) rclass, + dest_class); + } + } + + gcc_assert (best_size != 0); + +#ifdef LIMIT_RELOAD_CLASS + best_class = LIMIT_RELOAD_CLASS (mode, best_class); +#endif + return best_class; +} /* Return the number of a previously made reload that can be combined with a new one, or n_reloads if none of the existing reloads can be used. @@ -925,6 +974,8 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc, int secondary_in_reload = -1, secondary_out_reload = -1; enum insn_code secondary_in_icode = CODE_FOR_nothing; enum insn_code secondary_out_icode = CODE_FOR_nothing; + enum reg_class subreg_in_class ATTRIBUTE_UNUSED; + subreg_in_class = NO_REGS; /* INMODE and/or OUTMODE could be VOIDmode if no mode has been specified for the operand. In that case, @@ -1091,16 +1142,18 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc, if (in != 0 && reload_inner_reg_of_subreg (in, inmode, false)) { - enum reg_class in_class = rclass; - if (REG_P (SUBREG_REG (in))) - in_class + subreg_in_class = find_valid_class (inmode, GET_MODE (SUBREG_REG (in)), subreg_regno_offset (REGNO (SUBREG_REG (in)), GET_MODE (SUBREG_REG (in)), SUBREG_BYTE (in), GET_MODE (in)), REGNO (SUBREG_REG (in))); + else if (GET_CODE (SUBREG_REG (in)) == SYMBOL_REF) + subreg_in_class = find_valid_class_1 (inmode, + GET_MODE (SUBREG_REG (in)), + rclass); /* This relies on the fact that emit_reload_insns outputs the instructions for input reloads of type RELOAD_OTHER in the same @@ -1108,7 +1161,7 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc, RELOAD_OTHER, we are guaranteed that this inner reload will be output before the outer reload. */ push_reload (SUBREG_REG (in), NULL_RTX, &SUBREG_REG (in), (rtx *) 0, - in_class, VOIDmode, VOIDmode, 0, 0, opnum, type); + subreg_in_class, VOIDmode, VOIDmode, 0, 0, opnum, type); dont_remove_subreg = 1; } @@ -1327,13 +1380,15 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc, So add an additional reload. */ #ifdef SECONDARY_MEMORY_NEEDED - /* If a memory location is needed for the copy, make one. */ - if (in != 0 + if (subreg_in_class == NO_REGS + && in != 0 && (REG_P (in) || (GET_CODE (in) == SUBREG && REG_P (SUBREG_REG (in)))) - && reg_or_subregno (in) < FIRST_PSEUDO_REGISTER - && SECONDARY_MEMORY_NEEDED (REGNO_REG_CLASS (reg_or_subregno (in)), - rclass, inmode)) + && reg_or_subregno (in) < FIRST_PSEUDO_REGISTER) + subreg_in_class = REGNO_REG_CLASS (reg_or_subregno (in)); + /* If a memory location is needed for the copy, make one. */ + if (subreg_in_class != NO_REGS + && SECONDARY_MEMORY_NEEDED (subreg_in_class, rclass, inmode)) get_secondary_mem (in, inmode, opnum, type); #endif diff --git a/gcc/reload1.c b/gcc/reload1.c index e6d3a71..bf5d3d3 100644 --- a/gcc/reload1.c +++ b/gcc/reload1.c @@ -8469,6 +8469,18 @@ emit_insn_if_valid_for_reload (rtx insn) return NULL; } +/* If X is not a subreg, return it unmodified. If it is a subreg, + look up whether we made a replacement for the SUBREG_REG. Return + either the replacement or the SUBREG_REG. */ + +static rtx +replaced_subreg (rtx x) +{ + if (GET_CODE (x) == SUBREG) + return find_replacement (&SUBREG_REG (x)); + return x; +} + /* Emit code to perform a reload from IN (which may be a reload register) to OUT (which may also be a reload register). IN or OUT is from operand OPNUM with reload type TYPE. @@ -8479,7 +8491,7 @@ static rtx gen_reload (rtx out, rtx in, int opnum, enum reload_type type) { rtx last = get_last_insn (); - rtx tem; + rtx tem, tem1, tem2; /* If IN is a paradoxical SUBREG, remove it and try to put the opposite SUBREG on OUT. Likewise for a paradoxical SUBREG on OUT. */ @@ -8616,14 +8628,12 @@ gen_reload (rtx out, rtx in, int opnum, enum reload_type type) #ifdef SECONDARY_MEMORY_NEEDED /* If we need a memory location to do the move, do it that way. */ - else if ((REG_P (in) - || (GET_CODE (in) == SUBREG && REG_P (SUBREG_REG (in)))) - && reg_or_subregno (in) < FIRST_PSEUDO_REGISTER - && (REG_P (out) - || (GET_CODE (out) == SUBREG && REG_P (SUBREG_REG (out)))) - && reg_or_subregno (out) < FIRST_PSEUDO_REGISTER - && SECONDARY_MEMORY_NEEDED (REGNO_REG_CLASS (reg_or_subregno (in)), - REGNO_REG_CLASS (reg_or_subregno (out)), + else if ((tem1 = replaced_subreg (in), tem2 = replaced_subreg (out), + (REG_P (tem1) && REG_P (tem2))) + && REGNO (tem1) < FIRST_PSEUDO_REGISTER + && REGNO (tem2) < FIRST_PSEUDO_REGISTER + && SECONDARY_MEMORY_NEEDED (REGNO_REG_CLASS (REGNO (tem1)), + REGNO_REG_CLASS (REGNO (tem2)), GET_MODE (out))) { /* Get the memory to use and rewrite both registers to its mode. */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 47066a3..7dcf7d7 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2012-08-09 Bernd Schmidt <bernds@codesourcery.com> + + * gcc.c-torture/compile/20120727-1.c: New test. + 2012-08-09 Tobias Burnus <burnus@net-b.de> PR fortran/54199 diff --git a/gcc/testsuite/gcc.c-torture/compile/20120727-1.c b/gcc/testsuite/gcc.c-torture/compile/20120727-1.c new file mode 100644 index 0000000..d43472f --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/20120727-1.c @@ -0,0 +1,11 @@ +union { + char *p; + float f; +} u; + +void +f (void) +{ + u.p = ""; + u.f += 1.1; +} |