REF_REVERSE_STORAGE_ORDER is forgotten about when factor_out_conditional_load
was written up so if REF_REVERSE_STORAGE_ORDER was set, it would be lost.
If REF_REVERSE_STORAGE_ORDER was mismatched then it would mess up too.
This fixes that oversight.
Bootstrapped and tested on x86_64-linux-gnu.
PR tree-optimization/126729
gcc/ChangeLog:
* tree-ssa-phiopt.cc (factor_out_conditional_load): Handle
REF_REVERSE_STORAGE_ORDER being set correctly.
gcc/testsuite/ChangeLog:
* gcc.dg/sso/factor_load-1.c: New test.
Signed-off-by: Andrea Pinski <[email protected]>
---
gcc/testsuite/gcc.dg/sso/factor_load-1.c | 61 ++++++++++++++++++++++++
gcc/tree-ssa-phiopt.cc | 14 +++++-
2 files changed, 73 insertions(+), 2 deletions(-)
create mode 100644 gcc/testsuite/gcc.dg/sso/factor_load-1.c
diff --git a/gcc/testsuite/gcc.dg/sso/factor_load-1.c
b/gcc/testsuite/gcc.dg/sso/factor_load-1.c
new file mode 100644
index 00000000000..f5db8b44fba
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/sso/factor_load-1.c
@@ -0,0 +1,61 @@
+/* PR tree-optimization/126729 */
+/* { dg-do run } */
+
+struct S0 { int a; int v; }
__attribute__((scalar_storage_order("little-endian")));
+union U0 { struct S0 s; int i[2]; }
__attribute__((scalar_storage_order("little-endian")));
+struct S1 { int a; int v; }
__attribute__((scalar_storage_order("big-endian")));
+union U1 { struct S1 s; int i[2]; }
__attribute__((scalar_storage_order("big-endian")));
+
+
+__attribute__((noinline))
+int f(void *a, bool b, bool bb)
+{
+ if (b)
+ {
+ union U0 t = *((union U0*)a);
+ if (bb)
+ return t.i[0];
+ return t.s.a;
+ }
+ {
+ union U1 t = *((union U1*)a);
+ if (bb)
+ return t.i[0];
+ return t.s.a;
+ }
+}
+
+__attribute__((noinline))
+int f2(void *a, bool b, bool bb)
+{
+ if (b)
+ {
+ union U1 t = *((union U1*)a);
+ if (bb)
+ return t.i[0];
+ return t.s.a;
+ }
+ {
+ union U1 t = *((union U1*)a);
+ if (bb)
+ return t.i[0];
+ return t.s.a;
+ }
+}
+
+int main()
+{
+ union U1 a;
+ union U0 b;
+ int t = 0xabcd;
+ a.s.a = t;
+ b.s.a = t;
+ if (f((void*)&a, 0, 0) != t)
+ __builtin_abort();
+ if (f((void*)&b, 1, 0) != t)
+ __builtin_abort();
+ if (f2((void*)&a, 1, 0) != t)
+ __builtin_abort();
+ if (f2((void*)&a, 0, 0) != t)
+ __builtin_abort();
+}
diff --git a/gcc/tree-ssa-phiopt.cc b/gcc/tree-ssa-phiopt.cc
index 129a25abffb..784221c83b3 100644
--- a/gcc/tree-ssa-phiopt.cc
+++ b/gcc/tree-ssa-phiopt.cc
@@ -4177,11 +4177,14 @@ factor_out_conditional_load (edge e0, edge e1,
basic_block merge, gphi *phi,
tree index = nullptr;
tree step = nullptr;
tree index2 = nullptr;
+ bool rev_order = false;
/* Both must be *P loads of a compatible value type. The
TBAA alias-ptr type carried by MEM_REF operand 1 need not match; it is
merged the way get_alias_type_for_stmts does when the load is built. */
- if (TREE_CODE (ref0) != MEM_REF)
+ if (TREE_CODE (ref0) == MEM_REF)
+ rev_order = REF_REVERSE_STORAGE_ORDER (ref0);
+ else
{
if (TREE_CODE (ref0) != TARGET_MEM_REF)
return false;
@@ -4193,11 +4196,15 @@ factor_out_conditional_load (edge e0, edge e1,
basic_block merge, gphi *phi,
{
if (index || step || index2)
return false;
+ if (rev_order != REF_REVERSE_STORAGE_ORDER (ref1))
+ return false;
}
else
{
if (TREE_CODE (ref1) != TARGET_MEM_REF)
return false;
+ if (rev_order)
+ return false;
if (!safe_operand_equal_p (index, TMR_INDEX (ref1)))
return false;
if (!safe_operand_equal_p (step, TMR_STEP (ref1)))
@@ -4335,7 +4342,10 @@ factor_out_conditional_load (edge e0, edge e1,
basic_block merge, gphi *phi,
nref = build5 (TARGET_MEM_REF, TREE_TYPE (ref0), newptr,
newindex, index, step, index2);
else
- nref = build2 (MEM_REF, TREE_TYPE (ref0), newptr, newindex);
+ {
+ nref = build2 (MEM_REF, TREE_TYPE (ref0), newptr, newindex);
+ REF_REVERSE_STORAGE_ORDER (nref) = rev_order;
+ }
MR_DEPENDENCE_CLIQUE (nref) = clique;
MR_DEPENDENCE_BASE (nref) = base;
tree res = gimple_phi_result (phi);
--
2.43.0