new file mode 100644
@@ -0,0 +1,26 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -mno-sse" } */
+
+int flag;
+union { double f; unsigned long long i; } u;
+void __attribute__((noinline))
+init ()
+{
+ flag = 1;
+ u.i = 18442936822990639076ULL;
+}
+unsigned long long __attribute__((noinline))
+test ()
+{
+ if (flag)
+ return u.i;
+ else
+ return u.f;
+}
+int main()
+{
+ init ();
+ if (test () != 18442936822990639076ULL)
+ __builtin_abort ();
+ return 0;
+}
@@ -3571,6 +3571,16 @@ do_hoist_insertion (basic_block block)
continue;
}
+ /* If we end up with a punned expression representation and this
+ happens to be a float typed one give up - we can't know for
+ sure whether all paths perform the floating-point load we are
+ about to insert and on some targets this can cause correctness
+ issues. See PR88240. */
+ if (expr->kind == REFERENCE
+ && PRE_EXPR_REFERENCE (expr)->punned
+ && FLOAT_TYPE_P (get_expr_type (expr)))
+ continue;
+
/* OK, we should hoist this value. Perform the transformation. */
pre_stats.hoist_insert++;
if (dump_file && (dump_flags & TDF_DETAILS))
@@ -3601,6 +3601,7 @@ vn_reference_insert (tree op, tree result, tree vuse, tree vdef)
vr1->vuse = vuse_ssa_val (vuse);
vr1->operands = valueize_shared_reference_ops_from_ref (op, &tem).copy ();
vr1->type = TREE_TYPE (op);
+ vr1->punned = 0;
ao_ref op_ref;
ao_ref_init (&op_ref, op);
vr1->set = ao_ref_alias_set (&op_ref);
@@ -3660,6 +3661,7 @@ vn_reference_insert_pieces (tree vuse, alias_set_type set,
vr1->vuse = vuse_ssa_val (vuse);
vr1->operands = valueize_refs (operands);
vr1->type = type;
+ vr1->punned = 0;
vr1->set = set;
vr1->base_set = base_set;
vr1->hashcode = vn_reference_compute_hash (vr1);
@@ -4892,6 +4894,7 @@ visit_reference_op_call (tree lhs, gcall *stmt)
them here. */
vr2->operands = vr1.operands.copy ();
vr2->type = vr1.type;
+ vr2->punned = vr1.punned;
vr2->set = vr1.set;
vr2->base_set = vr1.base_set;
vr2->hashcode = vr1.hashcode;
@@ -4918,10 +4921,11 @@ visit_reference_op_load (tree lhs, tree op, gimple *stmt)
bool changed = false;
tree last_vuse;
tree result;
+ vn_reference_t res;
last_vuse = gimple_vuse (stmt);
result = vn_reference_lookup (op, gimple_vuse (stmt),
- default_vn_walk_kind, NULL, true, &last_vuse);
+ default_vn_walk_kind, &res, true, &last_vuse);
/* We handle type-punning through unions by value-numbering based
on offset and size of the access. Be prepared to handle a
@@ -4943,6 +4947,13 @@ visit_reference_op_load (tree lhs, tree op, gimple *stmt)
gimple_match_op res_op (gimple_match_cond::UNCOND,
VIEW_CONVERT_EXPR, TREE_TYPE (op), result);
result = vn_nary_build_or_lookup (&res_op);
+ if (result
+ && TREE_CODE (result) == SSA_NAME
+ && VN_INFO (result)->needs_insertion)
+ /* Track whether this is the canonical expression for different
+ typed loads. We use that as a stopgap measure for code
+ hoisting when dealing with floating point loads. */
+ res->punned = true;
}
/* When building the conversion fails avoid inserting the reference
@@ -145,6 +145,7 @@ typedef struct vn_reference_s
alias_set_type set;
alias_set_type base_set;
tree type;
+ unsigned punned : 1;
vec<vn_reference_op_s> operands;
tree result;
tree result_vdef;