new file mode 100644
@@ -0,0 +1,17 @@
+
+/* { dg-do compile } */
+/* { dg-options "-Ofast -fdump-tree-ifcvt-details -fno-common -ftree-loop-if-convert-stores" } */
+
+#define LEN 4096
+ __attribute__((aligned(32))) float array[LEN];
+
+void test ()
+{
+ for (int i = 0; i < LEN; i++)
+ {
+ if (array[i] > (float)0.)
+ array[i] =3 ;
+ }
+}
+
+/* { dg-final { scan-tree-dump-times "Applying if-conversion" 1 "ifcvt" } } */
@@ -19,22 +19,23 @@ along with GCC; see the file COPYING3. If not see
#ifndef tree_hash_traits_h
#define tree_hash_traits_h
-
/* Hash for trees based on operand_equal_p. */
struct tree_operand_hash : ggc_ptr_hash <tree_node>
{
- static inline hashval_t hash (const_tree);
- static inline bool equal_keys (const_tree, const_tree);
+ static inline hashval_t hash (const value_type &);
+ static inline bool equal (const value_type &,
+ const compare_type &);
};
inline hashval_t
-tree_operand_hash::hash (const_tree t)
+tree_operand_hash::hash (const value_type &t)
{
return iterative_hash_expr (t, 0);
}
inline bool
-tree_operand_hash::equal_keys (const_tree t1, const_tree t2)
+tree_operand_hash::equal (const value_type &t1,
+ const compare_type &t2)
{
return operand_equal_p (t1, t2, 0);
}
@@ -129,6 +129,12 @@ static basic_block *ifc_bbs;
/* Apply more aggressive (extended) if-conversion if true. */
static bool aggressive_if_conv;
+/* Hash table to store references, DR pairs. */
+static hash_map<tree_operand_hash, data_reference_p> *ref_DR_map;
+
+/* Hash table to store base reference, DR pairs. */
+static hash_map<tree_operand_hash, data_reference_p> *baseref_DR_map;
+
/* Structure used to predicate basic blocks. This is attached to the
->aux field of the BBs in the loop to be if-converted. */
struct bb_predicate {
@@ -592,137 +598,153 @@ struct ifc_dr {
/* -1 when not initialized, 0 when false, 1 when true. */
int rw_unconditionally;
+
+ tree ored_result;
+
};
#define IFC_DR(DR) ((struct ifc_dr *) (DR)->aux)
#define DR_WRITTEN_AT_LEAST_ONCE(DR) (IFC_DR (DR)->written_at_least_once)
#define DR_RW_UNCONDITIONALLY(DR) (IFC_DR (DR)->rw_unconditionally)
-/* Returns true when the memory references of STMT are read or written
- unconditionally. In other words, this function returns true when
- for every data reference A in STMT there exist other accesses to
- a data reference with the same base with predicates that add up (OR-up) to
- the true predicate: this ensures that the data reference A is touched
- (read or written) on every iteration of the if-converted loop. */
-
-static bool
-memrefs_read_or_written_unconditionally (gimple *stmt,
- vec<data_reference_p> drs)
+/* Iterates over DR's and stores refs, DR and base refs, DR pairs in
+ HASH tables. While storing them in HASH table, it checks if the
+ reference is unconditionally read or written and stores that as a flag
+ information. For base reference it checks if it is written atlest once
+ unconditionally and stores it as flag information along with DR.
+ In other words for every data reference A in STMT there exist other
+ accesses to a data reference with the same base with predicates that
+ add up (OR-up) to the true predicate: this ensures that the data
+ reference A is touched (read or written) on every iteration of the
+ if-converted loop. */
+static void
+hash_memrefs_baserefs_and_store_DRs_read_written_info (data_reference_p a)
{
- int i, j;
- data_reference_p a, b;
- tree ca = bb_predicate (gimple_bb (stmt));
- for (i = 0; drs.iterate (i, &a); i++)
- if (DR_STMT (a) == stmt)
- {
- bool found = false;
- int x = DR_RW_UNCONDITIONALLY (a);
-
- if (x == 0)
- return false;
+ data_reference_p *master_dr, *base_master_dr;
+ tree ref = DR_REF (a);
+ tree base_ref = DR_BASE_OBJECT (a);
+ tree ca = bb_predicate (gimple_bb (DR_STMT (a)));
+ bool exsist1, exsist2;
- if (x == 1)
- continue;
+ while (TREE_CODE (ref) == COMPONENT_REF
+ || TREE_CODE (ref) == IMAGPART_EXPR
+ || TREE_CODE (ref) == REALPART_EXPR)
+ ref = TREE_OPERAND (ref, 0);
- for (j = 0; drs.iterate (j, &b); j++)
- {
- tree ref_base_a = DR_REF (a);
- tree ref_base_b = DR_REF (b);
+ master_dr = &ref_DR_map->get_or_insert (ref, &exsist1);
- if (DR_STMT (b) == stmt)
- continue;
+ if (!exsist1)
+ {
+ if (is_true_predicate (ca))
+ {
+ DR_RW_UNCONDITIONALLY (a) = 1;
+ }
- while (TREE_CODE (ref_base_a) == COMPONENT_REF
- || TREE_CODE (ref_base_a) == IMAGPART_EXPR
- || TREE_CODE (ref_base_a) == REALPART_EXPR)
- ref_base_a = TREE_OPERAND (ref_base_a, 0);
+ IFC_DR (a)->ored_result = ca;
+ *master_dr = a;
+ }
+ else
+ {
+ IFC_DR (*master_dr)->ored_result
+ = fold_or_predicates
+ (EXPR_LOCATION (IFC_DR (*master_dr)->ored_result),
+ ca, IFC_DR (*master_dr)->ored_result);
- while (TREE_CODE (ref_base_b) == COMPONENT_REF
- || TREE_CODE (ref_base_b) == IMAGPART_EXPR
- || TREE_CODE (ref_base_b) == REALPART_EXPR)
- ref_base_b = TREE_OPERAND (ref_base_b, 0);
+ if (is_true_predicate (ca)
+ || is_true_predicate (IFC_DR (*master_dr)->ored_result))
+ {
+ DR_RW_UNCONDITIONALLY (*master_dr) = 1;
+ }
+ }
- if (operand_equal_p (ref_base_a, ref_base_b, 0))
- {
- tree cb = bb_predicate (gimple_bb (DR_STMT (b)));
-
- if (DR_RW_UNCONDITIONALLY (b) == 1
- || is_true_predicate (cb)
- || is_true_predicate (ca
- = fold_or_predicates (EXPR_LOCATION (cb), ca, cb)))
- {
- DR_RW_UNCONDITIONALLY (a) = 1;
- DR_RW_UNCONDITIONALLY (b) = 1;
- found = true;
- break;
- }
- }
- }
+ base_master_dr = &baseref_DR_map->get_or_insert (base_ref,&exsist2);
- if (!found)
- {
- DR_RW_UNCONDITIONALLY (a) = 0;
- return false;
- }
- }
+ if (!exsist2)
+ {
+ if (DR_IS_WRITE (a) && is_true_predicate (ca))
+ {
+ DR_WRITTEN_AT_LEAST_ONCE (a) = 1;
+ }
+ IFC_DR (a)->ored_result = ca;
+ *base_master_dr = a;
+ }
+ else
+ {
+ IFC_DR (*base_master_dr)->ored_result
+ = fold_or_predicates
+ (EXPR_LOCATION (IFC_DR (*base_master_dr)->ored_result),
+ ca, IFC_DR (*base_master_dr)->ored_result);
- return true;
+ if (DR_IS_WRITE (a)
+ && (is_true_predicate (ca)
+ || (is_true_predicate
+ (IFC_DR (*base_master_dr)->ored_result))))
+ {
+ DR_WRITTEN_AT_LEAST_ONCE (*base_master_dr) = 1;
+ }
+ }
}
-/* Returns true when the memory references of STMT are unconditionally
- written. In other words, this function returns true when for every
- data reference A written in STMT, there exist other writes to the
- same data reference with predicates that add up (OR-up) to the true
- predicate: this ensures that the data reference A is written on
- every iteration of the if-converted loop. */
-
+/* Returns true for the memory reference in STMT, same memory reference
+ is read or written unconditionally atleast once and the base memory
+ reference is written unconditionally once. This is to check reference
+ will not write fault. Also retuns true if the memory reference is
+ unconditionally read once then we are conditionally writing to memory
+ which is defined as read and write and is bound to the definition
+ we are seeing. */
static bool
-write_memrefs_written_at_least_once (gimple *stmt,
- vec<data_reference_p> drs)
+memrefs_read_or_written_unconditionally (gimple *stmt,
+ vec<data_reference_p> drs)
{
- int i, j;
- data_reference_p a, b;
- tree ca = bb_predicate (gimple_bb (stmt));
+ int i;
+ data_reference_p a, *master_dr, *base_master_dr;
+ bool found = false;
+ for (i = gimple_uid (stmt) - 1; drs.iterate (i, &a); i++)
+ {
+ if (DR_STMT (a) != stmt)
+ break;
- for (i = 0; drs.iterate (i, &a); i++)
- if (DR_STMT (a) == stmt
- && DR_IS_WRITE (a))
- {
- bool found = false;
- int x = DR_WRITTEN_AT_LEAST_ONCE (a);
+ tree ref_base_a = DR_REF (a);
+ tree base = DR_BASE_OBJECT (a);
- if (x == 0)
- return false;
+ while (TREE_CODE (ref_base_a) == COMPONENT_REF
+ || TREE_CODE (ref_base_a) == IMAGPART_EXPR
+ || TREE_CODE (ref_base_a) == REALPART_EXPR)
+ ref_base_a = TREE_OPERAND (ref_base_a, 0);
- if (x == 1)
- continue;
+ master_dr = ref_DR_map->get (ref_base_a);
+ base_master_dr = baseref_DR_map->get (base);
- for (j = 0; drs.iterate (j, &b); j++)
- if (DR_STMT (b) != stmt
- && DR_IS_WRITE (b)
- && same_data_refs_base_objects (a, b))
- {
- tree cb = bb_predicate (gimple_bb (DR_STMT (b)));
+ gcc_assert (master_dr != NULL && base_master_dr != NULL);
- if (DR_WRITTEN_AT_LEAST_ONCE (b) == 1
- || is_true_predicate (cb)
- || is_true_predicate (ca = fold_or_predicates (EXPR_LOCATION (cb),
- ca, cb)))
+ if (DR_RW_UNCONDITIONALLY (*master_dr) == 1)
+ {
+ if (DR_WRITTEN_AT_LEAST_ONCE (*base_master_dr) == 1)
+ {
+ found = true;
+ break;
+ }
+ else
+ {
+ tree base_tree = get_base_address (DR_REF (a));
+ if (DECL_P (base_tree)
+ && decl_binds_to_current_def_p (base_tree)
+ && !TREE_READONLY (base_tree))
{
- DR_WRITTEN_AT_LEAST_ONCE (a) = 1;
- DR_WRITTEN_AT_LEAST_ONCE (b) = 1;
- found = true;
+ found = true;
break;
}
}
+ }
- if (!found)
- {
- DR_WRITTEN_AT_LEAST_ONCE (a) = 0;
- return false;
- }
- }
+ if (!found)
+ {
+ DR_WRITTEN_AT_LEAST_ONCE (a) =0;
+ DR_RW_UNCONDITIONALLY (a) = 0;
+ return false;
+ }
+ }
return true;
}
@@ -748,8 +770,7 @@ write_memrefs_written_at_least_once (gimple *stmt,
static bool
ifcvt_memrefs_wont_trap (gimple *stmt, vec<data_reference_p> refs)
{
- return write_memrefs_written_at_least_once (stmt, refs)
- && memrefs_read_or_written_unconditionally (stmt, refs);
+ return memrefs_read_or_written_unconditionally (stmt, refs);
}
/* Wrapper around gimple_could_trap_p refined for the needs of the
@@ -1292,6 +1313,7 @@ if_convertible_loop_p_1 (struct loop *loop,
case GIMPLE_CALL:
case GIMPLE_DEBUG:
case GIMPLE_COND:
+ gimple_set_uid (gsi_stmt (gsi), 0);
break;
default:
return false;
@@ -1300,13 +1322,20 @@ if_convertible_loop_p_1 (struct loop *loop,
data_reference_p dr;
+ ref_DR_map = new hash_map<tree_operand_hash, data_reference_p>;
+ baseref_DR_map = new hash_map<tree_operand_hash, data_reference_p>;
+
+ predicate_bbs (loop);
+
for (i = 0; refs->iterate (i, &dr); i++)
{
dr->aux = XNEW (struct ifc_dr);
DR_WRITTEN_AT_LEAST_ONCE (dr) = -1;
DR_RW_UNCONDITIONALLY (dr) = -1;
+ if (gimple_uid (DR_STMT (dr)) == 0)
+ gimple_set_uid (DR_STMT (dr), i + 1);
+ hash_memrefs_baserefs_and_store_DRs_read_written_info (dr);
}
- predicate_bbs (loop);
for (i = 0; i < loop->num_nodes; i++)
{
@@ -1403,6 +1432,15 @@ if_convertible_loop_p (struct loop *loop, bool *any_mask_load_store)
free_data_refs (refs);
free_dependence_relations (ddrs);
+
+ if (ref_DR_map)
+ delete ref_DR_map;
+ ref_DR_map = NULL;
+
+ if (baseref_DR_map)
+ delete baseref_DR_map;
+ baseref_DR_map = NULL;
+
return res;
}