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.
This commit is contained in:
Georg-Johann Lay 2024-07-04 12:08:34 +02:00
parent 5104fe4c78
commit e21fef7da9
4 changed files with 47 additions and 0 deletions

View File

@ -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

View File

@ -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.

View File

@ -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.

View File

@ -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"