--- /dev/null
+/* { dg-do compile } */
+/* { dg-require-effective-target vect_float } */
+/* { dg-additional-options "-fdump-tree-lim2-details -fdump-tree-vect-details" } */
+
+/* Test vectorization of "self write" pattern: a[i] = a[0].
+ LICM should hoist a[0] by recognizing that even when i==0 causes
+ aliasing, the stored value equals the loaded value (via SSA). */
+
+#define N 32000
+
+float a[N];
+
+/* Should vectorize. */
+
+void
+test_safe_hoist (void)
+{
+ for (int i = 0; i < N; i++)
+ a[i] = a[0];
+}
+
+/* { dg-final { scan-tree-dump "loop vectorized" "vect" } } */
+/* { dg-final { scan-tree-dump "independent \\(self write\\)" "lim2" } } */
+
--- /dev/null
+/* { dg-do compile } */
+/* { dg-require-effective-target vect_float } */
+/* { dg-additional-options "-fdump-tree-lim2-details -fdump-tree-vect-details" } */
+
+/* Negative test: ensure we don't incorrectly hoist when
+ a store invalidates the loaded value. */
+
+#define N 32000
+
+float a[N];
+
+/* Should NOT hoist: a[0] = 5.0f breaks the SSA dependency. */
+
+void
+test_unsafe_hoist (void)
+{
+ for (int i = 0; i < N; i++)
+ {
+ float x = a[0];
+ a[i] = x;
+ a[0] = 5.0f;
+ }
+}
+
+/* { dg-final { scan-tree-dump-not "independent \\(constant-indexed load" "lim2" } } */
+
ref_always_accessed (loop, stored_p));
}
+/* Returns true if LOAD_REF and STORE_REF form a "self write" pattern
+ where the stored value comes from the loaded value via SSA.
+ Example: a[i] = a[0] is safe to hoist a[0] even when i==0. */
+
+static bool
+is_self_write (im_mem_ref *load_ref, im_mem_ref *store_ref)
+{
+ /* Only handle the simple case with a single access per ref.
+ Bail out on multiple accesses to be conservative. */
+ if (load_ref->accesses_in_loop.length () != 1
+ || store_ref->accesses_in_loop.length () != 1)
+ return false;
+
+ gimple *load_stmt = load_ref->accesses_in_loop[0].stmt;
+ gimple *store_stmt = store_ref->accesses_in_loop[0].stmt;
+
+ if (!is_gimple_assign (load_stmt) || !is_gimple_assign (store_stmt))
+ return false;
+
+ tree loaded_val = gimple_assign_lhs (load_stmt);
+ tree stored_val = gimple_assign_rhs1 (store_stmt);
+
+ if (TREE_CODE (loaded_val) != SSA_NAME || TREE_CODE (stored_val) != SSA_NAME)
+ return false;
+
+ /* Self write: stored value is the loaded value. */
+ return stored_val == loaded_val;
+}
+
/* Returns true if REF1 and REF2 are independent. */
static bool
break;
}
}
+ /* For hoisting loads (lim_raw), allow "self write": the store
+ writes back the loaded value. Example: a[i] = a[0]
+ is safe even when i==0 causes aliasing. */
+ else if (kind == lim_raw
+ && ref->loaded && aref->stored
+ && is_self_write (ref, aref))
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file,
+ "Dependency of refs %u and %u: "
+ "independent (self write).\n",
+ ref->id, aref->id);
+ }
+
else if (!refs_independent_p (ref, aref, kind != sm_waw))
{
indep_p = false;