diff --git a/gcc/testsuite/gcc.dg/torture/sso-fre-1.c b/gcc/testsuite/gcc.dg/torture/sso-fre-1.c
new file mode 100644
index 00000000000..2862517f838
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/sso-fre-1.c
@@ -0,0 +1,43 @@
+/* { dg-do run } */
+/* { dg-require-effective-target le } */
+
+/* Value numbering used to translate a reference through an aggregate copy
+   by folding the components of the reference into a constant offset into
+   the right-hand side of the copy.  A reversed storage order is a property
+   of the component and not of its position, so it was lost in the process
+   and the load of F7 below was resolved to the least significant bits of
+   the byte instead of to its most significant bits.  */
+
+struct __attribute__((scalar_storage_order("big-endian"))) S0
+{
+  signed f7 : 3;
+  unsigned f6 : 5;
+};
+
+struct S1 { int a; struct S0 f3; char pad; short s; };
+
+struct S1 g;
+struct S1 *escape;
+
+__attribute__((noipa)) int
+foo (void)
+{
+  struct S1 l;
+  struct S0 *q;
+
+  /* Reversed bit order, so this gives f7 == 1 and f6 == 4.  */
+  *(char *) &g.f3 = 0x24;
+  l = g;
+  /* Keep L addressable so that it is not scalarized away.  */
+  escape = &l;
+  q = (struct S0 *) ((char *) &l + __builtin_offsetof (struct S1, f3));
+  return q->f7;
+}
+
+int
+main (void)
+{
+  if (foo () != 1)
+    __builtin_abort ();
+  return 0;
+}
diff --git a/gcc/tree-ssa-sccvn.cc b/gcc/tree-ssa-sccvn.cc
index dbb19e4a498..95b5642ba36 100644
--- a/gcc/tree-ssa-sccvn.cc
+++ b/gcc/tree-ssa-sccvn.cc
@@ -1727,7 +1727,7 @@ contains_storage_order_barrier_p (vec<vn_reference_op_s> ops)
 /* Return true if OPS represent an access with reverse storage order.  */
 
 static bool
-reverse_storage_order_for_component_p (vec<vn_reference_op_s> ops)
+reverse_storage_order_for_component_p (const vec<vn_reference_op_s> &ops)
 {
   unsigned i = 0;
   if (ops[i].opcode == REALPART_EXPR || ops[i].opcode == IMAGPART_EXPR)
@@ -3779,6 +3779,17 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *data_,
       tree rhs1 = gimple_assign_rhs1 (def_stmt);
       copy_reference_ops_from_ref (rhs1, &rhs);
 
+      /* When none of the original operands survives the storage order of
+	 the translated reference is the one of the RHS of the copy.  The
+	 operands we folded into a constant offset above may well have
+	 specified a reverse storage order, which is a property of the
+	 component and not of its position, so it is not recoverable from
+	 that offset.  Punt unless both accesses are in natural order.  */
+      if (i < 0
+	  && (reverse_storage_order_for_component_p (vr->operands)
+	      || reverse_storage_order_for_component_p (rhs)))
+	return (void *)-1;
+
       /* Apply an extra offset to the inner MEM_REF of the RHS.  */
       bool force_no_tbaa = false;
       if (maybe_ne (extra_off, 0))
