From: Georg-Johann Lay Date: Thu, 4 Jul 2024 10:08:34 +0000 (+0200) Subject: AVR: target/90616 - Improve adding constants that are 0 mod 256. X-Git-Tag: basepoints/gcc-16~7451 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e21fef7da92ef36af1e1b020ae5f35ef4f3c3fce;p=thirdparty%2Fgcc.git 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 --git a/gcc/config/avr/avr.cc b/gcc/config/avr/avr.cc index 5fc046a310e..b9064424ffe 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; + } // *add3.zero_extend. // *addhi3_zero_extend diff --git a/gcc/config/avr/avr.md b/gcc/config/avr/avr.md index 695ff87f0c2..16adb7b85d9 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 b4e5525d197..35448614aa7 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 12013660ed1..5b49481ff0f 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"