https://gcc.gnu.org/g:538b28cfe1c6157dc63791bbf7bafb949f1c6a85

commit r16-6166-g538b28cfe1c6157dc63791bbf7bafb949f1c6a85
Author: Takayuki 'January June' Suwa <[email protected]>
Date:   Sun Dec 14 22:08:38 2025 +0900

    xtensa: Improve usage of SALT/SALTU instructions
    
    In the expansion of cstoresi4 insn patterns, LT[U] comparisons where the
    second operand is an integer constant are canonicalized to LE[U] ones with
    one less than the original.
    
         /* example */
         int test0(int a) {
           return a < 100;
         }
         unsigned int test1(unsigned int a) {
           return a <= 100u;
         }
         void test2(int a[], int b) {
           int i;
           for (i = 0; i < 16; ++i)
            a[i] = (a[i] <= b);
         }
    
         ;; before (TARGET_SALT)
         test0:
            entry   sp, 32
            movi    a8, 0x63
            salt    a2, a8, a2
            addi.n  a2, a2, -1      ;; unwanted inverting
            neg     a2, a2          ;;
            retw.n
         test1:
            entry   sp, 32
            movi    a8, 0x64
            saltu   a2, a8, a2
            addi.n  a2, a2, -1      ;; unwanted inverting
            neg     a2, a2          ;;
            retw.n
         test2:
            entry   sp, 32
            movi.n  a9, 0x10
            loop    a9, .L5_LEND
         .L5:
            l32i.n  a8, a2, 0
            salt    a8, a3, a8
            addi.n  a8, a8, -1      ;; immediate cannot be hoisted out
            neg     a8, a8
            s32i.n  a8, a2, 0
            addi.n  a2, a2, 4
            .L5_LEND:
            retw.n
    
    This patch reverts such canonicalization by adding 1 to the comparison value
    and then converting it back from LE[U] to LT[U], which better matches the
    output machine instructions.  This patch also makes it easier to benefit
    from other optimizations such as CSE, constant propagation, or 
loop-invariant
    hoisting by XORing the result with a register that has a value of 1, rather
    than subtracting 1 and then negating the sign to invert the truth of the
    result.
    
         ;; after (TARGET_SALT)
         test0:
            entry   sp, 32
            movi    a8, 0x64
            salt    a2, a2, a8
            retw.n
         test1:
            entry   sp, 32
            movi    a8, 0x65
            saltu   a2, a2, a8
            retw.n
         test2:
            entry   sp, 32
            movi.n  a10, 1          ;; hoisted out
            movi.n  a9, 0x10
            loop    a9, .L5_LEND
         .L5:
            l32i.n  a8, a2, 0
            salt    a8, a3, a8
            xor     a8, a8, a10
            s32i.n  a8, a2, 0
            addi.n  a2, a2, 4
            .L5_LEND:
            retw.n
    
    gcc/ChangeLog:
    
            * config/xtensa/xtensa.cc (xtensa_expand_scc_SALT):
            New sub-function that emits the SALT/SALTU instructions.
            (xtensa_expand_scc): Change the part related to the SALT/SALTU
            instructions to a call to the above sub-function.

Diff:
---
 gcc/config/xtensa/xtensa.cc | 115 ++++++++++++++++++++++----------------------
 1 file changed, 58 insertions(+), 57 deletions(-)

diff --git a/gcc/config/xtensa/xtensa.cc b/gcc/config/xtensa/xtensa.cc
index 43df10e4b63e..1299e45bc7d1 100644
--- a/gcc/config/xtensa/xtensa.cc
+++ b/gcc/config/xtensa/xtensa.cc
@@ -993,70 +993,71 @@ xtensa_expand_conditional_move (rtx *operands, int isflt)
 }
 
 
-int
-xtensa_expand_scc (rtx operands[4], machine_mode cmp_mode)
+static bool
+xtensa_expand_scc_SALT (rtx dest, enum rtx_code code, rtx op0, rtx op1)
 {
-  rtx dest = operands[0];
-  rtx cmp;
-  rtx one_tmp, zero_tmp;
-  rtx (*gen_fn) (rtx, rtx, rtx, rtx, rtx);
+  int flags;
 
-  if (cmp_mode == SImode && TARGET_SALT)
+  /* Revert back the canonicalization of '(lt[u]:SI (reg:SI) (const_int N)'
+     to '(le[u]:SI (reg:SI) (const_int N-1)'.
+     Note that a comparison like '(le[u]:SI (reg:SI) (const_int [U]INT_MAX))'
+     will never be passed; because the result of such a comparison is a mere
+     constant.  */
+  if (CONST_INT_P (op1))
+    switch (code)
+      {
+      case LE:
+       code = LT, op1 = GEN_INT (INTVAL (op1) + 1);
+       break;
+      case LEU:
+       code = LTU, op1 = GEN_INT (UINTVAL (op1) + 1u);
+       break;
+      default:
+       break;
+      }
+
+  /* b0: inverting, b1: swap(op0,op1), b2: unsigned */
+  switch (code)
     {
-      rtx a = operands[2], b = force_reg (SImode, operands[3]);
-      enum rtx_code code = GET_CODE (operands[1]);
-      bool invert_res = false;
+    case GE:   flags = 1; break;
+    case GT:   flags = 2; break;
+    case LE:   flags = 3; break;
+    case LT:   flags = 0; break;
+    case GEU:  flags = 5; break;
+    case GTU:  flags = 6; break;
+    case LEU:  flags = 7; break;
+    case LTU:  flags = 4; break;
+    default:   return false;
+    }
 
-      switch (code)
-       {
-       case GE:
-       case GEU:
-         invert_res = true;
-         break;
-       case GT:
-       case GTU:
-         std::swap (a, b);
-         break;
-       case LE:
-       case LEU:
-         invert_res = true;
-         std::swap (a, b);
-         break;
-       default:
-         break;
-       }
+  op1 = force_reg (SImode, op1);
+  if (flags & 2)
+    std::swap (op0, op1);
+  emit_insn ((flags & 4) ? gen_saltu (dest, op0, op1)
+                        : gen_salt (dest, op0, op1));
+  if (flags & 1)
+    /* XORing with a temporary register with a value of 1 is advantageous
+       over negation followed by addition of 1 because the temporary register
+       assignment can be subject to CSE, constant propagation, or loop-
+       invariant hoisting.  */
+    emit_insn (gen_xorsi3 (dest, dest, force_reg (SImode, const1_rtx)));
 
-      switch (code)
-       {
-       case GE:
-       case GT:
-       case LE:
-       case LT:
-         emit_insn (gen_salt (dest, a, b));
-         if (!invert_res)
-           return 1;
-         break;
-       case GEU:
-       case GTU:
-       case LEU:
-       case LTU:
-         emit_insn (gen_saltu (dest, a, b));
-         if (!invert_res)
-           return 1;
-         break;
-       default:
-         break;
-       }
+  return true;
+}
 
-      if (invert_res)
-       {
-         emit_insn (gen_negsi2 (dest, dest));
-         emit_insn (gen_addsi3 (dest, dest, const1_rtx));
-         return 1;
-       }
-    }
+int
+xtensa_expand_scc (rtx operands[4], machine_mode cmp_mode)
+{
+  rtx dest = operands[0];
+  rtx cmp, one_tmp, zero_tmp;
+  rtx (*gen_fn) (rtx, rtx, rtx, rtx, rtx);
+  enum rtx_code code = GET_CODE (operands[1]);
+
+  if (TARGET_SALT && cmp_mode == SImode
+      && xtensa_expand_scc_SALT (dest, code, operands[2], operands[3]))
+    return 1;
 
-  if (! (cmp = gen_conditional_move (GET_CODE (operands[1]), cmp_mode,
+  if (! (cmp = gen_conditional_move (code, cmp_mode,
                                     operands[2], operands[3])))
     return 0;

Reply via email to