https://gcc.gnu.org/g:e21fef7da92ef36af1e1b020ae5f35ef4f3c3fce

commit r15-2102-ge21fef7da92ef36af1e1b020ae5f35ef4f3c3fce
Author: Georg-Johann Lay <[email protected]>
Date:   Thu Jul 4 12:08:34 2024 +0200

    AVR: target/90616 - Improve adding constants that are 0 mod 256.
    
    This patch introduces a new insn that works as an insn combine
    pattern for
    
       (plus:HI (zero_extend:HI (reg:QI))
                (const_0mod256_operannd:HI))
    
    which requires at most 2 instructions.  When the input register operand
    is already in HImode, the addhi3 printer only adds the hi8 part when
    it sees a SYMBOL_REF or CONST aligned to at least 256 bytes.
    (The CONST_INT case was already handled).
    
    gcc/
            PR target/90616
            * config/avr/predicates.md (const_0mod256_operand): New predicate.
            * config/avr/constraints.md (Cp8): New constraint.
            * config/avr/avr.md (*aligned_add_symbol): New insn.
            * config/avr/avr.cc (avr_out_plus_symbol) [HImode]:
            When op2 is a multiple of 256, there is no need to add / subtract
            the lo8 part.
            (avr_rtx_costs_1) [PLUS && HImode]: Return expected costs for
            new insn *aligned_add_symbol as it applies.

Diff:
---
 gcc/config/avr/avr.cc         | 14 ++++++++++++++
 gcc/config/avr/avr.md         | 14 ++++++++++++++
 gcc/config/avr/constraints.md |  5 +++++
 gcc/config/avr/predicates.md  | 14 ++++++++++++++
 4 files changed, 47 insertions(+)

diff --git a/gcc/config/avr/avr.cc b/gcc/config/avr/avr.cc
index 5fc046a310e5..b9064424ffec 100644
--- a/gcc/config/avr/avr.cc
+++ b/gcc/config/avr/avr.cc
@@ -9434,6 +9434,12 @@ avr_out_plus_symbol (rtx *xop, enum rtx_code code, int 
*plen)
 
   gcc_assert (mode == HImode || mode == PSImode);
 
+  if (mode == HImode
+      && const_0mod256_operand (xop[2], HImode))
+    return avr_asm_len (PLUS == code
+                       ? "subi %B0,hi8(-(%2))"
+                       : "subi %B0,hi8(%2)", xop, plen, -1);
+
   avr_asm_len (PLUS == code
               ? "subi %A0,lo8(-(%2))" CR_TAB "sbci %B0,hi8(-(%2))"
               : "subi %A0,lo8(%2)"    CR_TAB "sbci %B0,hi8(%2)",
@@ -12759,6 +12765,14 @@ avr_rtx_costs_1 (rtx x, machine_mode mode, int 
outer_code,
          *total = COSTS_N_INSNS (3);
          return true;
        }
+      // *aligned_add_symbol
+      if (mode == HImode
+         && GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
+         && const_0mod256_operand (XEXP (x, 1), HImode))
+       {
+         *total = COSTS_N_INSNS (1.5);
+         return true;
+       }
 
       // *add<PSISI:mode>3.zero_extend.<QIPSI:mode>
       // *addhi3_zero_extend
diff --git a/gcc/config/avr/avr.md b/gcc/config/avr/avr.md
index 695ff87f0c26..16adb7b85d93 100644
--- a/gcc/config/avr/avr.md
+++ b/gcc/config/avr/avr.md
@@ -1617,6 +1617,20 @@
   "subi %A0,%n2\;sbc %B0,%B0"
   [(set_attr "length" "2")])
 
+;; PR90616: Adding symbols that are aligned to 256 bytes can
+;; save up to two instructions.
+(define_insn "*aligned_add_symbol"
+  [(set (match_operand:HI 0 "register_operand"                         "=d")
+        (plus:HI (zero_extend:HI (match_operand:QI 1 "register_operand" "r"))
+                 (match_operand:HI 2 "const_0mod256_operand"            
"Cp8")))]
+  ""
+  {
+    return REGNO (operands[0]) == REGNO (operands[1])
+      ? "ldi %B0,hi8(%2)"
+      : "mov %A0,%1\;ldi %B0,hi8(%2)";
+  }
+  [(set (attr "length")
+        (symbol_ref ("2 - (REGNO (operands[0]) == REGNO (operands[1]))")))])
 
 ;; Occurs when computing offsets into 16-bit arrays.
 ;; Saves up to 2 instructions.
diff --git a/gcc/config/avr/constraints.md b/gcc/config/avr/constraints.md
index b4e5525d1978..35448614aa7a 100644
--- a/gcc/config/avr/constraints.md
+++ b/gcc/config/avr/constraints.md
@@ -253,6 +253,11 @@
   (and (match_code "const_int")
        (match_test "IN_RANGE (ival, -255, -1)")))
 
+(define_constraint "Cp8"
+  "A constant integer or symbolic operand that is at least .p2align 8."
+  (and (match_code "const_int,symbol_ref,const")
+       (match_test "const_0mod256_operand (op, HImode)")))
+
 ;; CONST_FIXED is no element of 'n' so cook our own.
 ;; "i" or "s" would match but because the insn uses iterators that cover
 ;; INT_MODE, "i" or "s" is not always possible.
diff --git a/gcc/config/avr/predicates.md b/gcc/config/avr/predicates.md
index 12013660ed17..5b49481ff0f3 100644
--- a/gcc/config/avr/predicates.md
+++ b/gcc/config/avr/predicates.md
@@ -171,6 +171,20 @@
 (define_predicate "symbol_ref_operand"
   (match_code "symbol_ref"))
 
+;; Returns true when OP is a SYMBOL_REF, CONST or CONST_INT that is
+;; a multiple of 256, i.e. lo8(OP) = 0.
+(define_predicate "const_0mod256_operand"
+  (ior (and (match_code "symbol_ref")
+            (match_test "SYMBOL_REF_DECL (op)
+                         && DECL_P (SYMBOL_REF_DECL (op))
+                         && DECL_ALIGN (SYMBOL_REF_DECL (op)) >= 8 * 256"))
+       (and (match_code "const")
+            (match_test "GET_CODE (XEXP (op, 0)) == PLUS")
+            (match_test "const_0mod256_operand (XEXP (XEXP (op, 0), 0), 
HImode)")
+            (match_test "const_0mod256_operand (XEXP (XEXP (op, 0), 1), 
HImode)"))
+       (and (match_code "const_int")
+            (match_test "INTVAL (op) % 256 == 0"))))
+
 ;; Return true if OP is a text segment reference.
 ;; This is needed for program memory address expressions.
 (define_predicate "text_segment_operand"

Reply via email to