On 11/27/25 4:18 AM, Richard Biener wrote:
On Thu, 27 Nov 2025, Alexandre Oliva wrote:

On Nov 26, 2025, Vladimir Makarov<[email protected]> wrote:

I any case any saving is welcome.  Taking also into account that the
iterator is simpler, I'd go for this change.
So, Alex, if you want you can commit the patch (of course after usual
testing).
I'd already tested it, but I've added some comments, so I gave it
another round of testing, and a ChangeLog entry.

Here's what I'm going to put in, barring objections.  Regstrapped on
x86_64-linux-gnu.


Use the newly-added first_diff API for iteration.  This hugely
simplifies the iterator type, that no longer saves internal state, and
largely simplifies and likely speeds up iteration, thanks to the use
of ctz.


for  gcc/ChangeLog

        PR rtl-optimization/122767
        * hard-reg-set.h (hard_reg_set_iterator): Simplify.
        (hard_reg_set_iter_init): Likewise.
        (hard_reg_set_iter_set): Likewise.  Use first_diff.
        (hard_reg_set_iter_next): Likewise.
---
  gcc/hard-reg-set.h |   77 ++++++++++------------------------------------------
  1 file changed, 15 insertions(+), 62 deletions(-)

diff --git a/gcc/hard-reg-set.h b/gcc/hard-reg-set.h
index e33c8e334d396..92f5531cb2016 100644
--- a/gcc/hard-reg-set.h
+++ b/gcc/hard-reg-set.h
@@ -321,23 +321,13 @@ hard_reg_set_first_diff (const_hard_reg_set x, 
const_hard_reg_set y,
  }
  #endif
-/* Iterator for hard register sets. */
+/* Iterator for hard register sets.  This is not an iterator proper, the bulk
+   of the iterator state is held in the REGNO passed to the iterator
+   functions.  */
struct hard_reg_set_iterator
  {
-  /* Pointer to the current element.  */
-  const HARD_REG_ELT_TYPE *pelt;
-
-  /* The length of the set.  */
-  unsigned short length;
-
-  /* Word within the current element.  */
-  unsigned short word_no;
-
-  /* Contents of the actually processed word.  When finding next bit
-     it is shifted right, so that the actual bit is always the least
-     significant bit of ACTUAL.  */
-  HARD_REG_ELT_TYPE bits;
+  const HARD_REG_SET *set;
  };
#define HARD_REG_ELT_BITS UHOST_BITS_PER_WIDE_INT
@@ -348,64 +338,27 @@ inline void
  hard_reg_set_iter_init (hard_reg_set_iterator *iter, const_hard_reg_set set,
                          unsigned min, unsigned *regno)
  {
-#ifdef HARD_REG_SET_LONGS
-  iter->pelt = set.elts;
-  iter->length = HARD_REG_SET_LONGS;
-#else
-  iter->pelt = &set;
-  iter->length = 1;
-#endif
-  iter->word_no = min / HARD_REG_ELT_BITS;
-  if (iter->word_no < iter->length)
-    {
-      iter->bits = iter->pelt[iter->word_no];
-      iter->bits >>= min % HARD_REG_ELT_BITS;
-
-      /* This is required for correct search of the next bit.  */
-      min += !iter->bits;
-    }
+  iter->set = &set;
    *regno = min;
  }
inline bool
  hard_reg_set_iter_set (hard_reg_set_iterator *iter, unsigned *regno)
  {
-  while (1)
-    {
-      /* Return false when we're advanced past the end of the set.  */
-      if (iter->word_no >= iter->length)
-        return false;
-
-      if (iter->bits)
-        {
-          /* Find the correct bit and return it.  */
-          while (!(iter->bits & 1))
-            {
-              iter->bits >>= 1;
-              *regno += 1;
-            }
-          return (*regno < FIRST_PSEUDO_REGISTER);
-        }
-
-      /* Round to the beginning of the next word.  */
-      *regno = (*regno + HARD_REG_ELT_BITS - 1);
-      *regno -= *regno % HARD_REG_ELT_BITS;
-
-      /* Find the next non-zero word.  */
-      while (++iter->word_no < iter->length)
-        {
-          iter->bits = iter->pelt[iter->word_no];
-          if (iter->bits)
-            break;
-          *regno += HARD_REG_ELT_BITS;
-        }
-    }
+  static const HARD_REG_SET hard_reg_set_empty = {};
+  *regno = std::abs (hard_reg_set_first_diff (*iter->set,
+                                             hard_reg_set_empty,
+                                             *regno)) - 1;
I'm not sure I like using hard_reg_set_first_diff, esp. when
that ends up using the array version this looks like a step
backwards?

I've just approved the patch.  We need comparison of hard reg sets and hard_reg_set_first_diff provides this.  So it is logical to use it to shorten the iterator code, especially when the new iterator should be faster (usually the sets contain registers of one class and this make the regset sparse).  I counted lines of hard_reg_set_first_diff + iterator based on it and it is practically of the same as the old iterator size. Although if I would implement such functionality (comparison and iterators) with ctz, I probably do it a bit differently.

Reply via email to