diff --git a/gcc/ChangeLog b/gcc/ChangeLog index d2aa482b2e081dc2f3e0eb2f68c6d43eab205068..1c010560c19f49a5f28ba599bfbb9dba914fb1d2 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,14 @@ +2020-04-17 Jakub Jelinek <jakub@redhat.com> + Jeff Law <law@redhat.com> + + PR target/94567 + * config/i386/i386.md (*testqi_ext_3): Use CCZmode rather than + CCNOmode in ix86_match_ccmode if len is equal to <MODE>mode precision, + or pos + len >= 32, or pos + len is equal to operands[2] precision + and operands[2] is not a register operand. During splitting perform + SImode AND if operands[0] doesn't have CCZmode and pos + len is + equal to mode precision. + 2020-04-17 Richard Biener <rguenther@suse.de> PR other/94629 diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index 3051624d89fdaa01c4a95d7546a99df70723f350..b426c21d3ddd071a3579a3ed6c219b00c2d71584 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -8730,10 +8730,38 @@ && INTVAL (operands[3]) > 32 && INTVAL (operands[3]) + INTVAL (operands[4]) == 64)) && ix86_match_ccmode (insn, - /* *testdi_1 requires CCZmode if the mask has bit + /* If zero_extract mode precision is the same + as len, the SF of the zero_extract + comparison will be the most significant + extracted bit, but this could be matched + after splitting only for pos 0 len all bits + trivial extractions. Require CCZmode. */ + (GET_MODE_PRECISION (<MODE>mode) + == INTVAL (operands[3])) + /* Otherwise, require CCZmode if we'd use a mask + with the most significant bit set and can't + widen it to wider mode. *testdi_1 also + requires CCZmode if the mask has bit 31 set and all bits above it clear. */ - GET_MODE (operands[2]) == DImode - && INTVAL (operands[3]) + INTVAL (operands[4]) == 32 + || (INTVAL (operands[3]) + INTVAL (operands[4]) + >= 32) + /* We can't widen also if val is not a REG. */ + || (INTVAL (operands[3]) + INTVAL (operands[4]) + == GET_MODE_PRECISION (GET_MODE (operands[2])) + && !register_operand (operands[2], + GET_MODE (operands[2]))) + /* And we shouldn't widen if + TARGET_PARTIAL_REG_STALL. */ + || (TARGET_PARTIAL_REG_STALL + && (INTVAL (operands[3]) + INTVAL (operands[4]) + >= (paradoxical_subreg_p (operands[2]) + && (GET_MODE_CLASS + (GET_MODE (SUBREG_REG (operands[2]))) + == MODE_INT) + ? GET_MODE_PRECISION + (GET_MODE (SUBREG_REG (operands[2]))) + : GET_MODE_PRECISION + (GET_MODE (operands[2]))))) ? CCZmode : CCNOmode)" "#" "&& 1" @@ -8750,7 +8778,10 @@ /* Narrow paradoxical subregs to prevent partial register stalls. */ if (GET_MODE_BITSIZE (mode) > GET_MODE_BITSIZE (submode) - && GET_MODE_CLASS (submode) == MODE_INT) + && GET_MODE_CLASS (submode) == MODE_INT + && (GET_MODE (operands[0]) == CCZmode + || pos + len < GET_MODE_PRECISION (submode) + || REG_P (SUBREG_REG (val)))) { val = SUBREG_REG (val); mode = submode; @@ -8758,14 +8789,32 @@ } /* Small HImode tests can be converted to QImode. */ - if (register_operand (val, HImode) && pos + len <= 8) + if (pos + len <= 8 + && register_operand (val, HImode)) { - val = gen_lowpart (QImode, val); - mode = QImode; + rtx nval = gen_lowpart (QImode, val); + if (!MEM_P (nval) + || GET_MODE (operands[0]) == CCZmode + || pos + len < 8) + { + val = nval; + mode = QImode; + } } gcc_assert (pos + len <= GET_MODE_PRECISION (mode)); + /* If the mask is going to have the sign bit set in the mode + we want to do the comparison in and user isn't interested just + in the zero flag, then we must widen the target mode. */ + if (pos + len == GET_MODE_PRECISION (mode) + && GET_MODE (operands[0]) != CCZmode) + { + gcc_assert (pos + len < 32 && !MEM_P (val)); + mode = SImode; + val = gen_lowpart (mode, val); + } + wide_int mask = wi::shifted_mask (pos, len, false, GET_MODE_PRECISION (mode)); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index b98c72cdd2af6164310dfbd11ded84c39617ab7f..830ee92357e5bac7429b3b5026eb1378550ee30f 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2020-04-17 Jakub Jelinek <jakub@redhat.com> + Jeff Law <law@redhat.com> + + PR target/94567 + * gcc.c-torture/execute/pr94567.c: New test. + 2020-04-17 Nathan Sidwell <nathan@acm.org> PR c++/94608 diff --git a/gcc/testsuite/gcc.c-torture/execute/pr94567.c b/gcc/testsuite/gcc.c-torture/execute/pr94567.c new file mode 100644 index 0000000000000000000000000000000000000000..679d73d2ef42392eedbbb57cbac805db45a3be89 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/pr94567.c @@ -0,0 +1,26 @@ +/* PR target/94567 */ + +volatile int a = 1, b; +short c, d = 4, f = 2, g; +unsigned short e = 53736; + +int +foo (int i, int j) +{ + return i && j ? 0 : i + j; +} + +int +main () +{ + for (; a; a = 0) + { + unsigned short k = e; + g = k >> 3; + if (foo (g < (f || c), b)) + d = 0; + } + if (d != 4) + __builtin_abort (); + return 0; +}