Commit 0db8ddfc by Jeff Law Committed by Jeff Law

re PR tree-optimization/81741 (Misoptimisation : replacing a constant field read…

re PR tree-optimization/81741 (Misoptimisation : replacing a constant field read access by a function call)

	PR tree-optimization/81741
	PR tree-optimization/71947
	* tree-ssa-dom.c: Include tree-inline.h.
	(record_temporary_equivalences): Only record SSA_NAME = SSA_NAME
	equivalences if one is more expensive to compute than the other.
	* tree-ssa-scopedtables.h (class const_or_copies): Make
	record_const_or_copy_raw method private.
	(class avail_exprs_stack): New method simplify_binary_operation.
	* tree-ssa-scopedtables.c (avail_exprs_stack::lookup_avail_expr): Call
	avail_exprs_stack::simplify_binary_operation as needed.
	(avail_exprs_stack::simplify_binary_operation): New function.

	PR tree-optimization/81741
	PR tree-optimization/71947
	* gcc.dg/tree-ssa/pr81741.c: New test.
	* gcc.dg/tree-ssa/pr71947-7.c: New test.
	* gcc.dg/tree-ssa/pr71947-8.c: New test.
	* gcc.dg/tree-ssa/pr71947-9.c: New test.
	* gcc.dg/tree-ssa/pr71941-1.c: Tweak expected output.
	* gcc.dg/tree-ssa/pr71941-2.c: Tweak expected output.
	* gcc.dg/tree-ssa/pr71941-3.c: Tweak expected output.
	* gcc.dg/tree-ssa/20030922-2.c: xfail.

From-SVN: r251279
parent d4c550fd
2017-08-22 Jeff Law <law@redhat.com>
PR tree-optimization/81741
PR tree-optimization/71947
* tree-ssa-dom.c: Include tree-inline.h.
(record_temporary_equivalences): Only record SSA_NAME = SSA_NAME
equivalences if one is more expensive to compute than the other.
* tree-ssa-scopedtables.h (class const_or_copies): Make
record_const_or_copy_raw method private.
(class avail_exprs_stack): New method simplify_binary_operation.
* tree-ssa-scopedtables.c (avail_exprs_stack::lookup_avail_expr): Call
avail_exprs_stack::simplify_binary_operation as needed.
(avail_exprs_stack::simplify_binary_operation): New function.
2017-08-22 Sebastian Huber <sebastian.huber@embedded-brains.de> 2017-08-22 Sebastian Huber <sebastian.huber@embedded-brains.de>
* config.gcc (powerpc-*-rtems*): Add rs6000/linux64.opt. * config.gcc (powerpc-*-rtems*): Add rs6000/linux64.opt.
......
2017-08-22 Jeff Law <law@redhat.com>
PR tree-optimization/81741
PR tree-optimization/71947
* gcc.dg/tree-ssa/pr81741.c: New test.
* gcc.dg/tree-ssa/pr71947-7.c: New test.
* gcc.dg/tree-ssa/pr71947-8.c: New test.
* gcc.dg/tree-ssa/pr71947-9.c: New test.
* gcc.dg/tree-ssa/pr71941-1.c: Tweak expected output.
* gcc.dg/tree-ssa/pr71941-2.c: Tweak expected output.
* gcc.dg/tree-ssa/pr71941-3.c: Tweak expected output.
* gcc.dg/tree-ssa/20030922-2.c: xfail.
2017-08-22 Yvan Roux <yvan.roux@linaro.org> 2017-08-22 Yvan Roux <yvan.roux@linaro.org>
PR c++/80287 PR c++/80287
......
...@@ -20,4 +20,6 @@ rgn_rank (rtx insn1, rtx insn2) ...@@ -20,4 +20,6 @@ rgn_rank (rtx insn1, rtx insn2)
} }
/* There should be two IF conditionals. */ /* There should be two IF conditionals. */
/* { dg-final { scan-tree-dump-times "if " 2 "dom2" } } */ /* We no longer record the conditional equivalence by design, thus we
are unable to simplify the 3rd conditional at compile time. */
/* { dg-final { scan-tree-dump-times "if " 2 "dom2" { xfail *-*-* } } } */
...@@ -14,6 +14,6 @@ int f(int x, int y) ...@@ -14,6 +14,6 @@ int f(int x, int y)
return ret; return ret;
} }
/* { dg-final { scan-tree-dump "Folded to: ret_\[0-9\]+ = 0;" "dom2" } } */ /* { dg-final { scan-tree-dump "Replaced redundant expr \[^\r\n\]* with .0." "dom2" } } */
...@@ -13,4 +13,4 @@ int f(int x, int y) ...@@ -13,4 +13,4 @@ int f(int x, int y)
return ret; return ret;
} }
/* { dg-final { scan-tree-dump "Folded to: ret_\[0-9\]+ = 0;" "dom2" } } */ /* { dg-final { scan-tree-dump "Replaced redundant expr \[^\r\n\]* with .0." "dom2" } } */
...@@ -9,4 +9,5 @@ int f(int x, int y) ...@@ -9,4 +9,5 @@ int f(int x, int y)
return ret; return ret;
} }
/* { dg-final { scan-tree-dump "Folded to: ret_\[0-9\]+ = 0;" "dom2" } } */ /* { dg-final { scan-tree-dump "Replaced redundant expr \[^\r\n\]* with .0." "dom2" } } */
/* { dg-do compile } */
/* { dg-options "-O2 -fno-tree-vrp -fdump-tree-dom-details" } */
int f(int x, int y)
{
int ret;
if (x == y)
ret = x % y;
else
ret = 1;
return ret;
}
/* { dg-final { scan-tree-dump "Replaced redundant expr \[^\r\n\]* with .0." "dom2" } } */
/* { dg-do compile } */
/* { dg-options "-O2 -fno-tree-vrp -fdump-tree-dom-details" } */
int f(int x, int y)
{
int ret;
if (x == y)
ret = x / y;
else
ret = 0;
return ret;
}
/* { dg-final { scan-tree-dump "Replaced redundant expr \[^\r\n\]* with .1." "dom2" } } */
/* { dg-do compile } */
/* { dg-options "-O2 -fno-tree-vrp -fdump-tree-dom-details" } */
int f(int x, int y)
{
int ret;
if (x == y)
ret = x & y;
else
ret = 0;
return ret;
}
/* { dg-final { scan-tree-dump "Replaced redundant expr \[^\r\n\]* with .\(x|y\)." "dom2" } } */
/* { dg-do compile } */
/* { dg-options "-O2 -w -fdump-tree-dom2-details" } */
#include <string.h>
typedef struct string_s {
unsigned long size, alloc;
char *ptr;
} string_t[1];
# define M_ASSUME(x) \
(! __builtin_constant_p (!!(x) || !(x)) || (x) ? \
(void) 0 : __builtin_unreachable())
int f(string_t s)
{
M_ASSUME(strlen(s->ptr) == s->size);
return s->size;
}
/* { dg-final { scan-assembler-not "strlen" } } */
...@@ -32,6 +32,7 @@ along with GCC; see the file COPYING3. If not see ...@@ -32,6 +32,7 @@ along with GCC; see the file COPYING3. If not see
#include "cfgloop.h" #include "cfgloop.h"
#include "gimple-fold.h" #include "gimple-fold.h"
#include "tree-eh.h" #include "tree-eh.h"
#include "tree-inline.h"
#include "gimple-iterator.h" #include "gimple-iterator.h"
#include "tree-cfg.h" #include "tree-cfg.h"
#include "tree-into-ssa.h" #include "tree-into-ssa.h"
...@@ -776,16 +777,27 @@ record_temporary_equivalences (edge e, ...@@ -776,16 +777,27 @@ record_temporary_equivalences (edge e,
/* Record the simple NAME = VALUE equivalence. */ /* Record the simple NAME = VALUE equivalence. */
tree rhs = edge_info->rhs; tree rhs = edge_info->rhs;
record_equality (lhs, rhs, const_and_copies);
/* We already recorded that LHS = RHS, with canonicalization, /* If this is a SSA_NAME = SSA_NAME equivalence and one operand is
value chain following, etc. cheaper to compute than the other, then set up the equivalence
such that we replace the expensive one with the cheap one.
We also want to record RHS = LHS, but without any canonicalization If they are the same cost to compute, then do not record anything. */
or value chain following. */ if (TREE_CODE (lhs) == SSA_NAME && TREE_CODE (rhs) == SSA_NAME)
if (TREE_CODE (rhs) == SSA_NAME) {
const_and_copies->record_const_or_copy_raw (rhs, lhs, gimple *rhs_def = SSA_NAME_DEF_STMT (rhs);
SSA_NAME_VALUE (rhs)); int rhs_cost = estimate_num_insns (rhs_def, &eni_size_weights);
gimple *lhs_def = SSA_NAME_DEF_STMT (lhs);
int lhs_cost = estimate_num_insns (lhs_def, &eni_size_weights);
if (rhs_cost > lhs_cost)
record_equality (rhs, lhs, const_and_copies);
else if (rhs_cost < lhs_cost)
record_equality (lhs, rhs, const_and_copies);
}
else
record_equality (lhs, rhs, const_and_copies);
/* If LHS is an SSA_NAME and RHS is a constant integer and LHS was /* If LHS is an SSA_NAME and RHS is a constant integer and LHS was
set via a widening type conversion, then we may be able to record set via a widening type conversion, then we may be able to record
......
...@@ -116,6 +116,102 @@ vuse_eq (ao_ref *, tree vuse1, unsigned int cnt, void *data) ...@@ -116,6 +116,102 @@ vuse_eq (ao_ref *, tree vuse1, unsigned int cnt, void *data)
return NULL; return NULL;
} }
/* We looked for STMT in the hash table, but did not find it.
If STMT is an assignment from a binary operator, we may know something
about the operands relationship to each other which would allow
us to derive a constant value for the RHS of STMT. */
tree
avail_exprs_stack::simplify_binary_operation (gimple *stmt,
class expr_hash_elt element)
{
if (is_gimple_assign (stmt))
{
struct hashable_expr *expr = element.expr ();
if (expr->kind == EXPR_BINARY)
{
enum tree_code code = expr->ops.binary.op;
switch (code)
{
/* For these cases, if we know the operands
are equal, then we know the result. */
case MIN_EXPR:
case MAX_EXPR:
case BIT_IOR_EXPR:
case BIT_AND_EXPR:
case BIT_XOR_EXPR:
case MINUS_EXPR:
case TRUNC_DIV_EXPR:
case CEIL_DIV_EXPR:
case FLOOR_DIV_EXPR:
case ROUND_DIV_EXPR:
case EXACT_DIV_EXPR:
case TRUNC_MOD_EXPR:
case CEIL_MOD_EXPR:
case FLOOR_MOD_EXPR:
case ROUND_MOD_EXPR:
{
/* Build a simple equality expr and query the hash table
for it. */
struct hashable_expr expr;
expr.type = boolean_type_node;
expr.kind = EXPR_BINARY;
expr.ops.binary.op = EQ_EXPR;
expr.ops.binary.opnd0 = gimple_assign_rhs1 (stmt);
expr.ops.binary.opnd1 = gimple_assign_rhs2 (stmt);
class expr_hash_elt element2 (&expr, NULL_TREE);
expr_hash_elt **slot
= m_avail_exprs->find_slot (&element2, NO_INSERT);
tree result_type = TREE_TYPE (gimple_assign_lhs (stmt));
/* If the query was successful and returned a nonzero
result, then we know that the operands of the binary
expression are the same. In many cases this allows
us to compute a constant result of the expression
at compile time, even if we do not know the exact
values of the operands. */
if (slot && *slot && integer_onep ((*slot)->lhs ()))
{
switch (code)
{
case MIN_EXPR:
case MAX_EXPR:
case BIT_IOR_EXPR:
case BIT_AND_EXPR:
return gimple_assign_rhs1 (stmt);
case BIT_XOR_EXPR:
case MINUS_EXPR:
case TRUNC_MOD_EXPR:
case CEIL_MOD_EXPR:
case FLOOR_MOD_EXPR:
case ROUND_MOD_EXPR:
return build_zero_cst (result_type);
case TRUNC_DIV_EXPR:
case CEIL_DIV_EXPR:
case FLOOR_DIV_EXPR:
case ROUND_DIV_EXPR:
case EXACT_DIV_EXPR:
return build_one_cst (result_type);
default:
gcc_unreachable ();
}
}
break;
}
default:
break;
}
}
}
return NULL_TREE;
}
/* Search for an existing instance of STMT in the AVAIL_EXPRS_STACK table. /* Search for an existing instance of STMT in the AVAIL_EXPRS_STACK table.
If found, return its LHS. Otherwise insert STMT in the table and If found, return its LHS. Otherwise insert STMT in the table and
return NULL_TREE. return NULL_TREE.
...@@ -160,6 +256,12 @@ avail_exprs_stack::lookup_avail_expr (gimple *stmt, bool insert, bool tbaa_p) ...@@ -160,6 +256,12 @@ avail_exprs_stack::lookup_avail_expr (gimple *stmt, bool insert, bool tbaa_p)
} }
else if (*slot == NULL) else if (*slot == NULL)
{ {
/* If we did not find the expression in the hash table, we may still
be able to produce a result for some expressions. */
tree alt = avail_exprs_stack::simplify_binary_operation (stmt, element);
if (alt)
return alt;
class expr_hash_elt *element2 = new expr_hash_elt (element); class expr_hash_elt *element2 = new expr_hash_elt (element);
*slot = element2; *slot = element2;
......
...@@ -156,6 +156,11 @@ class avail_exprs_stack ...@@ -156,6 +156,11 @@ class avail_exprs_stack
vec<std::pair<expr_hash_elt_t, expr_hash_elt_t> > m_stack; vec<std::pair<expr_hash_elt_t, expr_hash_elt_t> > m_stack;
hash_table<expr_elt_hasher> *m_avail_exprs; hash_table<expr_elt_hasher> *m_avail_exprs;
/* For some assignments where the RHS is a binary operator, if we know
a equality relationship between the operands, we may be able to compute
a result, even if we don't know the exact value of the operands. */
tree simplify_binary_operation (gimple *, class expr_hash_elt);
/* We do not allow copying this object or initializing one /* We do not allow copying this object or initializing one
from another. */ from another. */
avail_exprs_stack& operator= (const avail_exprs_stack&); avail_exprs_stack& operator= (const avail_exprs_stack&);
...@@ -185,10 +190,6 @@ class const_and_copies ...@@ -185,10 +190,6 @@ class const_and_copies
may follow the value chain for the RHS. */ may follow the value chain for the RHS. */
void record_const_or_copy (tree, tree); void record_const_or_copy (tree, tree);
/* Record a single const/copy pair that can be unwound. This version
does not follow the value chain for the RHS. */
void record_const_or_copy_raw (tree, tree, tree);
/* Special entry point when we want to provide an explicit previous /* Special entry point when we want to provide an explicit previous
value for the first argument. Try to get rid of this in the future. value for the first argument. Try to get rid of this in the future.
...@@ -196,6 +197,10 @@ class const_and_copies ...@@ -196,6 +197,10 @@ class const_and_copies
void record_const_or_copy (tree, tree, tree); void record_const_or_copy (tree, tree, tree);
private: private:
/* Record a single const/copy pair that can be unwound. This version
does not follow the value chain for the RHS. */
void record_const_or_copy_raw (tree, tree, tree);
vec<tree> m_stack; vec<tree> m_stack;
const_and_copies& operator= (const const_and_copies&); const_and_copies& operator= (const const_and_copies&);
const_and_copies (class const_and_copies &); const_and_copies (class const_and_copies &);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment