From 8713d0f1c46f81107ea61781e2f4dc918d0fb67d Mon Sep 17 00:00:00 2001 From: Jeff Law Date: Mon, 4 Sep 2017 08:00:29 -0600 Subject: [PATCH] re PR tree-optimization/64910 (tree reassociation results in poor code) 2017-09-03 Jeff Law PR tree-optimization/64910 * tree-ssa-reassoc.c (reassociate_bb): For bitwise binary ops, swap the first and last operand if the last is a constant. PR tree-optimization/64910 * gcc.dg/tree-ssa/pr64910-2.c: New test. From-SVN: r251659 --- gcc/ChangeLog | 6 ++ gcc/testsuite/ChangeLog | 5 ++ gcc/testsuite/gcc.dg/tree-ssa/pr64910-2.c | 85 +++++++++++++++++++++++ gcc/tree-ssa-reassoc.c | 12 ++++ 4 files changed, 108 insertions(+) create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr64910-2.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 0bc8b4b9b18..5170417bbb0 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2017-09-04 Jeff Law + + PR tree-optimization/64910 + * tree-ssa-reassoc.c (reassociate_bb): For bitwise binary ops, + swap the first and last operand if the last is a constant. + 2017-09-04 Marek Polacek PR sanitizer/82072 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 45cee1fe463..8920c76f8c5 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2017-09-04 Jeff Law + + PR tree-optimization/64910 + * gcc.dg/tree-ssa/pr64910-2.c: New test. + 2017-09-04 Marek Polacek PR sanitizer/82072 diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr64910-2.c b/gcc/testsuite/gcc.dg/tree-ssa/pr64910-2.c new file mode 100644 index 00000000000..2e3d6790776 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr64910-2.c @@ -0,0 +1,85 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-reassoc1" } */ + +/* We want to make sure that we reassociate in a way that has the + constant last. With the constant last, it's more likely to result + in a bitfield test on targets with such capabilities. */ + +extern void boo (); + +int b2b_uc (unsigned char u, unsigned char w) +{ + if ((u & w) & 0x20) + boo (); +} + +int b2b_us (unsigned short u, unsigned short w) +{ + if ((u & w) & 0x20) + boo (); +} + +int b2b_ui (unsigned int u, unsigned int w) +{ + if ((u & w) & 0x20) + boo (); +} +int b2b_ul (unsigned long u, unsigned long w) +{ + if ((u & w) & 0x20) + boo (); +} +int b2b_ull (unsigned long long u, unsigned long long w) +{ + if ((u & w) & 0x20) + boo (); +} + +int b2b_sc (signed char u, signed char w) +{ + if ((u & w) & 0x20) + boo (); +} + +int b2b_ss (signed short u, signed short w) +{ + if ((u & w) & 0x20) + boo (); +} + +int b2b_si (signed int u, signed int w) +{ + if ((u & w) & 0x20) + boo (); +} +int b2b_sl (signed long u, signed long w) +{ + if ((u & w) & 0x20) + boo (); +} +int b2b_sll (signed long long u, signed long long w) +{ + if ((u & w) & 0x20) + boo (); +} + +/* The AND of U & W should go into a temporary, when is then ANDed + with the constant. + + First verify that we have the right number of ANDs between U and W. */ +/* { dg-final { scan-tree-dump-times "\[uw\]_\[0-9\]+.D. \& \[uw\]_\[0-9\]+.D.;" 10 "reassoc1"} } */ + +/* Then verify that we have the right number of ANDS between a temporary + and the constant. */ +/* { dg-final { scan-tree-dump-times "_\[0-9]+ \& 32;" 10 "reassoc1"} } */ + +/* Each function has one AND. It will have either a second AND or TEST. So + we can count the number of AND and TEST instructions. They must be 2X + the number of test functions in this file. */ +/* { dg-final { scan-assembler-times "and|test" 20 { target { i?86-*-* x86_64-*-*} } } } */ + +/* Similarly on the m68k. The code for the long long tests is suboptimal, + which catch via the second pattern and xfail. */ +/* { dg-final { scan-assembler-times "and|btst" 20 { target { m68k-*-* } } } } */ +/* { dg-final { scan-assembler-not "or" { target { m68k-*-* } xfail { *-*-* } } } } */ + diff --git a/gcc/tree-ssa-reassoc.c b/gcc/tree-ssa-reassoc.c index 561acea4dcc..76048196b27 100644 --- a/gcc/tree-ssa-reassoc.c +++ b/gcc/tree-ssa-reassoc.c @@ -5762,6 +5762,18 @@ reassociate_bb (basic_block bb) fprintf (dump_file, "Width = %d was chosen for reassociation\n", width); + + /* For binary bit operations, if the last operand in + OPS is a constant, move it to the front. This + helps ensure that we generate (X & Y) & C rather + than (X & C) & Y. The former will often match + a canonical bit test when we get to RTL. */ + if ((rhs_code == BIT_AND_EXPR + || rhs_code == BIT_IOR_EXPR + || rhs_code == BIT_XOR_EXPR) + && TREE_CODE (ops.last ()->op) == INTEGER_CST) + std::swap (*ops[0], *ops[ops_num - 1]); + if (width > 1 && ops.length () > 3) rewrite_expr_tree_parallel (as_a (stmt), -- 2.30.2