diff mbox series

[avr] Rework patterns that add / subtract an (inverted) MSB.

Message ID 0315222f-b1d4-4a90-bef7-7435c4182966@gjlay.de
State New
Headers show
Series [avr] Rework patterns that add / subtract an (inverted) MSB. | expand

Commit Message

Georg-Johann Lay Dec. 4, 2024, 9:39 a.m. UTC
This patch reworks patterns that add / subtract an (inverted) MSB.
It handles more cases by using mode iterators.

Ok for trunk?

Johann

--

AVR: Rework patterns that add / subtract an (inverted) MSB.

gcc/
	* config/avr/avr-protos.h (avr_out_add_msb): New proto.
	* config/avr/avr.cc (avr_out_add_msb): New function.
	(avr_adjust_insn_length) [ADJUST_LEN_ADD_GE0,
	ADJUST_LEN_ADD_LT0]: Handle cases.
	* config/avr/avr.md (adjust_len) <add_lt0, add_ge0>: New attr values.
	(QISI2): New mode iterator.
	(C_MSB): New mode_attr.
	(*add<mode>3...msb_split, *add<mode>3.ge0, *add<mode>3.lt0)
	(*sub<mode>3...msb_split, *sub<mode>3.ge0, *sub<mode>3.lt0): New
	patterns replacing old ones, but with iterators and
	using avr_out_add_msb() for asm out.

Comments

Denis Chertykov Dec. 5, 2024, 9:27 a.m. UTC | #1
ср, 4 дек. 2024 г. в 13:39, Georg-Johann Lay <avr@gjlay.de>:
>
> This patch reworks patterns that add / subtract an (inverted) MSB.
> It handles more cases by using mode iterators.
>
> Ok for trunk?
>

Please apply.

Denis
diff mbox series

Patch

    AVR: Rework patterns that add / subtract an (inverted) MSB.
    
    gcc/
            * config/avr/avr-protos.h (avr_out_add_msb): New proto.
            * config/avr/avr.cc (avr_out_add_msb): New function.
            (avr_adjust_insn_length) [ADJUST_LEN_ADD_GE0,
            ADJUST_LEN_ADD_LT0]: Handle cases.
            * config/avr/avr.md (adjust_len) <add_lt0, add_ge0>: New attr values.
            (QISI2): New mode iterator.
            (C_MSB): New mode_attr.
            (*add<mode>3...msb_split, *add<mode>3.ge0, *add<mode>3.lt0)
            (*sub<mode>3...msb_split, *sub<mode>3.ge0, *sub<mode>3.lt0): New
            patterns replacing old ones, but with iterators and
            using avr_out_add_msb() for asm out.

diff --git a/gcc/config/avr/avr-protos.h b/gcc/config/avr/avr-protos.h
index 4aa8554000b..5b42f04fb31 100644
--- a/gcc/config/avr/avr-protos.h
+++ b/gcc/config/avr/avr-protos.h
@@ -109,6 +109,7 @@  extern const char *avr_out_sbxx_branch (rtx_insn *insn, rtx operands[]);
 extern const char* avr_out_bitop (rtx, rtx*, int*);
 extern const char* avr_out_plus (rtx, rtx*, int* =NULL, bool =true);
 extern const char* avr_out_plus_ext (rtx_insn*, rtx*, int*);
+extern const char* avr_out_add_msb (rtx_insn*, rtx*, rtx_code, int*);
 extern const char* avr_out_round (rtx_insn *, rtx*, int* =NULL);
 extern const char* avr_out_addto_sp (rtx*, int*);
 extern const char* avr_out_xload (rtx_insn *, rtx*, int*);
diff --git a/gcc/config/avr/avr.cc b/gcc/config/avr/avr.cc
index ccf9b05bb3e..54f135c74b7 100644
--- a/gcc/config/avr/avr.cc
+++ b/gcc/config/avr/avr.cc
@@ -8258,6 +8258,94 @@  avr_out_plus_ext (rtx_insn *insn, rtx *yop, int *plen)
 }
 
 
+/* Output code for addition of a sign-bit
+
+      YOP[0] += YOP[1] <CMP> 0
+
+   or such a subtraction:
+
+      YOP[0] -= YOP[2] <CMP> 0
+
+   where CMP is in { GE, LT }.
+   If PLEN == NULL output the instructions.
+   If PLEN != NULL set *PLEN to the length of the sequence in words.  */
+
+const char *
+avr_out_add_msb (rtx_insn *insn, rtx *yop, rtx_code cmp, int *plen)
+{
+  const rtx_code add = GET_CODE (SET_SRC (single_set (insn)));
+  const machine_mode mode = GET_MODE (yop[0]);
+  const int n_bytes = GET_MODE_SIZE (mode);
+  rtx sigop = yop[add == PLUS ? 1 : 2];
+  rtx msb = avr_byte (sigop, GET_MODE_SIZE (GET_MODE (sigop)) - 1);
+  rtx op[3] = { yop[0], msb, nullptr };
+
+  if (plen)
+    *plen = 0;
+
+  if (n_bytes == 1
+      || (n_bytes == 2 && avr_adiw_reg_p (op[0])))
+    {
+      avr_asm_len (cmp == LT
+		   ? "sbrc %1,7"
+		   : "sbrs %1,7", op, plen, 1);
+      const char *s_add = add == PLUS
+	? n_bytes == 1 ? "inc %0" : "adiw %0,1"
+	: n_bytes == 1 ? "dec %0" : "sbiw %0,1";
+      return avr_asm_len (s_add, op, plen, 1);
+    }
+
+  bool labl_p = false;
+  const char *s_code0 = nullptr;
+
+  // Default code provided SREG.C = MSBit.
+  const char *s_code = add == PLUS
+    ? "adc %2,__zero_reg__"
+    : "sbc %2,__zero_reg__";
+
+  if (cmp == LT)
+    {
+      if (reg_unused_after (insn, sigop)
+	  && ! reg_overlap_mentioned_p (msb, op[0]))
+	avr_asm_len ("lsl %1", op, plen, 1);
+      else
+	avr_asm_len ("mov __tmp_reg__,%1" CR_TAB
+		     "lsl __tmp_reg__", op, plen, 2);
+    }
+  else if (test_hard_reg_class (LD_REGS, msb))
+    {
+      avr_asm_len ("cpi %1,0x80", op, plen, 1);
+    }
+  else if (test_hard_reg_class (LD_REGS, op[0]))
+    {
+      labl_p = true;
+      avr_asm_len ("tst %1" CR_TAB
+		   "brmi 0f", op, plen, 2);
+      s_code0 = add == PLUS ? "subi %2,-1" : "subi %2,1";
+      s_code  = add == PLUS ? "sbci %2,-1" : "sbci %2,0";
+    }
+  else
+    {
+      labl_p = true;
+      avr_asm_len ("tst %1"  CR_TAB
+		   "brmi 0f" CR_TAB
+		   "sec", op, plen, 3);
+    }
+
+  for (int i = 0; i < n_bytes; ++i)
+    {
+      op[2] = avr_byte (op[0], i);
+      avr_asm_len (i == 0 && s_code0
+		   ? s_code0
+		   : s_code, op, plen, 1);
+    }
+
+  return labl_p
+    ? avr_asm_len ("0:", op, plen, 0)
+    : "";
+}
+
+
 /* Output addition of register XOP[0] and compile time constant XOP[2].
    INSN is a single_set insn or an insn pattern.
    CODE == PLUS:  perform addition by using ADD instructions or
@@ -10653,6 +10741,9 @@  avr_adjust_insn_length (rtx_insn *insn, int len)
     case ADJUST_LEN_ADD_SET_ZN: avr_out_plus_set_ZN (op, &len); break;
     case ADJUST_LEN_ADD_SET_N:  avr_out_plus_set_N (op, &len); break;
 
+    case ADJUST_LEN_ADD_GE0: avr_out_add_msb (insn, op, GE, &len); break;
+    case ADJUST_LEN_ADD_LT0: avr_out_add_msb (insn, op, LT, &len); break;
+
     case ADJUST_LEN_INSV_NOTBIT: avr_out_insert_notbit (insn, op, &len); break;
 
     default:
diff --git a/gcc/config/avr/avr.md b/gcc/config/avr/avr.md
index 0c98318c03d..8e38db24c96 100644
--- a/gcc/config/avr/avr.md
+++ b/gcc/config/avr/avr.md
@@ -169,6 +169,7 @@  (define_attr "adjust_len"
    ashlhi, ashrhi, lshrhi,
    ashlsi, ashrsi, lshrsi,
    ashlpsi, ashrpsi, lshrpsi,
+   add_lt0, add_ge0,
    insert_bits, insv_notbit, insv, set_some,
    add_set_ZN, add_set_N, cmp_uext, cmp_sext, cmp_lsr,
    no"
@@ -256,6 +257,7 @@  (define_attr "enabled" ""
 (define_mode_iterator QIHI  [QI HI])
 (define_mode_iterator QIHI2 [QI HI])
 (define_mode_iterator QISI  [QI HI PSI SI])
+(define_mode_iterator QISI2 [QI HI PSI SI])
 (define_mode_iterator QIDI  [QI HI PSI SI DI])
 (define_mode_iterator QIPSI [QI HI PSI])
 (define_mode_iterator HISI  [HI PSI SI])
@@ -301,7 +303,15 @@  (define_mode_iterator SFDF [SF DF])
 (define_mode_attr MSB  [(QI "7") (QQ "7") (UQQ "7")
                         (HI "15") (HQ "15") (UHQ "15") (HA "15") (UHA "15")
                         (PSI "23")
-                        (SI "31") (SQ "31") (USQ "31") (SA "31") (USA "31") (SF "31")])
+                        (SI "31") (SQ "31") (USQ "31") (SA "31") (USA "31")
+                        (SF "31")])
+
+;; Where the most significant bit is located, as a constraint.
+(define_mode_attr C_MSB [(QI "C07") (QQ "C07") (UQQ "C07")
+                         (HI "C15") (HQ "C15") (UHQ "C15") (HA "C15") (UHA "C15")
+                         (PSI "C23")
+                         (SI "C31") (SQ "C31") (USQ "C31") (SA "C31") (USA "C31")
+                         (SF "C31")])
 
 ;; Size in bytes of the mode.
 (define_mode_attr SIZE [(QI "1") (QQ "1") (UQQ "1")
@@ -2194,135 +2204,146 @@  (define_insn "*<extend_su>mulqi3_highpart"
 
 
 ;; Used when expanding div or mod inline for some special values
-(define_insn_and_split "*subqi3.ashiftrt7_split"
-  [(set (match_operand:QI 0 "register_operand"                       "=r")
-        (minus:QI (match_operand:QI 1 "register_operand"              "0")
-                  (ashiftrt:QI (match_operand:QI 2 "register_operand" "r")
-                               (const_int 7))))]
+;; *subqi3.msbit_split   *subhi3.msbit_split
+;; *subpsi3.msbit_split  *subsi3.msbit_split
+(define_insn_and_split "*sub<mode>3.msbit_split"
+  [(set (match_operand:QISI 0 "register_operand"                              "=r")
+        (minus:QISI (match_operand:QISI 1 "register_operand"                   "0")
+                    (any_shiftrt:QISI (match_operand:QISI 2 "register_operand" "r")
+                                      (match_operand:QI 3 "const<MSB>_operand" "<C_MSB>"))))]
   ""
   "#"
   "&& reload_completed"
-  [(parallel [(set (match_dup 0)
-                   (minus:QI (match_dup 1)
-                             (ashiftrt:QI (match_dup 2)
-                                          (const_int 7))))
+  [; *sub<QISI:mode>3.lt0
+   (parallel [(set (match_dup 0)
+                   (minus:QISI (match_dup 1)
+                               (lt:QISI (match_dup 2)
+                                        (const_int 0))))
               (clobber (reg:CC REG_CC))])])
 
-(define_insn "*subqi3.ashiftrt7"
-  [(set (match_operand:QI 0 "register_operand"                       "=r")
-        (minus:QI (match_operand:QI 1 "register_operand"              "0")
-                  (ashiftrt:QI (match_operand:QI 2 "register_operand" "r")
-                               (const_int 7))))
-   (clobber (reg:CC REG_CC))]
-  "reload_completed"
-  "sbrc %2,7\;inc %0"
-  [(set_attr "length" "2")])
-
-(define_insn_and_split "*addqi3.lt0_split"
-  [(set (match_operand:QI 0 "register_operand"                 "=r")
-        (plus:QI (lt:QI (match_operand:QI 1 "register_operand"  "r")
-                        (const_int 0))
-                 (match_operand:QI 2 "register_operand"         "0")))]
+;; *addqi3.msbit_split   *addhi3.msbit_split
+;; *addpsi3.msbit_split  *addsi3.msbit_split
+(define_insn_and_split "*add<mode>3.msbit_split"
+  [(set (match_operand:QISI 0 "register_operand"                             "=r")
+        (plus:QISI (any_shiftrt:QISI (match_operand:QISI 1 "register_operand" "r")
+                                     (match_operand:QI 2 "const<MSB>_operand" "<C_MSB>"))
+                   (match_operand:QISI 3 "register_operand"                   "0")))]
   ""
   "#"
   "&& reload_completed"
-  [(parallel [(set (match_dup 0)
-                   (plus:QI (lt:QI (match_dup 1)
-                                   (const_int 0))
-                            (match_dup 2)))
+  [; *add<QISI:mode>3.lt0
+   (parallel [(set (match_dup 0)
+                   (plus:QISI (lt:QISI (match_dup 1)
+                                       (const_int 0))
+                              (match_dup 3)))
+              (clobber (reg:CC REG_CC))])])
+
+;;                           *addhi3.sex.msbit_split
+;; *addpsi3.sex.msbit_split  *addsi3.sex.msbit_split
+(define_insn_and_split "*add<HISI:mode>3.sex.msbit_split"
+  [(set (match_operand:HISI 0 "register_operand"                  "=r")
+        (plus:HISI (any_shiftrt:HISI
+                    (sign_extend:HISI (match_operand:QIPSI 1 "register_operand" "r"))
+                    (match_operand:QI 2 "const<HISI:MSB>_operand" "<HISI:C_MSB>"))
+                   (match_operand:HISI 3 "register_operand"       "0")))]
+  "<HISI:SIZE> > <QIPSI:SIZE>"
+  "#"
+  "&& reload_completed"
+  [; *add<QISI:mode>3.lt0
+   (parallel [(set (match_dup 0)
+                   (plus:HISI (lt:HISI (match_dup 1)
+                                       (const_int 0))
+                              (match_dup 3)))
+              (clobber (reg:CC REG_CC))])])
+
+;;                           *subhi3.sex.msbit_split
+;; *subpsi3.sex.msbit_split  *subsi3.sex.msbit_split
+(define_insn_and_split "*sub<HISI:mode>3.sex.msbit_split"
+  [(set (match_operand:HISI 0 "register_operand"                  "=r")
+        (minus:HISI (match_operand:HISI 1 "register_operand"       "0")
+                    (any_shiftrt:HISI
+                     (sign_extend:HISI (match_operand:QIPSI 2 "register_operand" "r"))
+                     (match_operand:QI 3 "const<HISI:MSB>_operand" "<HISI:C_MSB>"))))]
+  "<HISI:SIZE> > <QIPSI:SIZE>"
+  "#"
+  "&& reload_completed"
+  [; *sub<QISI:mode>3.lt0
+   (parallel [(set (match_dup 0)
+                   (minus:HISI (match_dup 1)
+                               (lt:HISI (match_dup 2)
+                                        (const_int 0))))
               (clobber (reg:CC REG_CC))])])
 
-(define_insn "*addqi3.lt0"
-  [(set (match_operand:QI 0 "register_operand"                 "=r")
-        (plus:QI (lt:QI (match_operand:QI 1 "register_operand"  "r")
-                        (const_int 0))
-                 (match_operand:QI 2 "register_operand"         "0")))
+;; *subqi3.lt0   *subqi3.ge0
+;; *subhi3.lt0   *subhi3.ge0
+;; *subpsi3.lt0  *subpsi3.ge0
+;; *subsi3.lt0   *subsi3.ge0
+(define_insn "*sub<QISI:mode>3.<code>0"
+  [(set (match_operand:QISI 0 "register_operand"                        "=r")
+        (minus:QISI (match_operand:QISI 1 "register_operand"             "0")
+                    (gelt:QISI (match_operand:QISI2 2 "register_operand" "r")
+                               (const_int 0))))
    (clobber (reg:CC REG_CC))]
   "reload_completed"
-  "sbrc %1,7\;inc %0"
-  [(set_attr "length" "2")])
-
-(define_insn_and_split "*addhi3.lt0_split"
-  [(set (match_operand:HI 0 "register_operand"                   "=w,r")
-        (plus:HI (lt:HI (match_operand:QI 1 "register_operand"    "r,r")
-                        (const_int 0))
-                 (match_operand:HI 2 "register_operand"           "0,0")))
-   (clobber (match_scratch:QI 3                                  "=X,&1"))]
-  ""
-  "#"
-  "&& reload_completed"
-  [(parallel [(set (match_dup 0)
-                   (plus:HI (lt:HI (match_dup 1)
-                                   (const_int 0))
-                            (match_dup 2)))
-              (clobber (match_dup 3))
-              (clobber (reg:CC REG_CC))])]
-  ""
-  [(set_attr "isa" "adiw,*")])
+  {
+    return avr_out_add_msb (insn, operands, <CODE>, nullptr);
+  }
+  [(set_attr "adjust_len" "add_<code>0")])
 
-(define_insn "*addhi3.lt0"
-  [(set (match_operand:HI 0 "register_operand"                   "=w,r")
-        (plus:HI (lt:HI (match_operand:QI 1 "register_operand"    "r,r")
-                        (const_int 0))
-                 (match_operand:HI 2 "register_operand"           "0,0")))
-   (clobber (match_scratch:QI 3                                  "=X,&1"))
+;; *addqi3.lt0   *addqi3.ge0
+;; *addhi3.lt0   *addhi3.ge0
+;; *addpsi3.lt0  *addpsi3.ge0
+;; *addsi3.lt0   *addsi3.ge0
+(define_insn "*add<QISI:mode>3.<code>0"
+  [(set (match_operand:QISI 0 "register_operand"                       "=r")
+        (plus:QISI (gelt:QISI (match_operand:QISI2 1 "register_operand" "r")
+                              (const_int 0))
+                   (match_operand:QISI 2 "register_operand"             "0")))
    (clobber (reg:CC REG_CC))]
   "reload_completed"
-  "@
-	sbrc %1,7\;adiw %0,1
-	lsl %1\;adc %A0,__zero_reg__\;adc %B0,__zero_reg__"
-  [(set_attr "length" "2,3")
-   (set_attr "isa" "adiw,*")])
+  {
+    return avr_out_add_msb (insn, operands, <CODE>, nullptr);
+  }
+  [(set_attr "adjust_len" "add_<code>0")])
 
-(define_insn_and_split "*addpsi3.lt0_split"
-  [(set (match_operand:PSI 0 "register_operand"                         "=r")
-        (plus:PSI (lshiftrt:PSI (match_operand:PSI 1 "register_operand"  "r")
-                                (const_int 23))
-                  (match_operand:PSI 2 "register_operand"                "0")))]
+;; *addqi3.lt0_split   *addqi3.ge0_split
+;; *addhi3.lt0_split   *addhi3.ge0_split
+;; *addpsi3.lt0_split  *addpsi3.ge0_split
+;; *addsi3.lt0_split   *addsi3.ge0_split
+(define_insn_and_split "*add<QISI:mode>3.<code>0_split"
+  [(set (match_operand:QISI 0 "register_operand"                       "=r")
+        (plus:QISI (gelt:QISI (match_operand:QISI2 1 "register_operand" "r")
+                              (const_int 0))
+                   (match_operand:QISI 2 "register_operand"             "0")))]
   ""
   "#"
   "&& reload_completed"
-  [(parallel [(set (match_dup 0)
-                   (plus:PSI (lshiftrt:PSI (match_dup 1)
-                                           (const_int 23))
-                             (match_dup 2)))
+  [; *add<QISI:mode>3.<code>0
+   (parallel [(set (match_dup 0)
+                   (plus:QISI (gelt:QISI (match_dup 1)
+                                         (const_int 0))
+                              (match_dup 2)))
               (clobber (reg:CC REG_CC))])])
 
-(define_insn "*addpsi3.lt0"
-  [(set (match_operand:PSI 0 "register_operand"                         "=r")
-        (plus:PSI (lshiftrt:PSI (match_operand:PSI 1 "register_operand"  "r")
-                                (const_int 23))
-                  (match_operand:PSI 2 "register_operand"                "0")))
-   (clobber (reg:CC REG_CC))]
-  "reload_completed"
-  "mov __tmp_reg__,%C1\;lsl __tmp_reg__
-	adc %A0,__zero_reg__\;adc %B0,__zero_reg__\;adc %C0,__zero_reg__"
-  [(set_attr "length" "5")])
-
-(define_insn_and_split "*addsi3.lt0_split"
-  [(set (match_operand:SI 0 "register_operand"                       "=r")
-        (plus:SI (lshiftrt:SI (match_operand:SI 1 "register_operand"  "r")
-                              (const_int 31))
-                 (match_operand:SI 2 "register_operand"               "0")))]
+;; *subqi3.lt0_split   *subqi3.ge0_split
+;; *subhi3.lt0_split   *subhi3.ge0_split
+;; *subpsi3.lt0_split  *subpsi3.ge0_split
+;; *subsi3.lt0_split   *subsi3.ge0_split
+(define_insn_and_split "*sub<QISI:mode>3.<code>0_split"
+  [(set (match_operand:QISI 0 "register_operand"                        "=r")
+        (minus:QISI (match_operand:QISI 1 "register_operand"             "0")
+                    (gelt:QISI (match_operand:QISI2 2 "register_operand" "r")
+                               (const_int 0))))]
   ""
   "#"
   "&& reload_completed"
-  [(parallel [(set (match_dup 0)
-                   (plus:SI (lshiftrt:SI (match_dup 1)
-                                         (const_int 31))
-                            (match_dup 2)))
+  [; *sub<QISI:mode>3.<code>0
+   (parallel [(set (match_dup 0)
+                   (minus:QISI (match_dup 1)
+                               (gelt:QISI (match_dup 2)
+                                          (const_int 0))))
               (clobber (reg:CC REG_CC))])])
 
-(define_insn "*addsi3.lt0"
-  [(set (match_operand:SI 0 "register_operand"                       "=r")
-        (plus:SI (lshiftrt:SI (match_operand:SI 1 "register_operand"  "r")
-                              (const_int 31))
-                 (match_operand:SI 2 "register_operand"               "0")))
-   (clobber (reg:CC REG_CC))]
-  "reload_completed"
-  "mov __tmp_reg__,%D1\;lsl __tmp_reg__
-	adc %A0,__zero_reg__\;adc %B0,__zero_reg__\;adc %C0,__zero_reg__\;adc %D0,__zero_reg__"
-  [(set_attr "length" "6")])
 
 (define_insn_and_split "*umulqihi3.call_split"
   [(set (reg:HI 24)