https://gcc.gnu.org/g:91109d7b6eea9b7d2b3c6c3198ef761126af69e8

commit r17-4937-g91109d7b6eea9b7d2b3c6c3198ef761126af69e8
Author: Michiel Derhaeg <[email protected]>
Date:   Fri Aug 28 13:49:07 2026 +0200

    arc: Correct ctz(0) and clz(0) for ARCompact [PR127117]
    
    CLZ_DEFINED_VALUE_AT_ZERO and CTZ_DEFINED_VALUE_AT_ZERO advertise
    clz(0) == 31 and ctz(0) == 31.  When clzsi2 and ctzsi2 expand to the
    ARCv2 fls and ffs instructions that holds.
    
    Both patterns can also be emulated with norm, which currently happens
    for ARCompact, in that case it returns 32 for a zero operand.
    
    Correct the two emulation patterns.  In *arc_clzsi2 only increment
    the norm result when the operand is strictly positive, which leaves a
    zero operand at norm's own result of 31.  In arc_ctzsi2 produce 31
    instead of 32 on the negative-flag path that a zero operand takes.
    
            PR target/127117
    
    gcc/ChangeLog:
    
            * config/arc/arc.md (*arc_clzsi2): Produce 31 rather than 32 for
            a zero operand.
            (arc_ctzsi2): Likewise.
    
    gcc/testsuite/ChangeLog:
    
            * gcc.target/arc/arc.exp (check_effective_target_norm): New.
            * gcc.target/arc/pr127117.c: New test.
    
    Co-authored-by: Luis Silva <[email protected]>
    Signed-off-by: Michiel Derhaeg <[email protected]>

Diff:
---
 gcc/config/arc/arc.md                   |  4 ++--
 gcc/testsuite/gcc.target/arc/arc.exp    |  9 +++++++++
 gcc/testsuite/gcc.target/arc/pr127117.c | 35 +++++++++++++++++++++++++++++++++
 3 files changed, 46 insertions(+), 2 deletions(-)

diff --git a/gcc/config/arc/arc.md b/gcc/config/arc/arc.md
index b4b4a6a3e8e2..ef1c0846f9fe 100644
--- a/gcc/config/arc/arc.md
+++ b/gcc/config/arc/arc.md
@@ -4600,7 +4600,7 @@ archs4x, archs4xd"
   emit_insn
     (gen_rtx_COND_EXEC
       (VOIDmode,
-       gen_rtx_GE (VOIDmode, gen_rtx_REG (CC_ZNmode, CC_REG), const0_rtx),
+       gen_rtx_GT (VOIDmode, gen_rtx_REG (CC_ZNmode, CC_REG), const0_rtx),
        gen_rtx_SET (operands[0], plus_constant (SImode, operands[0], 1))));
   DONE;
 }
@@ -4645,7 +4645,7 @@ archs4x, archs4xd"
     (gen_rtx_COND_EXEC
       (VOIDmode,
        gen_rtx_LT (VOIDmode, gen_rtx_REG (CC_ZNmode, CC_REG), const0_rtx),
-       gen_rtx_SET (operands[0], GEN_INT (32))));
+       gen_rtx_SET (operands[0], GEN_INT (31))));
   emit_insn
     (gen_rtx_COND_EXEC
       (VOIDmode,
diff --git a/gcc/testsuite/gcc.target/arc/arc.exp 
b/gcc/testsuite/gcc.target/arc/arc.exp
index e50db2b6478e..34e210b068bb 100644
--- a/gcc/testsuite/gcc.target/arc/arc.exp
+++ b/gcc/testsuite/gcc.target/arc/arc.exp
@@ -94,6 +94,15 @@ proc check_effective_target_barrelshifter { } {
     }]
 }
 
+# Return 1 if norm is enabled by default.
+proc check_effective_target_norm { } {
+    return [check_no_compiler_messages norm_default assembly {
+       #if !defined(__ARC_NORM__)
+       #error No default norm instruction
+       #endif
+    }]
+}
+
 #return 1 if we have code density option on.
 proc check_effective_target_codedensity { } {
     return [check_no_compiler_messages codedensity assembly {
diff --git a/gcc/testsuite/gcc.target/arc/pr127117.c 
b/gcc/testsuite/gcc.target/arc/pr127117.c
new file mode 100644
index 000000000000..56dd4bbff288
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arc/pr127117.c
@@ -0,0 +1,35 @@
+/* { dg-do run } */
+/* { dg-require-effective-target norm } */
+/* { dg-options "-O2" } */
+
+unsigned __attribute__ ((noipa))
+clz (unsigned x)
+{
+  return __builtin_clz (x);
+}
+
+unsigned __attribute__ ((noipa))
+ctz (unsigned x)
+{
+  return __builtin_ctz (x);
+}
+
+int
+main (void)
+{
+  unsigned msb, lsb;
+
+  if (clz (0) != 31 || ctz (0) != 31)
+    __builtin_abort ();
+
+  for (msb = 0; msb < 32; msb++)
+    for (lsb = 0; lsb <= msb; lsb++)
+      {
+       unsigned v = (1u << msb) | (1u << lsb);
+
+       if (clz (v) != 31 - msb || ctz (v) != lsb)
+         __builtin_abort ();
+      }
+
+  return 0;
+}

Reply via email to