}
\f
/* Return TRUE and set op[0] if T, following all SSA edges, is a type
- conversion. */
+ conversion. Reject loads if LOAD is NULL, otherwise set *LOAD if a
+ converting load is found. */
static bool
-gimple_convert_def_p (tree t, tree op[1])
+gimple_convert_def_p (tree t, tree op[1], gimple **load = NULL)
{
+ bool ret = false;
+
if (TREE_CODE (t) == SSA_NAME
&& !SSA_NAME_IS_DEFAULT_DEF (t))
if (gassign *def = dyn_cast <gassign *> (SSA_NAME_DEF_STMT (t)))
- switch (gimple_assign_rhs_code (def))
- {
- CASE_CONVERT:
- op[0] = gimple_assign_rhs1 (def);
- return true;
- case VIEW_CONVERT_EXPR:
- op[0] = TREE_OPERAND (gimple_assign_rhs1 (def), 0);
- return true;
- default:
- break;
- }
- return false;
+ {
+ bool load_p = gimple_assign_load_p (def);
+ if (load_p && !load)
+ return false;
+ switch (gimple_assign_rhs_code (def))
+ {
+ CASE_CONVERT:
+ op[0] = gimple_assign_rhs1 (def);
+ ret = true;
+ break;
+
+ case VIEW_CONVERT_EXPR:
+ op[0] = TREE_OPERAND (gimple_assign_rhs1 (def), 0);
+ ret = true;
+ break;
+
+ default:
+ break;
+ }
+
+ if (ret && load_p)
+ *load = def;
+ }
+
+ return ret;
}
/* Return TRUE and set op[*] if T, following all SSA edges, resolves to a
return NULL_TREE;
}
- /* Yet another chance to drop conversions. */
- if (gimple_convert_def_p (exp, res_ops))
+ /* Yet another chance to drop conversions. This one is allowed to
+ match a converting load, subsuming the load identification block
+ below. */
+ if (gimple_convert_def_p (exp, res_ops, load))
{
if (!outer_type)
{
outer_type = TREE_TYPE (exp);
loc[0] = gimple_location (SSA_NAME_DEF_STMT (exp));
}
+ if (*load)
+ loc[3] = gimple_location (*load);
exp = res_ops[0];
}
/* Identify the load, if there is one. */
- if (TREE_CODE (exp) == SSA_NAME
+ if (!(*load) && TREE_CODE (exp) == SSA_NAME
&& !SSA_NAME_IS_DEFAULT_DEF (exp))
{
gimple *def = SSA_NAME_DEF_STMT (exp);
/* It must be true that the inner operation on the lhs of each
comparison must be the same if we are to be able to do anything.
Then see if we have constants. If not, the same must be true for
- the rhs's. */
+ the rhs's. If one is a load and the other isn't, we have to be
+ conservative and avoid the optimization, otherwise we could get
+ SRAed fields wrong. */
if (volatilep
|| ll_reversep != rl_reversep
- || ll_inner == 0 || rl_inner == 0
- || ! operand_equal_p (ll_inner, rl_inner, 0)
- || (ll_load && rl_load
- && gimple_vuse (ll_load) != gimple_vuse (rl_load)))
+ || ll_inner == 0 || rl_inner == 0)
+ return 0;
+
+ if (! operand_equal_p (ll_inner, rl_inner, 0))
+ {
+ /* Try swapping the operands. */
+ if (ll_reversep != rr_reversep
+ || !rr_inner
+ || !operand_equal_p (ll_inner, rr_inner, 0))
+ return 0;
+
+ rcode = swap_tree_comparison (rcode);
+ std::swap (rl_arg, rr_arg);
+ std::swap (rl_inner, rr_inner);
+ std::swap (rl_bitsize, rr_bitsize);
+ std::swap (rl_bitpos, rr_bitpos);
+ std::swap (rl_unsignedp, rr_unsignedp);
+ std::swap (rl_reversep, rr_reversep);
+ std::swap (rl_and_mask, rr_and_mask);
+ std::swap (rl_load, rr_load);
+ std::swap (rl_loc, rr_loc);
+ }
+
+ if ((ll_load && rl_load)
+ ? gimple_vuse (ll_load) != gimple_vuse (rl_load)
+ : (!ll_load != !rl_load))
return 0;
if (TREE_CODE (lr_arg) == INTEGER_CST
else if (lr_reversep != rr_reversep
|| lr_inner == 0 || rr_inner == 0
|| ! operand_equal_p (lr_inner, rr_inner, 0)
- || (lr_load && rr_load
- && gimple_vuse (lr_load) != gimple_vuse (rr_load)))
+ || ((lr_load && rr_load)
+ ? gimple_vuse (lr_load) != gimple_vuse (rr_load)
+ : (!lr_load != !rr_load)))
return 0;
/* If we found sign tests, finish turning them into bit tests. */
--- /dev/null
+/* { dg-do run } */
+/* { dg-options "-O -fdump-tree-ifcombine-details" } */
+
+/* Check that we optimize swapped compares, and that we don't load from objects
+ before they're fully initialized. */
+
+struct pair {
+ signed char a;
+ signed char b;
+} __attribute__ ((aligned (2)));
+
+#define make_pair(a,b) { a, b }
+
+struct s {
+ struct pair c;
+ struct pair d;
+} __attribute__ ((aligned (4)));
+
+struct pair cp = make_pair (127, -1);
+struct pair dp = make_pair (42, 0xf1);
+
+struct pair cq = make_pair (127, -1);
+struct pair dq = make_pair (42, 0xf1);
+
+struct pair cr = make_pair (-127, -1);
+struct pair dr = make_pair (42, 0xff);
+
+static __attribute__ ((noinline, noclone, noipa))
+struct pair copy_pair (struct pair c)
+{
+ return c;
+}
+
+static inline
+struct s
+make_s (struct pair c, struct pair d)
+{
+ struct s r;
+ r.c = copy_pair (c);
+ r.d = copy_pair (d);
+ return r;
+}
+
+void f (void) {
+ struct s p = make_s (cp, dp);
+ struct s q = make_s (cq, dr);
+
+ if (0
+ || p.c.a != q.c.a
+ || q.c.b != p.c.b
+ || p.d.b != q.d.b
+ || q.d.a != p.d.a
+ )
+ return;
+ __builtin_abort ();
+}
+
+void g (void) {
+ struct s p = make_s (cp, dp);
+ struct s q = make_s (cr, dq);
+
+ if (0
+ || p.c.a != q.c.a
+ || q.c.b != p.c.b
+ || p.d.b != q.d.b
+ || q.d.a != p.d.a
+ )
+ return;
+ __builtin_abort ();
+}
+
+void h (void) {
+ struct s p = make_s (cp, dp);
+ struct s q = make_s (cq, dq);
+
+ if (0
+ || p.c.a != q.c.a
+ || q.c.b != p.c.b
+ || p.d.b != q.d.b
+ || q.d.a != p.d.a
+ )
+ __builtin_abort ();
+ return;
+}
+
+int main () {
+ f ();
+ g ();
+ h ();
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "optimizing" 9 "ifcombine" } } */