Commit 64ea4e15 by Richard Biener Committed by Richard Biener

re PR tree-optimization/70497 (Missed CSE of subregs on GIMPLE)

2016-05-10  Richard Biener  <rguenther@suse.de>

	PR tree-optimization/70497
	PR tree-optimization/28367
	* tree-ssa-sccvn.c (vn_nary_build_or_lookup): New function
	split out from ...
	(visit_reference_op_load): ... here.
	(vn_reference_lookup_3): Use it to handle subreg-like accesses
	with simplified BIT_FIELD_REFs.
	* tree-ssa-pre.c (eliminate_insert): Handle inserting BIT_FIELD_REFs.
	* tree-complex.c (extract_component): Handle BIT_FIELD_REFs
	correctly.

	* gcc.dg/torture/20160404-1.c: New testcase.
	* gcc.dg/tree-ssa/ssa-fre-54.c: Likewise.
	* gcc.dg/tree-ssa/ssa-fre-55.c: Likewise.

From-SVN: r236066
parent 5a96dae3
2016-05-10 Richard Biener <rguenther@suse.de>
PR tree-optimization/70497
PR tree-optimization/28367
* tree-ssa-sccvn.c (vn_nary_build_or_lookup): New function
split out from ...
(visit_reference_op_load): ... here.
(vn_reference_lookup_3): Use it to handle subreg-like accesses
with simplified BIT_FIELD_REFs.
* tree-ssa-pre.c (eliminate_insert): Handle inserting BIT_FIELD_REFs.
* tree-complex.c (extract_component): Handle BIT_FIELD_REFs
correctly.
2016-05-10 Pierre-Marie de Rodat <derodat@adacore.com>
* dwarf2out.c (add_abstract_origin_attribute): Adjust
......
2016-05-10 Richard Biener <rguenther@suse.de>
PR tree-optimization/70497
PR tree-optimization/28367
* gcc.dg/torture/20160404-1.c: New testcase.
* gcc.dg/tree-ssa/ssa-fre-54.c: Likewise.
* gcc.dg/tree-ssa/ssa-fre-55.c: Likewise.
2016-05-10 Pierre-Marie de Rodat <derodat@adacore.com>
* gcc.dg/debug/dwarf2/nested_fun.c: New testcase.
......
/* { dg-do compile } */
typedef __UINT64_TYPE__ UINT64;
typedef union {
struct {
unsigned short lo4;
unsigned short lo3;
unsigned short lo2;
unsigned short lo1;
} i;
long double f;
} BID_BINARY80LDOUBLE;
UINT64 __binary80_to_bid32 (long double x)
{
BID_BINARY80LDOUBLE x_in;
x_in.f = x;
return (x_in.i.lo4
+ ((UINT64)x_in.i.lo3 << 16)
+ ((UINT64)x_in.i.lo2 << 32)
+ ((UINT64)x_in.i.lo1 << 48));
}
/* { dg-do run } */
/* { dg-require-effective-target int32plus } */
/* { dg-options "-O -fdump-tree-fre1 -fdump-tree-dse1" } */
extern void abort (void);
union U { int i; char c[4]; short s[2]; };
char __attribute__((noinline,noclone)) foo(int i)
{
union U u;
u.i = i;
/* This should be equivalent to (char) i. */
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
return u.c[0];
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
return u.c[3];
#else
return 0x04;
#endif
}
short __attribute__((noinline,noclone)) baz(int i)
{
union U u;
u.i = i;
/* This should be equivalent to (char) i. */
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
return u.s[0];
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
return u.s[1];
#else
return 0x0304;
#endif
}
char __attribute__((noinline,noclone)) bar(int j)
{
union U u;
u.i = j;
/* This gets simplified to a BIT_FIELD_REF. */
return u.c[2];
}
int main()
{
if (foo (0x01020304) != 0x04)
abort ();
if (baz (0x01020304) != 0x0304)
abort ();
return 0;
}
/* { dg-final { scan-tree-dump "\\(char\\) i_" "fre1" } } */
/* { dg-final { scan-tree-dump "\\(short int\\) i_" "fre1" } } */
/* { dg-final { scan-tree-dump-not "u.i =" "dse1" } } */
/* { dg-do compile } */
/* { dg-options "-O -fdump-tree-optimized" } */
typedef int v4si __attribute__((vector_size(16)));
int f(v4si t)
{
union {
v4si t1;
int t2[4];
} u;
u.t1 = t;
return u.t2[1];
}
/* { dg-final { scan-tree-dump-not "u;" "optimized" } } */
/* { dg-final { scan-tree-dump-times "BIT_FIELD_REF" 1 "optimized" } } */
......@@ -604,6 +604,21 @@ extract_component (gimple_stmt_iterator *gsi, tree t, bool imagpart_p,
case COMPLEX_EXPR:
gcc_unreachable ();
case BIT_FIELD_REF:
{
tree inner_type = TREE_TYPE (TREE_TYPE (t));
t = unshare_expr (t);
TREE_TYPE (t) = inner_type;
TREE_OPERAND (t, 1) = TYPE_SIZE (inner_type);
if (imagpart_p)
TREE_OPERAND (t, 2) = size_binop (PLUS_EXPR, TREE_OPERAND (t, 2),
TYPE_SIZE (inner_type));
if (gimple_p)
t = force_gimple_operand_gsi (gsi, t, true, NULL, true,
GSI_SAME_STMT);
return t;
}
case VAR_DECL:
case RESULT_DECL:
case PARM_DECL:
......
......@@ -3855,19 +3855,28 @@ eliminate_insert (gimple_stmt_iterator *gsi, tree val)
gimple *stmt = gimple_seq_first_stmt (VN_INFO (val)->expr);
if (!is_gimple_assign (stmt)
|| (!CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (stmt))
&& gimple_assign_rhs_code (stmt) != VIEW_CONVERT_EXPR))
&& gimple_assign_rhs_code (stmt) != VIEW_CONVERT_EXPR
&& gimple_assign_rhs_code (stmt) != BIT_FIELD_REF))
return NULL_TREE;
tree op = gimple_assign_rhs1 (stmt);
if (gimple_assign_rhs_code (stmt) == VIEW_CONVERT_EXPR)
if (gimple_assign_rhs_code (stmt) == VIEW_CONVERT_EXPR
|| gimple_assign_rhs_code (stmt) == BIT_FIELD_REF)
op = TREE_OPERAND (op, 0);
tree leader = TREE_CODE (op) == SSA_NAME ? eliminate_avail (op) : op;
if (!leader)
return NULL_TREE;
gimple_seq stmts = NULL;
tree res = gimple_build (&stmts, gimple_assign_rhs_code (stmt),
TREE_TYPE (val), leader);
tree res;
if (gimple_assign_rhs_code (stmt) == BIT_FIELD_REF)
res = gimple_build (&stmts, BIT_FIELD_REF,
TREE_TYPE (val), leader,
TREE_OPERAND (gimple_assign_rhs1 (stmt), 1),
TREE_OPERAND (gimple_assign_rhs1 (stmt), 2));
else
res = gimple_build (&stmts, gimple_assign_rhs_code (stmt),
TREE_TYPE (val), leader);
gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
VN_INFO_GET (res)->valnum = val;
......
......@@ -1610,6 +1610,105 @@ vn_reference_lookup_or_insert_for_pieces (tree vuse,
operands.copy (), value, value_id);
}
static vn_nary_op_t vn_nary_op_insert_stmt (gimple *stmt, tree result);
/* Hook for maybe_push_res_to_seq, lookup the expression in the VN tables. */
static tree
vn_lookup_simplify_result (code_helper rcode, tree type, tree *ops)
{
if (!rcode.is_tree_code ())
return NULL_TREE;
vn_nary_op_t vnresult = NULL;
return vn_nary_op_lookup_pieces (TREE_CODE_LENGTH ((tree_code) rcode),
(tree_code) rcode, type, ops, &vnresult);
}
/* Return a value-number for RCODE OPS... either by looking up an existing
value-number for the simplified result or by inserting the operation. */
static tree
vn_nary_build_or_lookup (code_helper rcode, tree type, tree *ops)
{
tree result = NULL_TREE;
/* We will be creating a value number for
ROCDE (OPS...).
So first simplify and lookup this expression to see if it
is already available. */
mprts_hook = vn_lookup_simplify_result;
bool res = false;
switch (TREE_CODE_LENGTH ((tree_code) rcode))
{
case 1:
res = gimple_resimplify1 (NULL, &rcode, type, ops, vn_valueize);
break;
case 2:
res = gimple_resimplify2 (NULL, &rcode, type, ops, vn_valueize);
break;
case 3:
res = gimple_resimplify3 (NULL, &rcode, type, ops, vn_valueize);
break;
}
mprts_hook = NULL;
gimple *new_stmt = NULL;
if (res
&& gimple_simplified_result_is_gimple_val (rcode, ops))
/* The expression is already available. */
result = ops[0];
else
{
tree val = vn_lookup_simplify_result (rcode, type, ops);
if (!val)
{
gimple_seq stmts = NULL;
result = maybe_push_res_to_seq (rcode, type, ops, &stmts);
if (result)
{
gcc_assert (gimple_seq_singleton_p (stmts));
new_stmt = gimple_seq_first_stmt (stmts);
}
}
else
/* The expression is already available. */
result = val;
}
if (new_stmt)
{
/* The expression is not yet available, value-number lhs to
the new SSA_NAME we created. */
/* Initialize value-number information properly. */
VN_INFO_GET (result)->valnum = result;
VN_INFO (result)->value_id = get_next_value_id ();
gimple_seq_add_stmt_without_update (&VN_INFO (result)->expr,
new_stmt);
VN_INFO (result)->needs_insertion = true;
/* As all "inserted" statements are singleton SCCs, insert
to the valid table. This is strictly needed to
avoid re-generating new value SSA_NAMEs for the same
expression during SCC iteration over and over (the
optimistic table gets cleared after each iteration).
We do not need to insert into the optimistic table, as
lookups there will fall back to the valid table. */
if (current_info == optimistic_info)
{
current_info = valid_info;
vn_nary_op_insert_stmt (new_stmt, result);
current_info = optimistic_info;
}
else
vn_nary_op_insert_stmt (new_stmt, result);
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "Inserting name ");
print_generic_expr (dump_file, result, 0);
fprintf (dump_file, " for expression ");
print_gimple_expr (dump_file, new_stmt, 0, TDF_SLIM);
fprintf (dump_file, "\n");
}
}
return result;
}
/* Callback for walk_non_aliased_vuses. Tries to perform a lookup
from the statement defining VUSE and if not successful tries to
translate *REFP and VR_ through an aggregate copy at the definition
......@@ -1772,15 +1871,16 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *vr_,
/* 3) Assignment from a constant. We can use folds native encode/interpret
routines to extract the assigned bits. */
else if (vn_walk_kind == VN_WALKREWRITE
&& CHAR_BIT == 8 && BITS_PER_UNIT == 8
&& ref->size == maxsize
&& maxsize % BITS_PER_UNIT == 0
&& offset % BITS_PER_UNIT == 0
else if (ref->size == maxsize
&& is_gimple_reg_type (vr->type)
&& !contains_storage_order_barrier_p (vr->operands)
&& gimple_assign_single_p (def_stmt)
&& is_gimple_min_invariant (gimple_assign_rhs1 (def_stmt)))
&& CHAR_BIT == 8 && BITS_PER_UNIT == 8
&& maxsize % BITS_PER_UNIT == 0
&& offset % BITS_PER_UNIT == 0
&& (is_gimple_min_invariant (gimple_assign_rhs1 (def_stmt))
|| (TREE_CODE (gimple_assign_rhs1 (def_stmt)) == SSA_NAME
&& is_gimple_min_invariant (SSA_VAL (gimple_assign_rhs1 (def_stmt))))))
{
tree base2;
HOST_WIDE_INT offset2, size2, maxsize2;
......@@ -1800,6 +1900,9 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *vr_,
unsigned char buffer[64];
int len;
tree rhs = gimple_assign_rhs1 (def_stmt);
if (TREE_CODE (rhs) == SSA_NAME)
rhs = SSA_VAL (rhs);
len = native_encode_expr (gimple_assign_rhs1 (def_stmt),
buffer, sizeof (buffer));
if (len > 0)
......@@ -1824,56 +1927,37 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *vr_,
&& gimple_assign_single_p (def_stmt)
&& TREE_CODE (gimple_assign_rhs1 (def_stmt)) == SSA_NAME)
{
tree rhs1 = gimple_assign_rhs1 (def_stmt);
gimple *def_stmt2 = SSA_NAME_DEF_STMT (rhs1);
if (is_gimple_assign (def_stmt2)
&& (gimple_assign_rhs_code (def_stmt2) == COMPLEX_EXPR
|| gimple_assign_rhs_code (def_stmt2) == CONSTRUCTOR)
&& types_compatible_p (vr->type, TREE_TYPE (TREE_TYPE (rhs1))))
tree base2;
HOST_WIDE_INT offset2, size2, maxsize2;
bool reverse;
base2 = get_ref_base_and_extent (gimple_assign_lhs (def_stmt),
&offset2, &size2, &maxsize2,
&reverse);
if (!reverse
&& maxsize2 != -1
&& maxsize2 == size2
&& operand_equal_p (base, base2, 0)
&& offset2 <= offset
&& offset2 + size2 >= offset + maxsize
/* ??? We can't handle bitfield precision extracts without
either using an alternate type for the BIT_FIELD_REF and
then doing a conversion or possibly adjusting the offset
according to endianess. */
&& (! INTEGRAL_TYPE_P (vr->type)
|| ref->size == TYPE_PRECISION (vr->type))
&& ref->size % BITS_PER_UNIT == 0)
{
tree base2;
HOST_WIDE_INT offset2, size2, maxsize2, off;
bool reverse;
base2 = get_ref_base_and_extent (gimple_assign_lhs (def_stmt),
&offset2, &size2, &maxsize2,
&reverse);
off = offset - offset2;
if (!reverse
&& maxsize2 != -1
&& maxsize2 == size2
&& operand_equal_p (base, base2, 0)
&& offset2 <= offset
&& offset2 + size2 >= offset + maxsize)
code_helper rcode = BIT_FIELD_REF;
tree ops[3];
ops[0] = SSA_VAL (gimple_assign_rhs1 (def_stmt));
ops[1] = bitsize_int (ref->size);
ops[2] = bitsize_int (offset - offset2);
tree val = vn_nary_build_or_lookup (rcode, vr->type, ops);
if (val)
{
tree val = NULL_TREE;
HOST_WIDE_INT elsz
= TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (TREE_TYPE (rhs1))));
if (gimple_assign_rhs_code (def_stmt2) == COMPLEX_EXPR)
{
if (off == 0)
val = gimple_assign_rhs1 (def_stmt2);
else if (off == elsz)
val = gimple_assign_rhs2 (def_stmt2);
}
else if (gimple_assign_rhs_code (def_stmt2) == CONSTRUCTOR
&& off % elsz == 0)
{
tree ctor = gimple_assign_rhs1 (def_stmt2);
unsigned i = off / elsz;
if (i < CONSTRUCTOR_NELTS (ctor))
{
constructor_elt *elt = CONSTRUCTOR_ELT (ctor, i);
if (TREE_CODE (TREE_TYPE (rhs1)) == VECTOR_TYPE)
{
if (TREE_CODE (TREE_TYPE (elt->value))
!= VECTOR_TYPE)
val = elt->value;
}
}
}
if (val)
return vn_reference_lookup_or_insert_for_pieces
(vuse, vr->set, vr->type, vr->operands, val);
vn_reference_t res = vn_reference_lookup_or_insert_for_pieces
(vuse, vr->set, vr->type, vr->operands, val);
return res;
}
}
}
......@@ -2611,18 +2695,6 @@ vn_nary_op_lookup_stmt (gimple *stmt, vn_nary_op_t *vnresult)
return vn_nary_op_lookup_1 (vno1, vnresult);
}
/* Hook for maybe_push_res_to_seq, lookup the expression in the VN tables. */
static tree
vn_lookup_simplify_result (code_helper rcode, tree type, tree *ops)
{
if (!rcode.is_tree_code ())
return NULL_TREE;
vn_nary_op_t vnresult = NULL;
return vn_nary_op_lookup_pieces (TREE_CODE_LENGTH ((tree_code) rcode),
(tree_code) rcode, type, ops, &vnresult);
}
/* Allocate a vn_nary_op_t with LENGTH operands on STACK. */
static vn_nary_op_t
......@@ -3371,69 +3443,9 @@ visit_reference_op_load (tree lhs, tree op, gimple *stmt)
of VIEW_CONVERT_EXPR <TREE_TYPE (result)> (result).
So first simplify and lookup this expression to see if it
is already available. */
mprts_hook = vn_lookup_simplify_result;
code_helper rcode = VIEW_CONVERT_EXPR;
tree ops[3] = { result };
bool res = gimple_resimplify1 (NULL, &rcode, TREE_TYPE (op), ops,
vn_valueize);
mprts_hook = NULL;
gimple *new_stmt = NULL;
if (res
&& gimple_simplified_result_is_gimple_val (rcode, ops))
/* The expression is already available. */
result = ops[0];
else
{
tree val = vn_lookup_simplify_result (rcode, TREE_TYPE (op), ops);
if (!val)
{
gimple_seq stmts = NULL;
result = maybe_push_res_to_seq (rcode, TREE_TYPE (op), ops,
&stmts);
if (result)
{
gcc_assert (gimple_seq_singleton_p (stmts));
new_stmt = gimple_seq_first_stmt (stmts);
}
}
else
/* The expression is already available. */
result = val;
}
if (new_stmt)
{
/* The expression is not yet available, value-number lhs to
the new SSA_NAME we created. */
/* Initialize value-number information properly. */
VN_INFO_GET (result)->valnum = result;
VN_INFO (result)->value_id = get_next_value_id ();
gimple_seq_add_stmt_without_update (&VN_INFO (result)->expr,
new_stmt);
VN_INFO (result)->needs_insertion = true;
/* As all "inserted" statements are singleton SCCs, insert
to the valid table. This is strictly needed to
avoid re-generating new value SSA_NAMEs for the same
expression during SCC iteration over and over (the
optimistic table gets cleared after each iteration).
We do not need to insert into the optimistic table, as
lookups there will fall back to the valid table. */
if (current_info == optimistic_info)
{
current_info = valid_info;
vn_nary_op_insert_stmt (new_stmt, result);
current_info = optimistic_info;
}
else
vn_nary_op_insert_stmt (new_stmt, result);
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "Inserting name ");
print_generic_expr (dump_file, result, 0);
fprintf (dump_file, " for expression ");
print_gimple_expr (dump_file, new_stmt, 0, TDF_SLIM);
fprintf (dump_file, "\n");
}
}
result = vn_nary_build_or_lookup (rcode, TREE_TYPE (op), ops);
}
if (result)
......
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