]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
xtensa: Optimize branch whether (reg:SI) is within/out the range handled by CLAMPS...
authorTakayuki 'January June' Suwa <jjsuwa_sys3175@yahoo.co.jp>
Fri, 29 Aug 2025 10:19:32 +0000 (19:19 +0900)
committerMax Filippov <jcmvbkbc@gmail.com>
Sun, 31 Aug 2025 23:39:01 +0000 (16:39 -0700)
The CLAMPS instruction in Xtensa ISA, provided when the TARGET_CLAMPS
configuration is enabled (and also requires TARGET_MINMAX), returns a
value clamped the number in the specified register to between -(1<<N) and
(1<<N)-1 inclusive, where N is an immediate value from 7 to 22.

Therefore, when the above configurations are met, by comparing the clamped
result with the original value for equality, branching whether the value
is within the range mentioned above or not is implemented with fewer
instructions, especially when the upper and lower bounds of the range are
too large to fit into a single immediate assignment.

     /* example (TARGET_MINMAX and TARGET_CLAMPS) */
     extern void foo(void);
     void test0(int a) {
       if (a >= -(1 << 9) && a < (1 << 9))
         foo();
     }
     void test1(int a) {
       if (a < -(1 << 20) || a >= (1 << 20))
         foo();
     }

     ;; before
     test0:
      entry sp, 32
      addmi a2, a2, 0x200
      movi a8, 0x3ff
      bltu a8, a2, .L1
      call8 foo
     .L1:
      retw.n
     test1:
      entry sp, 32
      movi.n a9, 1
      movi.n a8, -1
      slli a9, a9, 20
      srli a8, a8, 11
      add.n a2, a2, a9
      bgeu a8, a2, .L4
      call8 foo
     .L4:
      retw.n

     ;; after
     test0:
      entry sp, 32
      clamps a8, a2, 9
      bne a2, a8, .L1
      call8 foo
     .L1:
      retw.n
     test1:
      entry sp, 32
      clamps a8, a2, 20
      beq a2, a8, .L4
      call8 foo
     .L4:
      retw.n

(note: Currently, in the RTL instruction combination pass, the possible
const_int values ​​are fundamentally constrained by
TARGET_LEGITIMATE_CONSTANT_P() if no bare large constant assignments are
possible (i.e., neither -mconst16 nor -mauto-litpools), so limiting N to
a range of 7 to only 10 instead of to 22.  A series of forthcoming
patches will introduce an entirely new "xt_largeconst" pass that will
solve several issues including this.)

gcc/ChangeLog:

* config/xtensa/predicates.md (alt_ubranch_operator):
New predicate.
* config/xtensa/xtensa.md (*eqne_in_range):
New insn_and_split pattern.

gcc/config/xtensa/predicates.md
gcc/config/xtensa/xtensa.md

index 9aeaba6ad723611b0e0d660c18f0e6302fe01de0..20160a4c4e5f5feb0b661daa41089e7e09ca3c26 100644 (file)
 (define_predicate "ubranch_operator"
   (match_code "ltu,geu"))
 
+(define_predicate "alt_ubranch_operator"
+  (match_code "gtu,leu"))
+
 (define_predicate "boolean_operator"
   (match_code "eq,ne"))
 
index 1339b03ce1e9df0418fb1e95cad879cae23dcc47..52ffb161c0f59615ff374723cd03427a39e19715 100644 (file)
                                    (const_int 8)
                                    (const_int 9))))])
 
+(define_insn_and_split "*eqne_in_range"
+  [(set (pc)
+       (if_then_else (match_operator 4 "alt_ubranch_operator"
+                       [(plus:SI (match_operand:SI 0 "register_operand" "r")
+                                 (match_operand:SI 1 "const_int_operand" "i"))
+                        (match_operand:SI 2 "const_int_operand" "i")])
+                     (label_ref (match_operand 3 ""))
+                     (pc)))
+   (clobber (match_scratch:SI 5 "=&a"))]
+  "TARGET_MINMAX && TARGET_CLAMPS
+   && INTVAL (operands[1]) * 2 - INTVAL (operands[2]) == 1
+   && IN_RANGE (exact_log2 (INTVAL (operands[1])), 7, 22)"
+  "#"
+  "&& 1"
+  [(set (match_dup 5)
+       (smin:SI (smax:SI (match_dup 0)
+                         (match_dup 1))
+                (match_dup 2)))
+   (set (pc)
+       (if_then_else (match_op_dup 4
+                       [(match_dup 0)
+                        (match_dup 5)])
+                     (label_ref (match_dup 3))
+                     (pc)))]
+{
+  HOST_WIDE_INT v = INTVAL (operands[1]);
+  operands[1] = GEN_INT (-v);
+  operands[2] = GEN_INT (v - 1);
+  PUT_CODE (operands[4], GET_CODE (operands[4]) == GTU ? NE : EQ);
+  if (GET_CODE (operands[5]) == SCRATCH)
+    operands[5] = gen_reg_rtx (SImode);
+}
+  [(set_attr "type"    "jump")
+   (set_attr "mode"    "none")
+   (set_attr "length"  "6")])
+
 (define_split
   [(clobber (match_operand 0 "register_operand"))]
   "HARD_REGISTER_P (operands[0])