https://gcc.gnu.org/g:80395d8d52da33478a757465dcd3032afc762693

commit r17-5647-g80395d8d52da33478a757465dcd3032afc762693
Author: Takayuki 'January June' Suwa <[email protected]>
Date:   Tue Oct 27 16:10:05 2026 +0900

    xtensa: Implement xtensa_rtl_combine_reached_p() predicate function
    
    For example, in the Xtensa ISA, there are no machine instructions for
    bitwise inversion (1's complement) or immediate-form XOR.  Consequently,
    implementing the former requires either assigning -1 into a scratch register
    and performing a reg-reg XOR, or adding 1 to the source value and inverting
    its sign.  The former implementation offers opportunities for CSE and loop-
    invariant hoisting, while the latter results in lower register pressure.
    Thus, when implementing an instruction that cannot be reduced to a single
    machine instruction, there are trade-offs regarding optimization depending
    on whether or not a scratch register containing a constant value is used.
    
    Now, looking at the optimization process after the RTL generation pass, we
    see that loop optimization follows forward propagation and CSE, and then
    instruction combination optimization.  Following this fact, it would be
    better to use constant-value scratch registers for insns that are material-
    ized early during RTL passes, such as those following the define_expand MD
    pattern, while such scratch registers should be avoided whenever possible
    for non-standard name patterns (often described by define_insn_and_split)
    found in the later instruction combination pass.  Even more conveniently,
    in the instruction combination pass, registers that have been subjected
    to CSE or loop-invariant hoisting are not used in the search for instruc-
    tions to combine.
    
    However, defining a insn(_and_split) MD pattern naturally means that the
    instruction recognizer will begin to recognize that pattern.  In practice,
    because recog() is conveniently invoked during early RTL passes (such as in
    forwprop), patterns that do not use constant-value scratch registers appear
    before CSE or loop optimization passes, and the intended optimization may
    not be achieved.
    
    This patch introduces a new target-specific predicate function that is false
    until the instruction combination RTL pass is reached, thereby providing a
    means to counteract the above disadvantage.
    
         /* example #1 */
         int test0(int a) {
           return ~a;
         }
         int test1(int a[]) {
           int i;
           for (i = 0; i < 16; ++i)
             a[i] = ~a[i];
         }
    
         /* after #1 (-O2) */
         test0:
            entry   sp, 32
            addi.n  a2, a2, 1       ;; "*one_cmplsi2" insn_and_split
            neg     a2, a2          ;; before this patch,
                                    ;;   "movi.n a8, -1; xor a2, a2, a8"
            retw.n
         test1:
            entry   sp, 32
            movi.n  a10, -1         ;; hoisted out
            movi.n  a9, 0x10
            loop    a9, .L4_LEND
         .L4:
            l32i.n  a8, a2, 0
            xor     a8, a8, a10     ;; "one_cmplsi2" standard generation
            s32i.n  a8, a2, 0
            addi.n  a2, a2, 4
            .L4_LEND:
            retw.n
    
         /* example #2 */
         int test0(int a) {
           return a & 0x0001FFFF;
         }
         int test1(int a[]) {
           int i;
           for (i = 0; i < 16; ++i)
             a[i] &= 0x0001FFFF;
         }
    
         /* after #2 (-O2) */
         test0:
            entry   sp, 32
            slli    a2, a2, 15      ;; "*andsi3_const_pow2_minus_one"
            srli    a2, a2, 15      ;;   insn_and_split
            retw.n
         test1:
            entry   sp, 32
            movi.n  a10, -1         ;; hoisted out
            srli    a10, a10, 15    ;;
            movi.n  a9, 0x10
            loop    a9, .L4_LEND
         .L4:
            l32i.n  a8, a2, 0
            and     a8, a8, a10     ;; "andsi3" standard generation
                                    ;; before this patch,
                                    ;;  "slli a8, a8, 15; srli a8, a8, 15"
            s32i.n  a8, a2, 0
            addi.n  a2, a2, 4
            .L4_LEND:
            retw.n
    
    gcc/ChangeLog:
    
            * config/xtensa/xtensa-passes.def (pass_xtensa_before_combine):
            New directive that inserts pass_xtensa_before_combine immediately
            before pass_combine.
            * config/xtensa/xtensa-protos.h
            (xtensa_rtl_combine_reached_p, make_pass_xtensa_before_combine):
            New function prototypes.
            * config/xtensa/xtensa.cc (machine_function):
            Add a new member "rtl_combine_reached".
            (xtensa_rtl_combine_reached_p, make_pass_xtensa_before_combine):
            New function definitions.
            (pass_data_xtensa_before_combine, pass_xtensa_before_combine):
            New target-specific hidden pass definition, whose sole purpose is
            to set cfun->machine->rtl_combine_reached to true.
            * config/xtensa/xtensa.md
            (*subsi3_from_const, *andsi3_const_pow2_minus_one)
            (*andsi3_const_negative_pow2, *andsi3_const_shifted_mask):
            Add the condition that xtensa_rtl_combine_reached_p() is true to
            the "condition" of each MD definition.
            (*one_cmplsi2): New insn_and_split pattern.

Diff:
---
 gcc/config/xtensa/xtensa-passes.def |  1 +
 gcc/config/xtensa/xtensa-protos.h   |  2 ++
 gcc/config/xtensa/xtensa.cc         | 54 +++++++++++++++++++++++++++++++++++++
 gcc/config/xtensa/xtensa.md         | 33 +++++++++++++++++++----
 4 files changed, 85 insertions(+), 5 deletions(-)

diff --git a/gcc/config/xtensa/xtensa-passes.def 
b/gcc/config/xtensa/xtensa-passes.def
index e1c636cc4a3f..d4243b683ce6 100644
--- a/gcc/config/xtensa/xtensa-passes.def
+++ b/gcc/config/xtensa/xtensa-passes.def
@@ -19,3 +19,4 @@ along with GCC; see the file COPYING3.  If not see
 
 INSERT_PASS_AFTER (pass_postreload_cse, 1, pass_xtensa_largeconst1);
 INSERT_PASS_BEFORE (pass_regrename, 1, pass_xtensa_largeconst2);
+INSERT_PASS_BEFORE (pass_combine, 1, pass_xtensa_before_combine);
diff --git a/gcc/config/xtensa/xtensa-protos.h 
b/gcc/config/xtensa/xtensa-protos.h
index 472b6c3d6c45..f5d4b8a2988f 100644
--- a/gcc/config/xtensa/xtensa-protos.h
+++ b/gcc/config/xtensa/xtensa-protos.h
@@ -62,6 +62,7 @@ extern bool xtensa_postreload_completed_p (void);
 extern char *xtensa_bswapsi2_output (rtx_insn *, const char *);
 extern bool xtensa_expand_load_force_l32 (rtx *, machine_mode, machine_mode,
                                          int);
+extern bool xtensa_rtl_combine_reached_p (void);
 
 #ifdef TREE_CODE
 extern void init_cumulative_args (CUMULATIVE_ARGS *, int);
@@ -84,5 +85,6 @@ extern HOST_WIDE_INT xtensa_initial_elimination_offset (int 
from, int to);
 extern const char **xtensa_get_config_strings (void);
 extern rtl_opt_pass *make_pass_xtensa_largeconst1 (gcc::context *);
 extern rtl_opt_pass *make_pass_xtensa_largeconst2 (gcc::context *);
+extern rtl_opt_pass *make_pass_xtensa_before_combine (gcc::context *);
 
 #endif /* !__XTENSA_PROTOS_H__ */
diff --git a/gcc/config/xtensa/xtensa.cc b/gcc/config/xtensa/xtensa.cc
index d0a5042ba2db..bfc8e8bfa013 100644
--- a/gcc/config/xtensa/xtensa.cc
+++ b/gcc/config/xtensa/xtensa.cc
@@ -110,6 +110,7 @@ struct GTY(()) machine_function
   rtx last_logues_a9_content;
   HARD_REG_SET eliminated_callee_saved;
   bool postreload_completed;
+  bool rtl_combine_reached;
 };
 
 /* Referenced by the REGNO_REG_CLASS() macro.  */
@@ -2636,6 +2637,16 @@ xtensa_bswapsi2_output (rtx_insn *insn, const char 
*output)
 }
 
 
+/* Return true if the current optimization pass has reached the RTL insn
+   combination.  */
+
+bool
+xtensa_rtl_combine_reached_p (void)
+{
+  return cfun && cfun->machine->rtl_combine_reached;
+}
+
+
 /* Try to split an integer value into what are suitable for two consecutive
    immediate addition instructions, ADDI or ADDMI.  */
 
@@ -6901,4 +6912,47 @@ make_pass_xtensa_largeconst2 (gcc::context *ctxt)
   return new pass_xtensa_largeconst2 (ctxt);
 }
 
+/* "Hidden" machine-specific pass only in order to detect when the current
+   pass has reached the RTL instruction combination pass.  */
+
+namespace
+{
+
+const pass_data pass_data_xtensa_before_combine =
+{
+  RTL_PASS, /* type */
+  "*xt_before_combine", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_MACH_DEP, /* tv_id */
+  0, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  0, /* todo_flags_finish */
+};
+
+class pass_xtensa_before_combine : public rtl_opt_pass
+{
+public:
+  pass_xtensa_before_combine (gcc::context *ctxt)
+    : rtl_opt_pass (pass_data_xtensa_before_combine, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  unsigned int execute (function *fun) final override
+  {
+    fun->machine->rtl_combine_reached = true;
+    return 0;
+  }
+
+};  // class pass_xtensa_before_combine
+
+} // anon namespace
+
+rtl_opt_pass *
+make_pass_xtensa_before_combine (gcc::context *ctxt)
+{
+  return new pass_xtensa_before_combine (ctxt);
+}
+
 #include "gt-xtensa.h"
diff --git a/gcc/config/xtensa/xtensa.md b/gcc/config/xtensa/xtensa.md
index d7fc098eeab2..157236c2c319 100644
--- a/gcc/config/xtensa/xtensa.md
+++ b/gcc/config/xtensa/xtensa.md
@@ -339,8 +339,9 @@
   [(set (match_operand:SI 0 "register_operand" "=a")
        (minus:SI (match_operand:SI 1 "const_int_operand" "")
                  (match_operand:SI 2 "register_operand" "r")))]
-  "xtensa_simm8 (-INTVAL (operands[1]))
-   || xtensa_simm8x256 (-INTVAL (operands[1]))"
+  "xtensa_rtl_combine_reached_p ()
+   && (xtensa_simm8 (-INTVAL (operands[1]))
+       || xtensa_simm8x256 (-INTVAL (operands[1])))"
   "#"
   "&& 1"
   [(set (match_dup 0)
@@ -757,6 +758,25 @@
   DONE;
 })
 
+(define_insn_and_split "*one_cmplsi2"
+  [(set (match_operand:SI 0 "register_operand" "=a")
+       (not:SI (match_operand:SI 1 "register_operand" "r")))]
+  "xtensa_rtl_combine_reached_p ()"
+  "#"
+  "&& reload_completed"
+  [(set (match_dup 0)
+       (plus:SI (match_dup 1)
+                (const_int 1)))
+   (set (match_dup 0)
+       (neg:SI (match_dup 0)))]
+  ""
+  [(set_attr "type"    "arith")
+   (set_attr "mode"    "SI")
+   (set (attr "length")
+       (if_then_else (match_test "TARGET_DENSITY")
+                     (const_int 5)
+                     (const_int 6)))])
+
 (define_insn "neg<mode>2"
   [(set (match_operand:SDF 0 "register_operand" "=f")
         (neg:SDF (match_operand:SDF 1 "register_operand" "f")))]
@@ -872,7 +892,8 @@
   [(set (match_operand:SI 0 "register_operand" "=a")
        (and:SI (match_operand:SI 1 "register_operand" "r")
                (match_operand:SI 2 "const_int_operand" "")))]
-  "IN_RANGE (exact_log2 (INTVAL (operands[2]) + 1), 17, 31)"
+  "xtensa_rtl_combine_reached_p ()
+   && IN_RANGE (exact_log2 (INTVAL (operands[2]) + 1), 17, 31)"
   "#"
   "&& 1"
   [(set (match_dup 0)
@@ -896,7 +917,8 @@
   [(set (match_operand:SI 0 "register_operand" "=a")
        (and:SI (match_operand:SI 1 "register_operand" "r")
                (match_operand:SI 2 "const_int_operand" "")))]
-  "IN_RANGE (exact_log2 (-INTVAL (operands[2])), 12, 31)"
+  "xtensa_rtl_combine_reached_p ()
+   && IN_RANGE (exact_log2 (-INTVAL (operands[2])), 12, 31)"
   "#"
   "&& 1"
   [(set (match_dup 0)
@@ -916,7 +938,8 @@
   [(set (match_operand:SI 0 "register_operand" "=a")
        (and:SI (match_operand:SI 1 "register_operand" "r")
                (match_operand:SI 2 "shifted_mask_operand" "")))]
-  "! xtensa_simm12b (INTVAL (operands[2]))"
+  "xtensa_rtl_combine_reached_p ()
+   && ! xtensa_simm12b (INTVAL (operands[2]))"
   "#"
   "&& 1"
   [(set (match_dup 0)

Reply via email to