diff options
author | Georg-Johann Lay <avr@gjlay.de> | 2024-07-04 12:08:34 +0200 |
---|---|---|
committer | Georg-Johann Lay <avr@gjlay.de> | 2024-07-17 17:37:10 +0200 |
commit | e21fef7da92ef36af1e1b020ae5f35ef4f3c3fce (patch) | |
tree | bbfff4188064bf584d89d6ef0d6ebd1497202827 | |
parent | 5104fe4c7808a66ed3041a8da8e4720585cc8a1f (diff) | |
download | gcc-e21fef7da92ef36af1e1b020ae5f35ef4f3c3fce.zip gcc-e21fef7da92ef36af1e1b020ae5f35ef4f3c3fce.tar.gz gcc-e21fef7da92ef36af1e1b020ae5f35ef4f3c3fce.tar.bz2 |
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.
-rw-r--r-- | gcc/config/avr/avr.cc | 14 | ||||
-rw-r--r-- | gcc/config/avr/avr.md | 14 | ||||
-rw-r--r-- | gcc/config/avr/constraints.md | 5 | ||||
-rw-r--r-- | gcc/config/avr/predicates.md | 14 |
4 files changed, 47 insertions, 0 deletions
diff --git a/gcc/config/avr/avr.cc b/gcc/config/avr/avr.cc index 5fc046a..b906442 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 695ff87..16adb7b 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 b4e5525..3544861 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 1201366..5b49481 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" |