2009-08-05 Jakub Jelinek PR target/40971 * config/rs6000/rs6000.c (rs6000_legitimize_address): For [DT][FDI]mode ensure the offset isn't 4/8/12 bytes below 0x8000. * gcc.dg/pr40971.c: New test. --- gcc/config/rs6000/rs6000.c.jj 2009-04-27 16:47:29.000000000 +0200 +++ gcc/config/rs6000/rs6000.c 2009-08-05 16:53:42.000000000 +0200 @@ -4490,6 +4490,28 @@ rs6000_legitimize_address (rtx x, rtx ol { rtx ret = NULL_RTX; rtx orig_x = x; + unsigned int extra = 0; + + switch (mode) + { + case DFmode: + case DDmode: + extra = 4; + break; + case DImode: + if (!TARGET_POWERPC64) + extra = 4; + break; + case TFmode: + case TDmode: + extra = 12; + break; + case TImode: + extra = TARGET_POWERPC64 ? 8 : 12; + break; + default: + break; + } if (GET_CODE (x) == SYMBOL_REF) { @@ -4512,7 +4534,7 @@ rs6000_legitimize_address (rtx x, rtx ol && GET_CODE (XEXP (x, 0)) == REG && GET_CODE (XEXP (x, 1)) == CONST_INT && ((unsigned HOST_WIDE_INT) (INTVAL (XEXP (x, 1)) + 0x8000) - >= 0x10000) + >= 0x10000 - extra) && !((TARGET_POWERPC64 && (mode == DImode || mode == TImode) && (INTVAL (XEXP (x, 1)) & 3) != 0) @@ -4524,10 +4546,12 @@ rs6000_legitimize_address (rtx x, rtx ol HOST_WIDE_INT high_int, low_int; rtx sum; low_int = ((INTVAL (XEXP (x, 1)) & 0xffff) ^ 0x8000) - 0x8000; + if (low_int >= 0x8000 - extra) + low_int = 0; high_int = INTVAL (XEXP (x, 1)) - low_int; sum = force_operand (gen_rtx_PLUS (Pmode, XEXP (x, 0), GEN_INT (high_int)), 0); - ret = gen_rtx_PLUS (Pmode, sum, GEN_INT (low_int)); + ret = plus_constant (sum, low_int); } else if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 0)) == REG --- gcc/testsuite/gcc.dg/pr40971.c.jj 2009-08-05 16:46:17.000000000 +0200 +++ gcc/testsuite/gcc.dg/pr40971.c 2009-08-05 16:45:44.000000000 +0200 @@ -0,0 +1,23 @@ +/* PR target/40971 */ +/* { dg-do compile } */ +/* { dg-options "-O -fstack-protector -fno-strict-aliasing" } */ +/* { dg-require-effective-target fstack_protector } */ + +extern void bar (char *); + +void +foo (int f, long a) +{ + { + char d[32768]; + bar (d); + } + double b = f; + while (a) + { + char c[sizeof (double)]; + __builtin_memcpy (c, &b, sizeof (c)); + if (*(double *) c != 2.0) + break; + } +}