aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorg-Johann Lay <avr@gjlay.de>2025-08-05 17:48:43 +0200
committerGeorg-Johann Lay <avr@gjlay.de>2025-08-05 17:53:58 +0200
commit59236d56eec6854e261dbf16963d5ee9e03bf7d5 (patch)
tree0e16969e00ba09219e4b3eb9a6ae287ddd4e4241
parentc9da74d5ad383b309195afb37b9044c1087da026 (diff)
downloadgcc-master.zip
gcc-master.tar.gz
gcc-master.tar.bz2
AVR: Allow combination of sign_extend with ashift.HEADtrunkmaster
gcc/ * config/avr/avr.cc (avr_rtx_costs_1) [SIGN_EXTEND]: Adjust cost. * config/avr/avr.md (*sext.ashift<QIPSI:mode><HISI:mode>2): New insn and a cc split.
-rw-r--r--gcc/config/avr/avr.cc10
-rw-r--r--gcc/config/avr/avr.md37
2 files changed, 46 insertions, 1 deletions
diff --git a/gcc/config/avr/avr.cc b/gcc/config/avr/avr.cc
index 1bfa3f5..ae49d4d 100644
--- a/gcc/config/avr/avr.cc
+++ b/gcc/config/avr/avr.cc
@@ -12758,6 +12758,16 @@ avr_rtx_costs_1 (rtx x, machine_mode mode, int outer_code,
return true;
case SIGN_EXTEND:
+ if (GET_CODE (XEXP (x, 0)) == ASHIFT
+ && CONST_INT_P (XEXP (XEXP (x, 0), 1)))
+ {
+ // "*sext.ashift<QIPSI:mode><HISI:mode>2_split"
+ int m0 = GET_MODE_SIZE (GET_MODE (XEXP (x, 0)));
+ int m1 = GET_MODE_SIZE (mode);
+ *total = COSTS_N_INSNS (m0 * INTVAL (XEXP (XEXP (x, 0), 1))
+ + m1 - m0);
+ return true;
+ }
*total = COSTS_N_INSNS (n_bytes + 2
- GET_MODE_SIZE (GET_MODE (XEXP (x, 0))));
*total += avr_operand_rtx_cost (XEXP (x, 0), GET_MODE (XEXP (x, 0)),
diff --git a/gcc/config/avr/avr.md b/gcc/config/avr/avr.md
index d4bf4da..60b1f60 100644
--- a/gcc/config/avr/avr.md
+++ b/gcc/config/avr/avr.md
@@ -2943,7 +2943,7 @@
[(set (match_operand:HI 0 "register_operand" "=r,*r")
(ashift:HI (sign_extend:HI (match_operand:QI 1 "register_operand" "0,r"))
(const_int 1)))
- (clobber (reg:CC REG_CC)) ]
+ (clobber (reg:CC REG_CC))]
"reload_completed"
"@
lsl %A0\;sbc %B0,%B0
@@ -3004,6 +3004,41 @@
operands[2] = gen_int_mode (1 << INTVAL (operands[2]), QImode);
})
+(define_insn_and_split "*sext.ashift<QIPSI:mode><HISI:mode>2_split"
+ [(set (match_operand:HISI 0 "register_operand" "=r")
+ (sign_extend:HISI (ashift:QIPSI (match_operand:QIPSI 1 "register_operand" "0")
+ (match_operand:QI 2 "const_int_operand" "PKC03"))))]
+ "<HISI:SIZE> > <QIPSI:SIZE>
+ && IN_RANGE (INTVAL (operands[2]), 1, 2 + (<QIPSI:SIZE> <= 2))"
+ "#"
+ "&& reload_completed"
+ [(scratch)]
+ { DONE_ADD_CCC })
+
+(define_insn "*sext.ashift<QIPSI:mode><HISI:mode>2"
+ [(set (match_operand:HISI 0 "register_operand" "=r")
+ (sign_extend:HISI (ashift:QIPSI (match_operand:QIPSI 1 "register_operand" "0")
+ (match_operand:QI 2 "const_int_operand" "PKC03"))))
+ (clobber (reg:CC REG_CC))]
+ "reload_completed
+ && <HISI:SIZE> > <QIPSI:SIZE>
+ && IN_RANGE (INTVAL (operands[2]), 1, 2 + (<QIPSI:SIZE> <= 2))"
+ {
+ const int regno = REGNO (operands[0]);
+ // The shift.
+ for (int s = 0; s < (int) INTVAL (operands[2]); ++s)
+ for (int b = 0; b < <QIPSI:SIZE>; ++b)
+ output_asm_insn (b == 0 ? "lsl %0" : "rol %0",
+ &all_regs_rtx[regno + b]);
+ // Sign-extend can use carry.
+ for (int b = <QIPSI:SIZE>; b < <HISI:SIZE>; ++b)
+ output_asm_insn ("sbc %0,%0", &all_regs_rtx[regno + b]);
+ return "";
+ }
+ [(set (attr "length")
+ (plus (symbol_ref "<QIPSI:SIZE> * INTVAL (operands[2])")
+ (symbol_ref "<HISI:SIZE> - <QIPSI:SIZE>")))])
+
;******************************************************************************
; mul HI: $1 = sign-/zero-/one-extend, $2 = reg
;******************************************************************************