This patch fixes gcc.dg/unroll_1.c for MIPS16. There were two problems, one in the testcase itself and one in the rtl code.
The testcase problem was that gcc.dg/unroll_1.c forces loop2_unroll to be run via -fenable-rtl-loop2_unroll but it doesn't explicitly force the associated init pass (loop2) to be run as well. This only happens because -fmove-loop-invariants is usually the default for -O2. It isn't the default on MIPS16 though, so neither loop2 nor loop2_unroll were being run. The patch adds an explicit -fenable-rtl-loop2 to get around this. The other problem is related to the way that MIPS16 tests for equality. Conditional branches test register $24, and the only instructions that set $24 are MOVE and CMP(I), which is actually an XOR rather than a subtraction. So branches for equality typically look like: (set (reg:SI cond) (xor:SI (reg:SI X) (const_int Y))) (set (pc) (if_then_else (eq (reg:SI cond) (const_int 0)) (label_ref ...) (pc))) get_condition didn't recognise this form and so loop-iv.c couldn't figure out the number of iterations. I fixed that by handling (eq (xor ...) (const_int 0)) and (ne (xor ...) (const_int 0)) in canonicalize_condition, in a similar way to (compare ...). The existing (compare ...) conditions both test: ((GET_MODE_CLASS (mode) == MODE_CC) != (GET_MODE_CLASS (inner_mode) == MODE_CC)) && mode != VOIDmode && inner_mode != VOIDmode) with the comment: /* ??? We may not combine comparisons done in a CCmode with comparisons not done in a CCmode. This is to aid targets like Alpha that have an IEEE compliant EQ instruction, and a non-IEEE compliant BEQ instruction. The use of CCmode is actually artificial, simply to prevent the combination, but should not affect other platforms. However, we must allow VOIDmode comparisons to match either CCmode or non-CCmode comparison, because some ports have modeless comparisons inside branch patterns. ??? This mode check should perhaps look more like the mode check in simplify_comparison in combine. */ The IEEE thing obviously isn't a worry for XOR, but it still seemed more consistent to handle all cases in the same way. I therefore split the condition out into a separate test. Tested on mips64-linux-gnu. OK to install? Thanks, Richard gcc/ * rtlanal.c (canonicalize_condition): Split out duplicated mode check. Handle XOR. gcc/testsuite/ * gcc.dg/unroll_1.c: Add -fenable-rtl-loop2. Index: gcc/rtlanal.c =================================================================== --- gcc/rtlanal.c 2014-01-23 19:12:05.089232340 +0000 +++ gcc/rtlanal.c 2014-01-23 19:12:15.168333561 +0000 @@ -5051,23 +5051,24 @@ canonicalize_condition (rtx insn, rtx co ??? This mode check should perhaps look more like the mode check in simplify_comparison in combine. */ - - if ((GET_CODE (SET_SRC (set)) == COMPARE - || (((code == NE - || (code == LT - && val_signbit_known_set_p (inner_mode, - STORE_FLAG_VALUE)) + if (((GET_MODE_CLASS (mode) == MODE_CC) + != (GET_MODE_CLASS (inner_mode) == MODE_CC)) + && mode != VOIDmode + && inner_mode != VOIDmode) + break; + if (GET_CODE (SET_SRC (set)) == COMPARE + || (((code == NE + || (code == LT + && val_signbit_known_set_p (inner_mode, + STORE_FLAG_VALUE)) #ifdef FLOAT_STORE_FLAG_VALUE - || (code == LT - && SCALAR_FLOAT_MODE_P (inner_mode) - && (fsfv = FLOAT_STORE_FLAG_VALUE (inner_mode), - REAL_VALUE_NEGATIVE (fsfv))) + || (code == LT + && SCALAR_FLOAT_MODE_P (inner_mode) + && (fsfv = FLOAT_STORE_FLAG_VALUE (inner_mode), + REAL_VALUE_NEGATIVE (fsfv))) #endif - )) - && COMPARISON_P (SET_SRC (set)))) - && (((GET_MODE_CLASS (mode) == MODE_CC) - == (GET_MODE_CLASS (inner_mode) == MODE_CC)) - || mode == VOIDmode || inner_mode == VOIDmode)) + )) + && COMPARISON_P (SET_SRC (set)))) x = SET_SRC (set); else if (((code == EQ || (code == GE @@ -5080,15 +5081,18 @@ canonicalize_condition (rtx insn, rtx co REAL_VALUE_NEGATIVE (fsfv))) #endif )) - && COMPARISON_P (SET_SRC (set)) - && (((GET_MODE_CLASS (mode) == MODE_CC) - == (GET_MODE_CLASS (inner_mode) == MODE_CC)) - || mode == VOIDmode || inner_mode == VOIDmode)) - + && COMPARISON_P (SET_SRC (set))) { reverse_code = 1; x = SET_SRC (set); } + else if ((code == EQ || code == NE) + && GET_CODE (SET_SRC (set)) == XOR) + /* (eq (xor X Y) (const_int 0)) -> (eq X Y) + (ne (xor X Y) (const_int 0)) -> (ne X Y) + + This is the form used by MIPS16, for example. */ + x = SET_SRC (set); else break; } Index: gcc/testsuite/gcc.dg/unroll_1.c =================================================================== --- gcc/testsuite/gcc.dg/unroll_1.c 2014-01-23 19:12:05.089232340 +0000 +++ gcc/testsuite/gcc.dg/unroll_1.c 2014-01-23 19:12:15.185333731 +0000 @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -fdump-rtl-loop2_unroll=stderr -fno-peel-loops -fno-tree-vrp -fdisable-tree-cunroll -fdisable-tree-cunrolli -fenable-rtl-loop2_unroll" } */ +/* { dg-options "-O2 -fdump-rtl-loop2_unroll=stderr -fno-peel-loops -fno-tree-vrp -fdisable-tree-cunroll -fdisable-tree-cunrolli -fenable-rtl-loop2 -fenable-rtl-loop2_unroll" } */ unsigned a[100], b[100]; inline void bar()