]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
vect: Add default types & retvals for uncounted loops
authorVictor Do Nascimento <victor.donascimento@arm.com>
Mon, 22 Sep 2025 16:52:11 +0000 (17:52 +0100)
committerVictor Do Nascimento <victor.donascimento@arm.com>
Mon, 15 Dec 2025 15:05:58 +0000 (15:05 +0000)
Detecting uncounted loops:
--------------------------

Given that scalar evolution analysis of uncounted loops sets
`loop_vec_info->num_iters' to `chrec_dont_know', we use this as the
criterion for probing whether a loop is uncounted or not.
Consequently, we introduce a new access function on `loop_vec_info' to
conveniently test whether a loop in question is uncounted or not, in
the form of `LOOP_VINFO_NITERS_UNCOUNTED_P(L)'.

Default types:
--------------

While the primary exit condition for loops is no longer tied to some
upper limit in the number of executed iterations, similar limits are
still required for vectorization.  One example of this is with prolog
peeling.  The prolog will always have an IV exit associated with the
misalignment of data accesses within the loop.

Historically, the assumption held that the data-type that this counter
should have could be derived from the type of the niters limit for the
original loop, so we could get the type from `TREE_TYPE (niters)'.

Moving forward, we provide a backup type to be used for iteration
counters when the maximum number of iterations to be run is unknown.

We take this to be `sizetype', given its role in storing the maximum
size of a theoretically possible object of any type (including array).

Default return values:
----------------------

To avoid having to gate all calls to functions that query a loop's
niters value it is better to "teach" such functions how to handle
uncounted loops and have them return a sensible value that can be
handled upon a function's return.

We therefore prevent functions operating on niters from segfaulting by
adding a default `SCEV_NOT_KNOWN' return value when niters information
absent.

gcc/ChangeLog:

* tree-vect-loop-manip.cc (vect_build_loop_niters): Gracefully
handle uncounted loops.
(vect_gen_prolog_loop_niters): Add type default of `sizetype'.
(vect_gen_vector_loop_niters): Likewise.
(vect_do_peeling): Likewise.
* tree-vect-loop.cc (vect_min_prec_for_max_niters): Likewise.
(loop_niters_no_overflow): Likewise.
* tree-vectorizer.h (LOOP_VINFO_NITERS_UNCOUNTED_P): New.

gcc/tree-vect-loop-manip.cc
gcc/tree-vect-loop.cc
gcc/tree-vectorizer.h

index c6d8b05b617f2e73e329a72516964ba0f48b677b..bf60628a2896408396087f534ca590e6ce543d38 100644 (file)
@@ -2550,7 +2550,10 @@ vect_gen_prolog_loop_niters (loop_vec_info loop_vinfo,
 {
   dr_vec_info *dr_info = LOOP_VINFO_UNALIGNED_DR (loop_vinfo);
   tree var;
-  tree niters_type = TREE_TYPE (LOOP_VINFO_NITERS (loop_vinfo));
+  tree niters_type
+    = LOOP_VINFO_NITERS_UNCOUNTED_P (loop_vinfo) ? sizetype
+                                                : TREE_TYPE (LOOP_VINFO_NITERS
+                                                             (loop_vinfo));
   gimple_seq stmts = NULL, new_stmts = NULL;
   tree iters, iters_name;
   stmt_vec_info stmt_info = dr_info->stmt;
@@ -2729,6 +2732,8 @@ vect_prepare_for_masked_peels (loop_vec_info loop_vinfo)
 tree
 vect_build_loop_niters (loop_vec_info loop_vinfo, bool *new_var_p)
 {
+  if (LOOP_VINFO_NITERS_UNCOUNTED_P (loop_vinfo))
+    return NULL_TREE;
   tree ni = unshare_expr (LOOP_VINFO_NITERS (loop_vinfo));
   if (TREE_CODE (ni) == INTEGER_CST)
     return ni;
@@ -2830,7 +2835,8 @@ vect_gen_vector_loop_niters (loop_vec_info loop_vinfo, tree niters,
                             bool niters_no_overflow)
 {
   tree ni_minus_gap, var;
-  tree niters_vector, step_vector, type = TREE_TYPE (niters);
+  tree niters_vector, step_vector;
+  tree type = niters ? TREE_TYPE (niters) : sizetype;
   poly_uint64 vf = LOOP_VINFO_VECT_FACTOR (loop_vinfo);
   edge pe = loop_preheader_edge (LOOP_VINFO_LOOP (loop_vinfo));
 
@@ -3174,7 +3180,8 @@ vect_do_peeling (loop_vec_info loop_vinfo, tree niters, tree nitersm1,
                 tree *advance)
 {
   edge e, guard_e;
-  tree type = TREE_TYPE (niters), guard_cond;
+  tree type = niters ? TREE_TYPE (niters) : sizetype;
+  tree guard_cond;
   basic_block guard_bb, guard_to;
   profile_probability prob_prolog, prob_vector, prob_epilog;
   int estimated_vf;
index f9dd88ed82468923ce6f1d01324a247a47169cde..eb89d8e6ebe828fe10b2000b3aea55d8b73fc9b4 100644 (file)
@@ -923,7 +923,11 @@ vect_min_prec_for_max_niters (loop_vec_info loop_vinfo, unsigned int factor)
 
   /* Get the maximum number of iterations that is representable
      in the counter type.  */
-  tree ni_type = TREE_TYPE (LOOP_VINFO_NITERSM1 (loop_vinfo));
+  tree ni_type;
+  if (!LOOP_VINFO_NITERS_UNCOUNTED_P (loop_vinfo))
+    ni_type = TREE_TYPE (LOOP_VINFO_NITERSM1 (loop_vinfo));
+  else
+    ni_type = sizetype;
   widest_int max_ni = wi::to_widest (TYPE_MAX_VALUE (ni_type)) + 1;
 
   /* Get a more refined estimate for the number of iterations.  */
@@ -10399,6 +10403,8 @@ vectorizable_live_operation (vec_info *vinfo, stmt_vec_info stmt_info,
 static bool
 loop_niters_no_overflow (loop_vec_info loop_vinfo)
 {
+  gcc_assert (!LOOP_VINFO_NITERS_UNCOUNTED_P (loop_vinfo));
+
   /* Constant case.  */
   if (LOOP_VINFO_NITERS_KNOWN_P (loop_vinfo))
     {
@@ -11056,6 +11062,7 @@ vect_transform_loop (loop_vec_info loop_vinfo, gimple *loop_vectorized_call)
   bool check_profitability = false;
   unsigned int th;
   bool flat = maybe_flat_loop_profile (loop);
+  bool uncounted_p = LOOP_VINFO_NITERS_UNCOUNTED_P (loop_vinfo);
 
   DUMP_VECT_SCOPE ("vec_transform_loop");
 
@@ -11117,9 +11124,10 @@ vect_transform_loop (loop_vec_info loop_vinfo, gimple *loop_vectorized_call)
   tree niters = vect_build_loop_niters (loop_vinfo);
   LOOP_VINFO_NITERS_UNCHANGED (loop_vinfo) = niters;
   tree nitersm1 = unshare_expr (LOOP_VINFO_NITERSM1 (loop_vinfo));
-  bool niters_no_overflow = loop_niters_no_overflow (loop_vinfo);
   tree advance;
   drs_init_vec orig_drs_init;
+  bool niters_no_overflow = uncounted_p ? false /* Not known.  */
+                                       : loop_niters_no_overflow (loop_vinfo);
 
   epilogue = vect_do_peeling (loop_vinfo, niters, nitersm1, &niters_vector,
                              &step_vector, &niters_vector_mult_vf, th,
index 563a69ffd93bbbcbd9dc76a88d9a7c65c52d820a..5b68c3b46fe0f51a2013a82cc09895fe7e623882 100644 (file)
@@ -1263,6 +1263,8 @@ public:
 #define LOOP_VINFO_NBBS(L)                 (L)->nbbs
 #define LOOP_VINFO_NITERSM1(L)             (L)->num_itersm1
 #define LOOP_VINFO_NITERS(L)               (L)->num_iters
+#define LOOP_VINFO_NITERS_UNCOUNTED_P(L)   (LOOP_VINFO_NITERS (L) \
+                                           == chrec_dont_know)
 /* Since LOOP_VINFO_NITERS and LOOP_VINFO_NITERSM1 can change after
    prologue peeling retain total unchanged scalar loop iterations for
    cost model.  */