Address computation (usually add) with symbols that are aligned
to 256 bytes does not require to add the lo8() part as it is zero.
This patch adds a new combine insn that performs a widening add
from QImode plus such a symbol. The case when such an aligned
symbol is added to a reg that's already in HImode can be handled
in the addhi3 asm printer.
Ok to apply?
Johann
--
AVR: target90616 - 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.
pr90616-const_0mod256.diff
diff --git a/gcc/config/avr/avr.cc b/gcc/config/avr/avr.cc
index f048bf5fd41..014588dd6a7 100644
--- a/gcc/config/avr/avr.cc
+++ b/gcc/config/avr/avr.cc
@@ -9343,6 +9343,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)",
@@ -12615,6 +12621,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;
+ }
if (GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
&& REG_P (XEXP (x, 1)))
diff --git a/gcc/config/avr/avr.md b/gcc/config/avr/avr.md
index dabf4c0fc5a..72ea1292576 100644
--- a/gcc/config/avr/avr.md
+++ b/gcc/config/avr/avr.md
@@ -10077,6 +10077,23 @@ (define_expand "isinf<mode>2"
FAIL;
})
+
+;; 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]))")))])
+
+
;; Fixed-point instructions
(include "avr-fixed.md")
diff --git a/gcc/config/avr/constraints.md b/gcc/config/avr/constraints.md
index b4e5525d197..35448614aa7 100644
--- a/gcc/config/avr/constraints.md
+++ b/gcc/config/avr/constraints.md
@@ -253,6 +253,11 @@ (define_constraint "Cn8"
(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 12013660ed1..5b49481ff0f 100644
--- a/gcc/config/avr/predicates.md
+++ b/gcc/config/avr/predicates.md
@@ -171,6 +171,20 @@ (define_predicate "reg_or_0_operand"
(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"