On 11/25/25 1:06 AM, Alexandre Oliva wrote:
On Nov 24, 2025, Vladimir Makarov <[email protected]> wrote:

I am also agree using ctz should be faster.
My secret evil plan ;-) was to use the newly-added API for
EXECUTE_IF_SET_IN_HARD_REG_SET, as in the working patchlet below, but
the existing iterators with ctz or ffs would be more efficient, so the
SKIP parameter I put in end up useless.  It's not so important, because
the single use is inlined with skip == 0, but we could drop the
infrastructure for skipping, and switch to a ctz or ffs in the iterator
loop in a followup.  WDYT?

I suppose where ctz or ffs are not directly supported in hardware,
testing a few of the least significant bits to use the current loop
instead of the ctz/ffs call might be profitable, but I'm not sure that's
worth the trouble.

I believe your iterator should be faster.  But I am not sure that it will give significant time saving.

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).

Returning to go compiler.   It iterates over hard regs in the following way:

for m != 0 {
  r := pickReg(m)

  m &^= regMask(1<<r)

}

where pickReg is a trailing zero insn.

--- a/gcc/hard-reg-set.h
+++ b/gcc/hard-reg-set.h
@@ -325,19 +325,7 @@ hard_reg_set_first_diff (const_hard_reg_set x, 
const_hard_reg_set y,
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 +336,23 @@ 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 HARD_REG_SET hard_reg_set_empty;
+  *regno = std::abs (hard_reg_set_first_diff (*iter->set,
+                                             hard_reg_set_empty,
+                                             *regno)) - 1;
+  return *regno < FIRST_PSEUDO_REGISTER;
  }
inline void
-hard_reg_set_iter_next (hard_reg_set_iterator *iter, unsigned *regno)
+hard_reg_set_iter_next (hard_reg_set_iterator *, unsigned *regno)
  {
-  iter->bits >>= 1;
    *regno += 1;
  }


Reply via email to