On Mon, Oct 29, 2012 at 5:11 PM, H.J. Lu <hjl.to...@gmail.com> wrote: > On Mon, Oct 29, 2012 at 4:41 PM, H.J. Lu <hjl.to...@gmail.com> wrote: >> On Mon, Oct 29, 2012 at 9:38 AM, Vladimir Makarov <vmaka...@redhat.com> >> wrote: >>> On 12-10-29 12:21 PM, Richard Sandiford wrote: >>>> >>>> Vladimir Makarov <vmaka...@redhat.com> writes: >>>>> >>>>> H.J. in >>>>> >>>>> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=55116 >>>>> >>>>> reported an interesting address >>>>> >>>>> (and:DI (subreg:DI (plus:SI (ashift:SI (reg:SI 96 [ glob_vol_int.22 ]) >>>>> (const_int 2 [0x2])) >>>>> (symbol_ref:SI ("glob_vol_int_arr") <var_decl >>>>> 0x7ffff03c2720 glob_vol_int_arr>)) 0) >>>>> (const_int 4294967295 [0xffffffff])) >>>>> >>>>> which can not be correctly extracted. Here `and' with `subreg' >>>>> behaves as an address mutation. >>>>> >>>>> The following patch fixes the problem. >>>>> >>>>> Ok to commit, Richard? >>>> >>>> Heh, I wondered if subregs might still be used like that, and was almost >>>> tempted to add them just in case. >>>> >>>> I think this particular case is really a failed canonicalisation and that: >>>> >>>> (and:DI (subreg:DI (foo:SI ...) 0) (const_int 0xffffffff)) >>>> >>>> ought to be: >>>> >>>> (zero_extend:DI (foo:SI ...)) >>> >>> Yes, that was my thought too. >>> >>>> But I know I've approved MIPS patches to accept >>>> (and:DI ... (const_int 0xffffffff)) as an alternative. >>>> >>>>> Index: rtlanal.c >>>>> =================================================================== >>>>> --- rtlanal.c (revision 192942) >>>>> +++ rtlanal.c (working copy) >>>>> @@ -5459,6 +5459,11 @@ strip_address_mutations (rtx *loc, enum >>>>> else if (code == AND && CONST_INT_P (XEXP (*loc, 1))) >>>>> /* (and ... (const_int -X)) is used to align to X bytes. */ >>>>> loc = &XEXP (*loc, 0); >>>>> + else if (code == SUBREG >>>>> + && ! REG_P (XEXP (*loc, 0)) && ! MEM_P (XEXP (*loc, 0))) >>>>> + /* (subreg (operator ...) ...) usually inside and is used for >>>>> + mode conversion too. */ >>>>> + loc = &XEXP (*loc, 0); >>>> >>>> I think the condition should be: >>>> >>>> else if (code == SUBREG >>>> && !OBJECT_P (SUBREG_REG (*loc)) >>>> && subreg_lowpart (*loc)) >>>> >>>> OK with that change, if it works. >>>> >>> Yes, it works. >>> I've submitted the following patch. >>> >> >> It doesn't work right. I will create a new testcase. >> > >
This patch limits SUBREG to Pmode. Tested on Linux/x86-64. OK to install? Thanks. -- H.J. gcc/ 2012-10-29 H.J. Lu <hongjiu...@intel.com> PR middle-end/55116 * rtlanal.c (strip_address_mutations): Handle SUBREG only for Pmode. gcc/testsuite/ 2012-10-29 H.J. Lu <hongjiu...@intel.com> PR middle-end/55116 * gcc.target/i386/pr55116-2.c: New file. diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c index 43d4cb8..d076ad6 100644 --- a/gcc/rtlanal.c +++ b/gcc/rtlanal.c @@ -5460,6 +5460,7 @@ strip_address_mutations (rtx *loc, enum rtx_code *outer_code) /* (and ... (const_int -X)) is used to align to X bytes. */ loc = &XEXP (*loc, 0); else if (code == SUBREG + && GET_MODE (*loc) == Pmode && !OBJECT_P (SUBREG_REG (*loc)) && subreg_lowpart_p (*loc)) /* (subreg (operator ...) ...) inside and is used for mode diff --git a/gcc/testsuite/gcc.target/i386/pr55116-2.c b/gcc/testsuite/gcc.target/i386/pr55116-2.c new file mode 100644 index 0000000..7ef8ead --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr55116-2.c @@ -0,0 +1,86 @@ +/* { dg-do compile { target { ! { ia32 } } } } */ +/* { dg-options "-O2 -mx32 -maddress-mode=long" } */ + +typedef struct rtx_def *rtx; +enum rtx_code { MINUS }; +union rtunion_def { + rtx rt_rtx; +}; +typedef union rtunion_def rtunion; +struct rtx_def { + enum rtx_code code: 16; + union u { + rtunion fld[1]; + } + u; +}; +rtx simplify_binary_operation (enum rtx_code code, int mode, + rtx op0, rtx op1); +struct simplify_plus_minus_op_data { + rtx op; + short neg; +}; +void simplify_plus_minus (enum rtx_code code, int mode, rtx op0, rtx op1) +{ + struct simplify_plus_minus_op_data ops[8]; + rtx tem = (rtx) 0; + int n_ops = 2, input_ops = 2; + int changed, canonicalized = 0; + int i, j; + __builtin_memset (ops, 0, sizeof (ops)); + do + { + changed = 0; + for (i = 0; i < n_ops; i++) + { + rtx this_op = ops[i].op; + int this_neg = ops[i].neg; + enum rtx_code this_code = ((enum rtx_code) (this_op)->code); + switch (this_code) + { + case MINUS: + if (n_ops == 7) + return; + n_ops++; + input_ops++; + changed = 1; + canonicalized |= this_neg; + break; + } + } + } + while (changed); + do + { + j = n_ops - 1; + for (i = n_ops - 1; j >= 0; j--) + { + rtx lhs = ops[j].op, rhs = ops[i].op; + int lneg = ops[j].neg, rneg = ops[i].neg; + if (lhs != 0 && rhs != 0) + { + enum rtx_code ncode = MINUS; + if (((enum rtx_code) (lhs)->code) == MINUS) + tem = simplify_binary_operation (ncode, mode, lhs, rhs); + if (tem && ! (((enum rtx_code) (tem)->code) == MINUS + && ((((((tem)->u.fld[0]).rt_rtx))->u.fld[0]).rt_rtx) == lhs + && ((((((tem)->u.fld[0]).rt_rtx))->u.fld[1]).rt_rtx) == rhs)) + { + lneg &= rneg; + ops[i].op = tem; + ops[i].neg = lneg; + ops[j].op = (rtx) 0; + changed = 1; + canonicalized = 1; + } + } + } + for (i = 0, j = 0; j < n_ops; j++) + if (ops[j].op) + { + ops[i] = ops[j]; + i++; + } + } + while (changed); +}