diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 2b6d43c4c97..526c390d4c1 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +2007-04-26 Ian Lance Taylor + + PR target/28675 + * reload.c (find_reloads_subreg_address): If the address was valid + in the original mode but not in the new mode, reload the whole + address. + 2007-04-27 Zdenek Dvorak * tree-cfgcleanup.c (cfgcleanup_altered_bbs): New global variable. diff --git a/gcc/reload.c b/gcc/reload.c index b0374d8c106..de6093b0339 100644 --- a/gcc/reload.c +++ b/gcc/reload.c @@ -6006,6 +6006,8 @@ find_reloads_subreg_address (rtx x, int force_replace, int opnum, unsigned inner_size = GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))); int offset; rtx orig = tem; + enum machine_mode orig_mode = GET_MODE (orig); + int reloaded; /* For big-endian paradoxical subregs, SUBREG_BYTE does not hold the correct (negative) byte offset. */ @@ -6038,13 +6040,32 @@ find_reloads_subreg_address (rtx x, int force_replace, int opnum, return x; } - find_reloads_address (GET_MODE (tem), &tem, XEXP (tem, 0), - &XEXP (tem, 0), opnum, type, - ind_levels, insn); + reloaded = find_reloads_address (GET_MODE (tem), &tem, + XEXP (tem, 0), &XEXP (tem, 0), + opnum, type, ind_levels, insn); /* ??? Do we need to handle nonzero offsets somehow? */ if (!offset && !rtx_equal_p (tem, orig)) push_reg_equiv_alt_mem (regno, tem); + /* For some processors an address may be valid in the + original mode but not in a smaller mode. For + example, ARM accepts a scaled index register in + SImode but not in HImode. find_reloads_address + assumes that we pass it a valid address, and doesn't + force a reload. This will probably be fine if + find_reloads_address finds some reloads. But if it + doesn't find any, then we may have just converted a + valid address into an invalid one. Check for that + here. */ + if (reloaded != 1 + && strict_memory_address_p (orig_mode, XEXP (tem, 0)) + && !strict_memory_address_p (GET_MODE (tem), + XEXP (tem, 0))) + push_reload (XEXP (tem, 0), NULL_RTX, &XEXP (tem, 0), (rtx*) 0, + base_reg_class (GET_MODE (tem), MEM, SCRATCH), + GET_MODE (XEXP (tem, 0)), VOIDmode, 0, 0, + opnum, type); + /* If this is not a toplevel operand, find_reloads doesn't see this substitution. We have to emit a USE of the pseudo so that delete_output_reload can see it. */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 6b7bcc7d67e..40c811bb7aa 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2007-04-26 Ian Lance Taylor + + PR target/28675 + * gcc.c-torture/compile/pr28675.c: New test. + 2007-04-26 Andrew Pinski PR C++/30016 @@ -79,7 +84,7 @@ 2007-04-24 Ian Lance Taylor - PR tree-optimizatoin/31605 + PR tree-optimization/31605 * gcc.c-torture/execute/pr31605.c: New test. 2007-04-24 Francois-Xavier Coudert diff --git a/gcc/testsuite/gcc.c-torture/compile/pr28675.c b/gcc/testsuite/gcc.c-torture/compile/pr28675.c new file mode 100644 index 00000000000..0d78353739c --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/pr28675.c @@ -0,0 +1,38 @@ +struct fb_cmap { + unsigned int start; + unsigned int len; + unsigned short *red; + unsigned short *green; + unsigned short *blue; + unsigned short *transp; +}; + +typedef struct { + int r; + int g; + int b; + int a; +} rgba_t; + +static unsigned int cmap_len; + +extern unsigned int red_len, green_len, blue_len, alpha_len; +extern struct fb_cmap fb_cmap; +extern rgba_t *clut; +extern int fb_set_cmap(void); + +void directcolor_update_cmap(void) +{ + unsigned int i; + + for (i = 0; i < cmap_len; i++) { + if (i < red_len) + fb_cmap.red[i] = clut[i].r; + if (i < green_len) + fb_cmap.green[i] = clut[i].g; + if (i < blue_len) + fb_cmap.blue[i] = clut[i].b; + if (fb_cmap.transp && i < alpha_len) + fb_cmap.transp[i] = clut[i].a; + } +}