diff options
author | Hao Liu <hliu@os.amperecomputing.com> | 2023-12-06 14:52:19 +0800 |
---|---|---|
committer | Hao Liu <hliu@os.amperecomputing.com> | 2023-12-08 11:18:03 +0800 |
commit | 2efe3a7de0107618397264017fb045f237764cc7 (patch) | |
tree | ee0a1dd559c20e6e9fa0b038ad49e2f16564974c /gcc | |
parent | 9f7ad5eff3bf1e42aac0825b37d2c9ab43eaafd2 (diff) | |
download | gcc-2efe3a7de0107618397264017fb045f237764cc7.zip gcc-2efe3a7de0107618397264017fb045f237764cc7.tar.gz gcc-2efe3a7de0107618397264017fb045f237764cc7.tar.bz2 |
tree-optimization/112774: extend the SCEV CHREC tree with a nonwrapping flag
The flag is defined as CHREC_NOWRAP(tree), and will be dumped from
"{offset, +, 1}_1" to "{offset, +, 1}<nw>_1" (nw is short for nonwrapping).
Two SCEV interfaces record_nonwrapping_chrec and nonwrapping_chrec_p are
added to set and check the flag respectively.
As resetting the SCEV cache (i.e., the chrec trees) may not reset the
loop->estimate_state, free_numbers_of_iterations_estimates is called
explicitly in loop vectorization to make sure the flag can be
calculated propriately by niter.
gcc/ChangeLog:
PR tree-optimization/112774
* tree-pretty-print.cc: if nonwrapping flag is set, chrec will be
printed with additional <nw> info.
* tree-scalar-evolution.cc: add record_nonwrapping_chrec and
nonwrapping_chrec_p to set and check the new flag respectively.
* tree-scalar-evolution.h: Likewise.
* tree-ssa-loop-niter.cc (idx_infer_loop_bounds,
infer_loop_bounds_from_pointer_arith, infer_loop_bounds_from_signedness,
scev_probably_wraps_p): call record_nonwrapping_chrec before
record_nonwrapping_iv, call nonwrapping_chrec_p to check the flag is
set and return false from scev_probably_wraps_p.
* tree-vect-loop.cc (vect_analyze_loop): call
free_numbers_of_iterations_estimates explicitly.
* tree-core.h: document the nothrow_flag usage in CHREC_NOWRAP
* tree.h: add CHREC_NOWRAP(NODE), base.nothrow_flag is used to
represent the nonwrapping info.
gcc/testsuite/ChangeLog:
* gcc.dg/tree-ssa/scev-16.c: New test.
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/testsuite/gcc.dg/tree-ssa/scev-16.c | 18 | ||||
-rw-r--r-- | gcc/tree-core.h | 3 | ||||
-rw-r--r-- | gcc/tree-pretty-print.cc | 2 | ||||
-rw-r--r-- | gcc/tree-scalar-evolution.cc | 24 | ||||
-rw-r--r-- | gcc/tree-scalar-evolution.h | 2 | ||||
-rw-r--r-- | gcc/tree-ssa-loop-niter.cc | 21 | ||||
-rw-r--r-- | gcc/tree-vect-loop.cc | 4 | ||||
-rw-r--r-- | gcc/tree.h | 8 |
8 files changed, 73 insertions, 9 deletions
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/scev-16.c b/gcc/testsuite/gcc.dg/tree-ssa/scev-16.c new file mode 100644 index 0000000..120f40c --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/scev-16.c @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target vect_int } */ +/* { dg-options "-O2 -ftree-vectorize -fdump-tree-vect-details" } */ + +int A[1024 * 2]; + +int foo (unsigned offset, unsigned N) +{ + int sum = 0; + + for (unsigned i = 0; i < N; i++) + sum += A[i + offset]; + + return sum; +} + +/* Loop can be vectorized by referring "i + offset" is nonwrapping from array. */ +/* { dg-final { scan-tree-dump "vectorized 1 loops" "vect" { target { ! { avr-*-* msp430-*-* pru-*-* } } } } } */ diff --git a/gcc/tree-core.h b/gcc/tree-core.h index 65e51b9..04c04cf 100644 --- a/gcc/tree-core.h +++ b/gcc/tree-core.h @@ -1387,6 +1387,9 @@ struct GTY(()) tree_base { DECL_NONALIASED in VAR_DECL + CHREC_NOWRAP in + POLYNOMIAL_CHREC + deprecated_flag: TREE_DEPRECATED in diff --git a/gcc/tree-pretty-print.cc b/gcc/tree-pretty-print.cc index 1fadd75..0dabb6d 100644 --- a/gcc/tree-pretty-print.cc +++ b/gcc/tree-pretty-print.cc @@ -3488,7 +3488,7 @@ dump_generic_node (pretty_printer *pp, tree node, int spc, dump_flags_t flags, dump_generic_node (pp, CHREC_LEFT (node), spc, flags, false); pp_string (pp, ", +, "); dump_generic_node (pp, CHREC_RIGHT (node), spc, flags, false); - pp_string (pp, "}_"); + pp_string (pp, !CHREC_NOWRAP (node) ? "}_" : "}<nw>_"); pp_scalar (pp, "%u", CHREC_VARIABLE (node)); is_stmt = false; break; diff --git a/gcc/tree-scalar-evolution.cc b/gcc/tree-scalar-evolution.cc index 385fc64..94250b1 100644 --- a/gcc/tree-scalar-evolution.cc +++ b/gcc/tree-scalar-evolution.cc @@ -2050,6 +2050,30 @@ analyze_scalar_evolution (class loop *loop, tree var) return res; } +/* If CHREC doesn't overflow, set the nonwrapping flag. */ + +void record_nonwrapping_chrec (tree chrec) +{ + CHREC_NOWRAP(chrec) = 1; + + if (dump_file && (dump_flags & TDF_SCEV)) + { + fprintf (dump_file, "(record_nonwrapping_chrec: "); + print_generic_expr (dump_file, chrec); + fprintf (dump_file, ")\n"); + } +} + +/* Return true if CHREC's nonwrapping flag is set. */ + +bool nonwrapping_chrec_p (tree chrec) +{ + if (!chrec || TREE_CODE(chrec) != POLYNOMIAL_CHREC) + return false; + + return CHREC_NOWRAP(chrec); +} + /* Analyzes and returns the scalar evolution of VAR address in LOOP. */ static tree diff --git a/gcc/tree-scalar-evolution.h b/gcc/tree-scalar-evolution.h index a64ed78..f57fde1 100644 --- a/gcc/tree-scalar-evolution.h +++ b/gcc/tree-scalar-evolution.h @@ -43,6 +43,8 @@ extern bool simple_iv (class loop *, class loop *, tree, struct affine_iv *, bool); extern bool iv_can_overflow_p (class loop *, tree, tree, tree); extern tree compute_overall_effect_of_inner_loop (class loop *, tree); +extern void record_nonwrapping_chrec (tree); +extern bool nonwrapping_chrec_p (tree); /* Returns the basic block preceding LOOP, or the CFG entry block when the loop is function's body. */ diff --git a/gcc/tree-ssa-loop-niter.cc b/gcc/tree-ssa-loop-niter.cc index 2098bef..d465e0e 100644 --- a/gcc/tree-ssa-loop-niter.cc +++ b/gcc/tree-ssa-loop-niter.cc @@ -4206,11 +4206,15 @@ idx_infer_loop_bounds (tree base, tree *idx, void *dta) /* If access is not executed on every iteration, we must ensure that overlow may not make the access valid later. */ - if (!dominated_by_p (CDI_DOMINATORS, loop->latch, gimple_bb (data->stmt)) - && scev_probably_wraps_p (NULL_TREE, - initial_condition_in_loop_num (ev, loop->num), - step, data->stmt, loop, true)) - upper = false; + if (!dominated_by_p (CDI_DOMINATORS, loop->latch, gimple_bb (data->stmt))) + { + if (scev_probably_wraps_p (NULL_TREE, + initial_condition_in_loop_num (ev, loop->num), + step, data->stmt, loop, true)) + upper = false; + } + else + record_nonwrapping_chrec (ev); record_nonwrapping_iv (loop, init, step, data->stmt, low, high, false, upper); return true; @@ -4324,6 +4328,7 @@ infer_loop_bounds_from_pointer_arith (class loop *loop, gimple *stmt) if (flag_delete_null_pointer_checks && int_cst_value (low) == 0) low = build_int_cstu (TREE_TYPE (low), TYPE_ALIGN_UNIT (TREE_TYPE (type))); + record_nonwrapping_chrec (scev); record_nonwrapping_iv (loop, base, step, stmt, low, high, false, true); } @@ -4371,6 +4376,7 @@ infer_loop_bounds_from_signedness (class loop *loop, gimple *stmt) high = wide_int_to_tree (type, r.upper_bound ()); } + record_nonwrapping_chrec (scev); record_nonwrapping_iv (loop, base, step, stmt, low, high, false, true); } @@ -5505,6 +5511,11 @@ scev_probably_wraps_p (tree var, tree base, tree step, if (loop_exits_before_overflow (base, step, at_stmt, loop)) return false; + /* Check the nonwrapping flag, which may be set by niter analysis (e.g., the + above loop exits before overflow). */ + if (var && nonwrapping_chrec_p (analyze_scalar_evolution (loop, var))) + return false; + /* At this point we still don't have a proof that the iv does not overflow: give up. */ return true; diff --git a/gcc/tree-vect-loop.cc b/gcc/tree-vect-loop.cc index dd584ab..6261cd1 100644 --- a/gcc/tree-vect-loop.cc +++ b/gcc/tree-vect-loop.cc @@ -3570,6 +3570,10 @@ vect_analyze_loop (class loop *loop, vec_info_shared *shared) analysis are done under the assumptions. */ loop_constraint_set (loop, LOOP_C_FINITE); } + else + /* Clear the existing niter information to make sure the nonwrapping flag + will be calculated and set propriately. */ + free_numbers_of_iterations_estimates (loop); auto_vector_modes vector_modes; /* Autodetect first vector size we try. */ @@ -1438,9 +1438,11 @@ class auto_suppress_location_wrappers #define COND_EXPR_ELSE(NODE) (TREE_OPERAND (COND_EXPR_CHECK (NODE), 2)) /* Accessors for the chains of recurrences. */ -#define CHREC_LEFT(NODE) TREE_OPERAND (POLYNOMIAL_CHREC_CHECK (NODE), 0) -#define CHREC_RIGHT(NODE) TREE_OPERAND (POLYNOMIAL_CHREC_CHECK (NODE), 1) -#define CHREC_VARIABLE(NODE) POLYNOMIAL_CHREC_CHECK (NODE)->base.u.chrec_var +#define CHREC_LEFT(NODE) TREE_OPERAND (POLYNOMIAL_CHREC_CHECK (NODE), 0) +#define CHREC_RIGHT(NODE) TREE_OPERAND (POLYNOMIAL_CHREC_CHECK (NODE), 1) +#define CHREC_VARIABLE(NODE) POLYNOMIAL_CHREC_CHECK (NODE)->base.u.chrec_var +/* Nonzero if this chrec doesn't overflow (i.e., nonwrapping). */ +#define CHREC_NOWRAP(NODE) POLYNOMIAL_CHREC_CHECK (NODE)->base.nothrow_flag /* LABEL_EXPR accessor. This gives access to the label associated with the given label expression. */ |