This patch is similar to https://gcc.gnu.org/r15-5569 (tweak ashift:SI)
but for
ashiftrt and lshiftrt codes. It splits constant shift offsets > 16
into a 3-operand byte shift and a 2-operand residual bit shift.
Moreover, some of the constraint alternatives have been promoted
to 3-operand alternatives regardless of options. For example,
ashift:HI and lshiftrt:HI can support 3 operands for offsets 9...12
without any overhead.
Apart from that, it's a bit of code clean up for 2-byte and 4-byte
shift insns: Use one RTL peephole with any_shift code iterator
instead of 3 individual peepholes. It also removes some useless
split insns; presumably introduced during the cc0 -> CCmode work.
No regressions. Ok for trunk?
Johann
--
AVR: target/117726 - Tweak ashiftrt:SI and lshiftrt:SI insns.
This patch is similar to r15-5569 (tweak ashift:SI) but for
ashiftrt and lshiftrt codes. It splits constant shift offsets > 16
into a 3-operand byte shift and a 2-operand residual bit shift.
Moreover, some of the constraint alternatives have been promoted
to 3-operand alternatives regardless of options. For example,
ashift:HI and lshiftrt:HI can support 3 operands for offsets 9...12
without any overhead.
Apart from that, it's a bit of code clean up for 2-byte and 4-byte
shift insns: Use one RTL peephole with any_shift code iterator
instead of 3 individual peepholes. It also removes some useless
split insns; presumably introduced during the cc0 -> CCmode work.
PR target/117726
gcc/
* config/avr/avr-passes.cc (avr_split_shift): Also handle
ASHIFTRT and LSHIFTRT codes for 4-byte shifts.
(constr_split_shift4): New code_attr.
* config/avr/predicates.md (scratch_or_d_register_operand):
rename to scratch_or_dreg_operand.
* config/avr/avr.md: Same.
(define_peephole2): Write the RTL scratch peephole for 2-byte and
4-byte shifts that generates *sh*<mode>3_const insns using code
iterator any_shift.
(*ashlhi3_const_split, *ashrhi3_const_split, *ashrhi3_const_split)
(*lshrsi3_const_split, *lshrhi3_const_split): Remove useless
split insns.
(define_split) [avropt_split_bit_shift]: Add splitters
for 4-byte ASHIFTRT and LSHIFTRT insns using avr_split_shift().
(ashrsi3, *ashrsi3, *ashrsi3_const): Add "r,0,C4a" and "r,r,C4a"
constraint alternatives depending on 2op, 3op.
(lshrsi3, *lshrsi3, *lshrsi3_const): Add "r,0,C4r" and "r,r,C4r"
constraint alternatives depending on 2op, 3op. Add "r,r,C15".
(lshrhi3, *lshrhi3, *lshrhi3_const, ashlhi3, *ashlhi3)
(*ashlhi3_const): Add "r,r,C7c" alternative.
* config/avr/constraints.md (C7c): New constraint in 7...12.
* config/avr/avr.cc (ashlhi3_out, lshrhi3_out)
[case 7, 9, 10, 11, 12]: Support as 3-operand insn.
(lshrsi3_out) [case 15]: Support as 3-operand insn.
* doc/invoke.texi (AVR Options) <-msplit-bit-shift>: Document.
AVR: target/117726 - Tweak ashiftrt:SI and lshiftrt:SI insns.
This patch is similar to r15-5569 (tweak ashift:SI) but for
ashiftrt and lshiftrt codes. It splits constant shift offsets > 16
into a 3-operand byte shift and a 2-operand residual bit shift.
Moreover, some of the constraint alternatives have been promoted
to 3-operand alternatives regardless of options. For example,
ashift:HI and lshiftrt:HI can support 3 operands for offsets 9...12
without any overhead.
Apart from that, it's a bit of code clean up for 2-byte and 4-byte
shift insns: Use one RTL peephole with any_shift code iterator
instead of 3 individual peepholes. It also removes some useless
split insns; presumably introduced during the cc0 -> CCmode work.
PR target/117726
gcc/
* config/avr/avr-passes.cc (avr_split_shift): Also handle
ASHIFTRT and LSHIFTRT codes for 4-byte shifts.
(constr_split_shift4): New code_attr.
* config/avr/predicates.md (scratch_or_d_register_operand):
rename to scratch_or_dreg_operand.
* config/avr/avr.md: Same.
(define_peephole2): Write the RTL scratch peephole for 2-byte and
4-byte shifts that generates *sh*<mode>3_const insns using code
iterator any_shift.
(*ashlhi3_const_split, *ashrhi3_const_split, *ashrhi3_const_split)
(*lshrsi3_const_split, *lshrhi3_const_split): Remove useless
split insns.
(define_split) [avropt_split_bit_shift]: Add splitters
for 4-byte ASHIFTRT and LSHIFTRT insns using avr_split_shift().
(ashrsi3, *ashrsi3, *ashrsi3_const): Add "r,0,C4a" and "r,r,C4a"
constraint alternatives depending on 2op, 3op.
(lshrsi3, *lshrsi3, *lshrsi3_const): Add "r,0,C4r" and "r,r,C4r"
constraint alternatives depending on 2op, 3op. Add "r,r,C15".
(lshrhi3, *lshrhi3, *lshrhi3_const, ashlhi3, *ashlhi3)
(*ashlhi3_const): Add "r,r,C7c" alternative.
* config/avr/constraints.md (C7c): New constraint in 7...12.
* config/avr/avr.cc (ashlhi3_out, lshrhi3_out)
[case 7, 9, 10, 11, 12]: Support as 3-operand insn.
(lshrsi3_out) [case 15]: Support as 3-operand insn.
* doc/invoke.texi (AVR Options) <-msplit-bit-shift>: Document.
diff --git a/gcc/config/avr/avr-passes.cc b/gcc/config/avr/avr-passes.cc
index 57c3fed1e41..3eedee5d206 100644
--- a/gcc/config/avr/avr-passes.cc
+++ b/gcc/config/avr/avr-passes.cc
@@ -4840,22 +4840,38 @@ avr_shift_is_3op ()
LSHIFTRT, ASHIFT } into a byte shift and a residual bit shift. */
bool
-avr_split_shift_p (int n_bytes, int offset, rtx_code)
+avr_split_shift_p (int n_bytes, int offset, rtx_code code)
{
gcc_assert (n_bytes == 4);
- return (avr_shift_is_3op ()
- && offset % 8 != 0 && IN_RANGE (offset, 17, 30));
+ if (avr_shift_is_3op ()
+ && offset % 8 != 0)
+ return select<bool>()
+ : code == ASHIFT ? IN_RANGE (offset, 17, 30)
+ : code == ASHIFTRT ? IN_RANGE (offset, 9, 30)
+ : code == LSHIFTRT ? IN_RANGE (offset, 9, 30) && offset != 15
+ : bad_case<bool> ();
+
+ return false;
}
+/* Emit a DEST = SRC <code> OFF shift of QImode or HImode.
+ SCRATCH is a QImode d-register or NULL_RTX. */
+
static void
avr_emit_shift (rtx_code code, rtx dest, rtx src, int off, rtx scratch)
{
- machine_mode mode = GET_MODE (dest);
+ const machine_mode mode = GET_MODE (dest);
+ bool is_3op = off % 8 == 0;
+ is_3op |= mode == QImode && off == 7;
+ is_3op |= mode == HImode && off == 15;
+ is_3op |= (mode == HImode
+ && (code == ASHIFT || code == LSHIFTRT)
+ && IN_RANGE (off, 7, 12)); // "r,r,C7c"
rtx shift;
- if (off == GET_MODE_BITSIZE (mode) - 1)
+ if (is_3op)
{
shift = gen_rtx_fmt_ee (code, mode, src, GEN_INT (off));
}
@@ -4870,7 +4886,7 @@ avr_emit_shift (rtx_code code, rtx dest, rtx src, int off, rtx scratch)
}
-/* Worker for define_split that run when -msplit-bit-shift is on.
+/* Worker for define_split that runs when -msplit-bit-shift is on.
Split a shift of code CODE into a 3op byte shift and a residual bit shift.
Return 'true' when a split has been performed and insns have been emitted.
Otherwise, return 'false'. */
@@ -4887,25 +4903,73 @@ avr_split_shift (rtx xop[], rtx scratch, rtx_code code)
if (code == ASHIFT)
{
- if (ioff >= 25)
+ if (IN_RANGE (ioff, 25, 30))
{
rtx dst8 = avr_byte (dest, 3);
rtx src8 = avr_byte (src, 0);
- avr_emit_shift (code, dst8, src8, ioff % 8, NULL_RTX);
+ avr_emit_shift (code, dst8, src8, ioff - 24, NULL_RTX);
emit_valid_move_clobbercc (avr_byte (dest, 2), const0_rtx);
emit_valid_move_clobbercc (avr_word (dest, 0), const0_rtx);
return true;
}
- else if (ioff >= 17)
+ else if (IN_RANGE (ioff, 17, 23))
{
rtx dst16 = avr_word (dest, 2);
rtx src16 = avr_word (src, 0);
- avr_emit_shift (code, dst16, src16, ioff % 16, scratch);
+ avr_emit_shift (code, dst16, src16, ioff - 16, scratch);
emit_valid_move_clobbercc (avr_word (dest, 0), const0_rtx);
return true;
}
- else
- gcc_unreachable ();
+ }
+ else if (code == ASHIFTRT
+ || code == LSHIFTRT)
+ {
+ if (IN_RANGE (ioff, 25, 30))
+ {
+ rtx dst8 = avr_byte (dest, 0);
+ rtx src8 = avr_byte (src, 3);
+ avr_emit_shift (code, dst8, src8, ioff - 24, NULL_RTX);
+ if (code == ASHIFTRT)
+ {
+ rtx signs = avr_byte (dest, 1);
+ avr_emit_shift (code, signs, src8, 7, NULL_RTX);
+ emit_valid_move_clobbercc (avr_byte (dest, 2), signs);
+ emit_valid_move_clobbercc (avr_byte (dest, 3), signs);
+ }
+ else
+ {
+ emit_valid_move_clobbercc (avr_byte (dest, 1), const0_rtx);
+ emit_valid_move_clobbercc (avr_word (dest, 2), const0_rtx);
+ }
+ return true;
+ }
+ else if (IN_RANGE (ioff, 17, 23))
+ {
+ rtx dst16 = avr_word (dest, 0);
+ rtx src16 = avr_word (src, 2);
+ avr_emit_shift (code, dst16, src16, ioff - 16, scratch);
+ if (code == ASHIFTRT)
+ {
+ rtx msb = avr_byte (src, 3);
+ rtx signs = avr_byte (dest, 2);
+ avr_emit_shift (code, signs, msb, 7, NULL_RTX);
+ emit_valid_move_clobbercc (avr_byte (dest, 3), signs);
+ }
+ else
+ emit_valid_move_clobbercc (avr_word (dest, 2), const0_rtx);
+
+ return true;
+ }
+ else if (IN_RANGE (ioff, 9, 15))
+ {
+ avr_emit_shift (code, dest, src, 8, NULL_RTX);
+ rtx dst24 = avr_chunk (PSImode, dest, 0);
+ rtx src24 = avr_chunk (PSImode, dest, 0);
+ if (! scratch)
+ scratch = gen_rtx_SCRATCH (QImode);
+ avr_emit_shift (code, dst24, src24, ioff - 8, scratch);
+ return true;
+ }
}
else
gcc_unreachable ();
diff --git a/gcc/config/avr/avr.cc b/gcc/config/avr/avr.cc
index cc13dae9bfe..d9aa3d03f18 100644
--- a/gcc/config/avr/avr.cc
+++ b/gcc/config/avr/avr.cc
@@ -6809,6 +6809,7 @@ ashlhi3_out (rtx_insn *insn, rtx operands[], int *plen)
&& XVECLEN (PATTERN (insn), 0) == 3
&& REG_P (operands[3]));
bool ldi_ok = test_hard_reg_class (LD_REGS, operands[0]);
+ bool reg1_unused_after = reg_unused_after (insn, operands[1]);
if (plen)
*plen = 0;
@@ -6878,43 +6879,50 @@ ashlhi3_out (rtx_insn *insn, rtx operands[], int *plen)
"mov %B0,%A0" CR_TAB
"mov %A0,__tmp_reg__", operands, plen, 9);
case 7:
- return avr_asm_len ("lsr %B0" CR_TAB
- "mov %B0,%A0" CR_TAB
- "clr %A0" CR_TAB
- "ror %B0" CR_TAB
- "ror %A0", operands, plen, 5);
+ return reg1_unused_after
+ ? avr_asm_len ("lsr %B1" CR_TAB
+ "mov %B0,%A1" CR_TAB
+ "clr %A0" CR_TAB
+ "ror %B0" CR_TAB
+ "ror %A0", operands, plen, 5)
+ : avr_asm_len ("bst %B1,0" CR_TAB
+ "mov %B0,%A1" CR_TAB
+ "clr %A0" CR_TAB
+ "ror %B0" CR_TAB
+ "ror %A0" CR_TAB
+ "bld %B0,7", operands, plen, 6);
case 8:
return avr_asm_len ("mov %B0,%A1" CR_TAB
"clr %A0", operands, plen, 2);
case 9:
- return avr_asm_len ("mov %B0,%A0" CR_TAB
+ return avr_asm_len ("mov %B0,%A1" CR_TAB
"clr %A0" CR_TAB
"lsl %B0", operands, plen, 3);
case 10:
- return avr_asm_len ("mov %B0,%A0" CR_TAB
+ return avr_asm_len ("mov %B0,%A1" CR_TAB
"clr %A0" CR_TAB
"lsl %B0" CR_TAB
"lsl %B0", operands, plen, 4);
case 11:
- return avr_asm_len ("mov %B0,%A0" CR_TAB
+ return avr_asm_len ("mov %B0,%A1" CR_TAB
"clr %A0" CR_TAB
"lsl %B0" CR_TAB
"lsl %B0" CR_TAB
"lsl %B0", operands, plen, 5);
case 12:
if (ldi_ok)
- return avr_asm_len ("mov %B0,%A0" CR_TAB
+ return avr_asm_len ("mov %B0,%A1" CR_TAB
"clr %A0" CR_TAB
"swap %B0" CR_TAB
"andi %B0,0xf0", operands, plen, 4);
if (scratch)
- return avr_asm_len ("mov %B0,%A0" CR_TAB
+ return avr_asm_len ("mov %B0,%A1" CR_TAB
"clr %A0" CR_TAB
"swap %B0" CR_TAB
"ldi %3,0xf0" CR_TAB
"and %B0,%3", operands, plen, 5);
- return avr_asm_len ("mov %B0,%A0" CR_TAB
+ return avr_asm_len ("mov %B0,%A1" CR_TAB
"clr %A0" CR_TAB
"lsl %B0" CR_TAB
"lsl %B0" CR_TAB
@@ -7566,6 +7574,7 @@ lshrhi3_out (rtx_insn *insn, rtx operands[], int *plen)
&& XVECLEN (PATTERN (insn), 0) == 3
&& REG_P (operands[3]));
bool ldi_ok = test_hard_reg_class (LD_REGS, operands[0]);
+ bool reg1_unused_after = reg_unused_after (insn, operands[1]);
if (plen)
*plen = 0;
@@ -7635,42 +7644,49 @@ lshrhi3_out (rtx_insn *insn, rtx operands[], int *plen)
"mov %A0,%B0" CR_TAB
"mov %B0,__tmp_reg__", operands, plen, 9);
case 7:
- return avr_asm_len ("lsl %A0" CR_TAB
- "mov %A0,%B0" CR_TAB
- "rol %A0" CR_TAB
- "sbc %B0,%B0" CR_TAB
- "neg %B0", operands, plen, 5);
+ return reg1_unused_after
+ ? avr_asm_len ("lsl %A1" CR_TAB
+ "mov %A0,%B1" CR_TAB
+ "rol %A0" CR_TAB
+ "sbc %B0,%B0" CR_TAB
+ "neg %B0", operands, plen, 5)
+ : avr_asm_len ("bst %A1,7" CR_TAB
+ "mov %A0,%B1" CR_TAB
+ "rol %A0" CR_TAB
+ "sbc %B0,%B0" CR_TAB
+ "neg %B0" CR_TAB
+ "bld %A0,0", operands, plen, 6);
case 8:
return avr_asm_len ("mov %A0,%B1" CR_TAB
"clr %B0", operands, plen, 2);
case 9:
- return avr_asm_len ("mov %A0,%B0" CR_TAB
+ return avr_asm_len ("mov %A0,%B1" CR_TAB
"clr %B0" CR_TAB
"lsr %A0", operands, plen, 3);
case 10:
- return avr_asm_len ("mov %A0,%B0" CR_TAB
+ return avr_asm_len ("mov %A0,%B1" CR_TAB
"clr %B0" CR_TAB
"lsr %A0" CR_TAB
"lsr %A0", operands, plen, 4);
case 11:
- return avr_asm_len ("mov %A0,%B0" CR_TAB
+ return avr_asm_len ("mov %A0,%B1" CR_TAB
"clr %B0" CR_TAB
"lsr %A0" CR_TAB
"lsr %A0" CR_TAB
"lsr %A0", operands, plen, 5);
case 12:
if (ldi_ok)
- return avr_asm_len ("mov %A0,%B0" CR_TAB
+ return avr_asm_len ("mov %A0,%B1" CR_TAB
"clr %B0" CR_TAB
"swap %A0" CR_TAB
"andi %A0,0x0f", operands, plen, 4);
return scratch
- ? avr_asm_len ("mov %A0,%B0" CR_TAB
+ ? avr_asm_len ("mov %A0,%B1" CR_TAB
"clr %B0" CR_TAB
"swap %A0" CR_TAB
"ldi %3,0x0f" CR_TAB
"and %A0,%3", operands, plen, 5)
- : avr_asm_len ("mov %A0,%B0" CR_TAB
+ : avr_asm_len ("mov %A0,%B1" CR_TAB
"clr %B0" CR_TAB
"lsr %A0" CR_TAB
"lsr %A0" CR_TAB
@@ -7816,6 +7832,7 @@ lshrsi3_out (rtx_insn *insn, rtx operands[], int *plen)
{
int reg0 = true_regnum (operands[0]);
int reg1 = true_regnum (operands[1]);
+ bool reg1_unused_after_p = reg_unused_after (insn, operands[1]);
if (plen)
*plen = 0;
@@ -7844,6 +7861,30 @@ lshrsi3_out (rtx_insn *insn, rtx operands[], int *plen)
"mov %C0,%D1" CR_TAB
"mov %B0,%C1" CR_TAB
"mov %A0,%B1", operands, plen, 4);
+ case 15:
+ avr_asm_len (reg1_unused_after_p
+ ? "lsl %B1"
+ : "bst %B1,7", operands, plen, 1);
+ if (reg0 != reg1 + 2)
+ {
+ if (AVR_HAVE_MOVW)
+ avr_asm_len ("movw %A0,%C1", operands, plen, 1);
+ else
+ avr_asm_len ("mov %A0,%C1" CR_TAB
+ "mov %B0,%D1", operands, plen, 2);
+ }
+ return reg1_unused_after_p
+ ? avr_asm_len ("clr %D0" CR_TAB
+ "clr %C0" CR_TAB
+ "rol %A0" CR_TAB
+ "rol %B0" CR_TAB
+ "rol %C0", operands, plen, 5)
+ : avr_asm_len ("clr %D0" CR_TAB
+ "clr %C0" CR_TAB
+ "lsl %A0" CR_TAB
+ "rol %B0" CR_TAB
+ "rol %C0" CR_TAB
+ "bld %A0,0", operands, plen, 6);
case 16:
if (reg0 == reg1 + 2)
return avr_asm_len ("clr %C0" CR_TAB
@@ -12723,8 +12764,13 @@ avr_rtx_costs_1 (rtx x, machine_mode mode, int outer_code,
case 2:
*total = COSTS_N_INSNS (!speed ? 7 : 8);
break;
- case 8:
+ case 15:
+ *total = COSTS_N_INSNS (8 - AVR_HAVE_MOVW);
+ break;
case 16:
+ *total = COSTS_N_INSNS (4 - AVR_HAVE_MOVW);
+ break;
+ case 8:
case 24:
*total = COSTS_N_INSNS (4);
break;
diff --git a/gcc/config/avr/avr.md b/gcc/config/avr/avr.md
index 59e327fe727..55648c460f7 100644
--- a/gcc/config/avr/avr.md
+++ b/gcc/config/avr/avr.md
@@ -5148,10 +5148,13 @@ (define_insn "*ashl<mode>3"
[(set_attr "length" "5,0,1,2,3,4,6,9")
(set_attr "adjust_len" "ashlqi")])
+;; "ashlhi3"
+;; "ashlhq3" "ashluhq3"
+;; "ashlha3" "ashluha3"
(define_insn_and_split "ashl<mode>3"
- [(set (match_operand:ALL2 0 "register_operand" "=r,r,r,r ,r,r,r")
- (ashift:ALL2 (match_operand:ALL2 1 "register_operand" "0,0,0,r ,0,0,0")
- (match_operand:QI 2 "nop_general_operand" "r,L,P,O C15,K,n,Qm")))]
+ [(set (match_operand:ALL2 0 "register_operand" "=r,r ,r ,r,r")
+ (ashift:ALL2 (match_operand:ALL2 1 "register_operand" "0,0 ,r ,0,0")
+ (match_operand:QI 2 "nop_general_operand" "r,LPK,O C7c C15,n,Qm")))]
""
"#"
"&& reload_completed"
@@ -5160,16 +5163,19 @@ (define_insn_and_split "ashl<mode>3"
(match_dup 2)))
(clobber (reg:CC REG_CC))])])
+;; "*ashlhi3"
+;; "*ashlhq3" "*ashluhq3"
+;; "*ashlha3" "*ashluha3"
(define_insn "*ashl<mode>3"
- [(set (match_operand:ALL2 0 "register_operand" "=r,r,r,r ,r,r,r")
- (ashift:ALL2 (match_operand:ALL2 1 "register_operand" "0,0,0,r ,0,0,0")
- (match_operand:QI 2 "nop_general_operand" "r,L,P,O C15,K,n,Qm")))
+ [(set (match_operand:ALL2 0 "register_operand" "=r,r ,r ,r,r")
+ (ashift:ALL2 (match_operand:ALL2 1 "register_operand" "0,0 ,r ,0,0")
+ (match_operand:QI 2 "nop_general_operand" "r,LPK,O C7c C15,n,Qm")))
(clobber (reg:CC REG_CC))]
"reload_completed"
{
return ashlhi3_out (insn, operands, NULL);
}
- [(set_attr "length" "6,0,2,3,4,10,10")
+ [(set_attr "length" "10")
(set_attr "adjust_len" "ashlhi")])
@@ -5342,69 +5348,61 @@ (define_peephole2 ; ashlqi3_l_const6
operands[2] = avr_to_int_mode (operands[0]);
})
-(define_peephole2
+(define_peephole2 ; *ashlhi3_const *ashrhi3_const *lshrhi3_const
[(match_scratch:QI 3 "d")
- (parallel [(set (match_operand:ALL2 0 "register_operand" "")
- (ashift:ALL2 (match_operand:ALL2 1 "register_operand" "")
- (match_operand:QI 2 "const_int_operand" "")))
- (clobber (reg:CC REG_CC))])]
+ (parallel [(set (match_operand:ALL2 0 "register_operand")
+ (any_shift:ALL2 (match_operand:ALL2 1 "register_operand")
+ (match_operand:QI 2 "const_int_operand")))
+ (clobber (reg:CC REG_CC))])
+ ;; Don't allow $3 to overlap with $0.
+ (match_dup 3)]
""
[(parallel [(set (match_dup 0)
- (ashift:ALL2 (match_dup 1)
- (match_dup 2)))
+ (any_shift:ALL2 (match_dup 1)
+ (match_dup 2)))
(clobber (match_dup 3))
(clobber (reg:CC REG_CC))])])
;; "*ashlhi3_const"
;; "*ashlhq3_const" "*ashluhq3_const"
;; "*ashlha3_const" "*ashluha3_const"
-(define_insn_and_split "*ashl<mode>3_const_split"
- [(set (match_operand:ALL2 0 "register_operand" "=r,r,r ,r,r")
- (ashift:ALL2 (match_operand:ALL2 1 "register_operand" "0,0,r ,0,0")
- (match_operand:QI 2 "const_int_operand" "L,P,O C15,K,n")))
- (clobber (match_scratch:QI 3 "=X,X,X ,X,&d"))]
- "reload_completed"
- "#"
- "&& reload_completed"
- [(parallel [(set (match_dup 0)
- (ashift:ALL2 (match_dup 1)
- (match_dup 2)))
- (clobber (match_dup 3))
- (clobber (reg:CC REG_CC))])])
-
(define_insn "*ashl<mode>3_const"
- [(set (match_operand:ALL2 0 "register_operand" "=r,r,r ,r,r")
- (ashift:ALL2 (match_operand:ALL2 1 "register_operand" "0,0,r ,0,0")
- (match_operand:QI 2 "const_int_operand" "L,P,O C15,K,n")))
- (clobber (match_scratch:QI 3 "=X,X,X ,X,&d"))
+ [(set (match_operand:ALL2 0 "register_operand" "=r ,r ,r")
+ (ashift:ALL2 (match_operand:ALL2 1 "register_operand" "0 ,r ,0")
+ (match_operand:QI 2 "const_int_operand" "LPK,O C7c C15,n")))
+ (clobber (match_scratch:QI 3 "=X ,X ,&d"))
(clobber (reg:CC REG_CC))]
"reload_completed"
{
return ashlhi3_out (insn, operands, NULL);
}
- [(set_attr "length" "0,2,2,4,10")
+ [(set_attr "length" "10")
(set_attr "adjust_len" "ashlhi")])
+(define_code_attr constr_split_shift4
+ [(ashift "C4l")
+ (ashiftrt "C4a")
+ (lshiftrt "C4r")])
;; Split shift into a byte shift and a residual bit shift (without scratch)
(define_split
[(parallel [(set (match_operand:ALL4 0 "register_operand")
- (ashift:ALL4 (match_operand:ALL4 1 "register_operand")
- (match_operand:QI 2 "const_int_operand")))
+ (any_shift:ALL4 (match_operand:ALL4 1 "register_operand")
+ (match_operand:QI 2 "const_int_operand")))
(clobber (reg:CC REG_CC))])]
"avropt_split_bit_shift
&& n_avr_fuse_add_executed >= 1
- && satisfies_constraint_C4l (operands[2])"
+ && satisfies_constraint_<constr_split_shift4> (operands[2])"
[(parallel [(set (match_dup 0)
- (ashift:ALL4 (match_dup 1)
- (match_dup 3)))
+ (any_shift:ALL4 (match_dup 1)
+ (match_dup 3)))
(clobber (reg:CC REG_CC))])
(parallel [(set (match_dup 0)
- (ashift:ALL4 (match_dup 0)
- (match_dup 4)))
+ (any_shift:ALL4 (match_dup 0)
+ (match_dup 4)))
(clobber (reg:CC REG_CC))])]
{
- if (avr_split_shift (operands, NULL_RTX, ASHIFT))
+ if (avr_split_shift (operands, NULL_RTX, <CODE>))
DONE;
else if (REGNO (operands[0]) == REGNO (operands[1]))
FAIL;
@@ -5416,24 +5414,24 @@ (define_split
;; Split shift into a byte shift and a residual bit shift (with scratch)
(define_split
[(parallel [(set (match_operand:ALL4 0 "register_operand")
- (ashift:ALL4 (match_operand:ALL4 1 "register_operand")
- (match_operand:QI 2 "const_int_operand")))
- (clobber (match_operand:QI 3 "scratch_or_d_register_operand"))
+ (any_shift:ALL4 (match_operand:ALL4 1 "register_operand")
+ (match_operand:QI 2 "const_int_operand")))
+ (clobber (match_operand:QI 3 "scratch_or_dreg_operand"))
(clobber (reg:CC REG_CC))])]
"avropt_split_bit_shift
&& n_avr_fuse_add_executed >= 1
- && satisfies_constraint_C4l (operands[2])"
+ && satisfies_constraint_<constr_split_shift4> (operands[2])"
[(parallel [(set (match_dup 0)
- (ashift:ALL4 (match_dup 1)
- (match_dup 4)))
+ (any_shift:ALL4 (match_dup 1)
+ (match_dup 4)))
(clobber (reg:CC REG_CC))])
(parallel [(set (match_dup 0)
- (ashift:ALL4 (match_dup 0)
- (match_dup 5)))
+ (any_shift:ALL4 (match_dup 0)
+ (match_dup 5)))
(clobber (match_dup 3))
(clobber (reg:CC REG_CC))])]
{
- if (avr_split_shift (operands, operands[3], ASHIFT))
+ if (avr_split_shift (operands, operands[3], <CODE>))
DONE;
else if (REGNO (operands[0]) == REGNO (operands[1]))
FAIL;
@@ -5443,27 +5441,31 @@ (define_split
})
-(define_peephole2
+;; Endow 4-byte shift with a scratch if available.
+(define_peephole2 ; *ashrsi3_const *lshrsi3_const *ashlsi3_const
[(match_scratch:QI 3 "d")
- (parallel [(set (match_operand:ALL4 0 "register_operand" "")
- (ashift:ALL4 (match_operand:ALL4 1 "register_operand" "")
- (match_operand:QI 2 "const_int_operand" "")))
+ (parallel [(set (match_operand:ALL4 0 "register_operand")
+ (any_shift:ALL4 (match_operand:ALL4 1 "register_operand")
+ (match_operand:QI 2 "const_int_operand")))
(clobber (reg:CC REG_CC))])
;; $3 must not overlap with the output of the insn above.
(match_dup 3)]
""
[(parallel [(set (match_dup 0)
- (ashift:ALL4 (match_dup 1)
- (match_dup 2)))
+ (any_shift:ALL4 (match_dup 1)
+ (match_dup 2)))
(clobber (match_dup 3))
(clobber (reg:CC REG_CC))])])
+;; "*ashlsi3_const"
+;; "*ashlsq3_const" "*ashlusq3_const"
+;; "*ashlsa3_const" "*ashlusa3_const"
(define_insn "*ashl<mode>3_const"
- [(set (match_operand:ALL4 0 "register_operand" "=r ,r ,r ,r ,r")
- (ashift:ALL4 (match_operand:ALL4 1 "register_operand" "0 ,r ,0 ,r ,0")
- (match_operand:QI 2 "const_int_operand" "LP,O C15 C31,C4l,C4l,n")))
- (clobber (match_operand:QI 3 "scratch_or_d_register_operand" "=X ,X ,&d ,&d ,&d"))
+ [(set (match_operand:ALL4 0 "register_operand" "=r ,r ,r ,r ,r")
+ (ashift:ALL4 (match_operand:ALL4 1 "register_operand" "0 ,r ,0 ,r ,0")
+ (match_operand:QI 2 "const_int_operand" "LP,O C15 C31,C4l,C4l,n")))
+ (clobber (match_operand:QI 3 "scratch_or_dreg_operand" "=X ,X ,&d ,&d ,&d"))
(clobber (reg:CC REG_CC))]
"reload_completed"
{
@@ -5612,61 +5614,36 @@ (define_insn "*ashrpsi3"
;; "ashrsq3" "ashrusq3"
;; "ashrsa3" "ashrusa3"
(define_insn_and_split "ashr<mode>3"
- [(set (match_operand:ALL4 0 "register_operand" "=r,r,r,r ,r,r,r")
- (ashiftrt:ALL4 (match_operand:ALL4 1 "register_operand" "0,0,0,r ,0,0,0")
- (match_operand:QI 2 "nop_general_operand" "r,L,P,O C31,K,n,Qm")))]
+ [(set (match_operand:ALL4 0 "register_operand" "=r,r ,r ,r ,r ,r,r")
+ (ashiftrt:ALL4 (match_operand:ALL4 1 "register_operand" "0,0 ,r ,0 ,r ,0,0")
+ (match_operand:QI 2 "nop_general_operand" "r,LPK,O C31,C4a,C4a,n,Qm")))]
""
"#"
"&& reload_completed"
[(parallel [(set (match_dup 0)
(ashiftrt:ALL4 (match_dup 1)
(match_dup 2)))
- (clobber (reg:CC REG_CC))])])
+ (clobber (reg:CC REG_CC))])]
+ ""
+ [(set_attr "isa" "*,*,*,2op,3op,*,*")])
(define_insn "*ashr<mode>3"
- [(set (match_operand:ALL4 0 "register_operand" "=r,r,r,r ,r,r,r")
- (ashiftrt:ALL4 (match_operand:ALL4 1 "register_operand" "0,0,0,r ,0,0,0")
- (match_operand:QI 2 "nop_general_operand" "r,L,P,O C31,K,n,Qm")))
+ [(set (match_operand:ALL4 0 "register_operand" "=r,r ,r ,r ,r ,r,r")
+ (ashiftrt:ALL4 (match_operand:ALL4 1 "register_operand" "0,0 ,r ,0 ,r ,0,0")
+ (match_operand:QI 2 "nop_general_operand" "r,LPK,O C31,C4a,C4a,n,Qm")))
(clobber (reg:CC REG_CC))]
"reload_completed"
{
return ashrsi3_out (insn, operands, NULL);
}
- [(set_attr "length" "8,0,4,6,8,10,12")
+ [(set_attr "isa" "*,*,*,2op,3op,*,*")
+ (set_attr "length" "12")
(set_attr "adjust_len" "ashrsi")])
-;; Optimize if a scratch register from LD_REGS happens to be available.
-
-(define_peephole2
- [(match_scratch:QI 3 "d")
- (parallel [(set (match_operand:ALL2 0 "register_operand" "")
- (ashiftrt:ALL2 (match_operand:ALL2 1 "register_operand" "")
- (match_operand:QI 2 "const_int_operand" "")))
- (clobber (reg:CC REG_CC))])]
- ""
- [(parallel [(set (match_dup 0)
- (ashiftrt:ALL2 (match_dup 1)
- (match_dup 2)))
- (clobber (match_dup 3))
- (clobber (reg:CC REG_CC))])])
;; "*ashrhi3_const"
;; "*ashrhq3_const" "*ashruhq3_const"
;; "*ashrha3_const" "*ashruha3_const"
-(define_insn_and_split "*ashr<mode>3_const_split"
- [(set (match_operand:ALL2 0 "register_operand" "=r,r,r ,r,r")
- (ashiftrt:ALL2 (match_operand:ALL2 1 "register_operand" "0,0,r ,0,0")
- (match_operand:QI 2 "const_int_operand" "L,P,O C15,K,n")))
- (clobber (match_scratch:QI 3 "=X,X,X ,X,&d"))]
- "reload_completed"
- "#"
- "&& reload_completed"
- [(parallel [(set (match_dup 0)
- (ashiftrt:ALL2 (match_dup 1)
- (match_dup 2)))
- (clobber (match_dup 3))
- (clobber (reg:CC REG_CC))])])
-
(define_insn "*ashr<mode>3_const"
[(set (match_operand:ALL2 0 "register_operand" "=r,r,r ,r,r")
(ashiftrt:ALL2 (match_operand:ALL2 1 "register_operand" "0,0,r ,0,0")
@@ -5680,47 +5657,22 @@ (define_insn "*ashr<mode>3_const"
[(set_attr "length" "0,2,4,4,10")
(set_attr "adjust_len" "ashrhi")])
-(define_peephole2
- [(match_scratch:QI 3 "d")
- (parallel [(set (match_operand:ALL4 0 "register_operand" "")
- (ashiftrt:ALL4 (match_operand:ALL4 1 "register_operand" "")
- (match_operand:QI 2 "const_int_operand" "")))
- (clobber (reg:CC REG_CC))])]
- ""
- [(parallel [(set (match_dup 0)
- (ashiftrt:ALL4 (match_dup 1)
- (match_dup 2)))
- (clobber (match_dup 3))
- (clobber (reg:CC REG_CC))])])
;; "*ashrsi3_const"
;; "*ashrsq3_const" "*ashrusq3_const"
;; "*ashrsa3_const" "*ashrusa3_const"
-(define_insn_and_split "*ashr<mode>3_const_split"
- [(set (match_operand:ALL4 0 "register_operand" "=r,r,r ,r")
- (ashiftrt:ALL4 (match_operand:ALL4 1 "register_operand" "0,0,r ,0")
- (match_operand:QI 2 "const_int_operand" "L,P,O C31,n")))
- (clobber (match_scratch:QI 3 "=X,X,X ,&d"))]
- "reload_completed"
- "#"
- "&& reload_completed"
- [(parallel [(set (match_dup 0)
- (ashiftrt:ALL4 (match_dup 1)
- (match_dup 2)))
- (clobber (match_dup 3))
- (clobber (reg:CC REG_CC))])])
-
(define_insn "*ashr<mode>3_const"
- [(set (match_operand:ALL4 0 "register_operand" "=r,r,r ,r")
- (ashiftrt:ALL4 (match_operand:ALL4 1 "register_operand" "0,0,r ,0")
- (match_operand:QI 2 "const_int_operand" "L,P,O C31,n")))
- (clobber (match_scratch:QI 3 "=X,X,X ,&d"))
+ [(set (match_operand:ALL4 0 "register_operand" "=r ,r ,r ,r ,r")
+ (ashiftrt:ALL4 (match_operand:ALL4 1 "register_operand" "0 ,r ,0 ,r ,0")
+ (match_operand:QI 2 "const_int_operand" "LP,O C31,C4a,C4a,n")))
+ (clobber (match_operand:QI 3 "scratch_or_dreg_operand" "=X ,X ,&d ,&d ,&d"))
(clobber (reg:CC REG_CC))]
"reload_completed"
{
return ashrsi3_out (insn, operands, NULL);
}
- [(set_attr "length" "0,4,4,10")
+ [(set_attr "isa" "*,*,2op,3op,*")
+ (set_attr "length" "10")
(set_attr "adjust_len" "ashrsi")])
;; >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >> >>
@@ -5802,9 +5754,9 @@ (define_insn "*lshr<mode>3"
;; "lshrhq3" "lshruhq3"
;; "lshrha3" "lshruha3"
(define_insn_and_split "lshr<mode>3"
- [(set (match_operand:ALL2 0 "register_operand" "=r,r,r,r,r ,r,r,r")
- (lshiftrt:ALL2 (match_operand:ALL2 1 "register_operand" "0,0,0,r,r ,0,0,0")
- (match_operand:QI 2 "nop_general_operand" "r,L,P,O,C15,K,n,Qm")))]
+ [(set (match_operand:ALL2 0 "register_operand" "=r,r ,r ,r,r")
+ (lshiftrt:ALL2 (match_operand:ALL2 1 "register_operand" "0,0 ,r ,0,0")
+ (match_operand:QI 2 "nop_general_operand" "r,LPK,O C7c C15,n,Qm")))]
""
"#"
"&& reload_completed"
@@ -5814,9 +5766,9 @@ (define_insn_and_split "lshr<mode>3"
(clobber (reg:CC REG_CC))])])
(define_insn "*lshr<mode>3"
- [(set (match_operand:ALL2 0 "register_operand" "=r,r,r,r,r ,r,r,r")
- (lshiftrt:ALL2 (match_operand:ALL2 1 "register_operand" "0,0,0,r,r ,0,0,0")
- (match_operand:QI 2 "nop_general_operand" "r,L,P,O,C15,K,n,Qm")))
+ [(set (match_operand:ALL2 0 "register_operand" "=r,r ,r ,r,r")
+ (lshiftrt:ALL2 (match_operand:ALL2 1 "register_operand" "0,0 ,r ,0,0")
+ (match_operand:QI 2 "nop_general_operand" "r,LPK,O C7c C15,n,Qm")))
(clobber (reg:CC REG_CC))]
"reload_completed"
{
@@ -5854,27 +5806,30 @@ (define_insn "*lshrpsi3"
;; "lshrsq3" "lshrusq3"
;; "lshrsa3" "lshrusa3"
(define_insn_and_split "lshr<mode>3"
- [(set (match_operand:ALL4 0 "register_operand" "=r,r,r,r,r,r ,r,r")
- (lshiftrt:ALL4 (match_operand:ALL4 1 "register_operand" "0,0,0,r,0,r ,0,0")
- (match_operand:QI 2 "nop_general_operand" "r,L,P,O,K,C31,n,Qm")))]
+ [(set (match_operand:ALL4 0 "register_operand" "=r,r ,r ,r ,r ,r,r")
+ (lshiftrt:ALL4 (match_operand:ALL4 1 "register_operand" "0,0 ,r ,0 ,r ,0,0")
+ (match_operand:QI 2 "nop_general_operand" "r,LPK,O C15 C31,C4r,C4r,n,Qm")))]
""
"#"
"&& reload_completed"
[(parallel [(set (match_dup 0)
(lshiftrt:ALL4 (match_dup 1)
(match_dup 2)))
- (clobber (reg:CC REG_CC))])])
+ (clobber (reg:CC REG_CC))])]
+ ""
+ [(set_attr "isa" "*,*,*,2op,3op,*,*")])
(define_insn "*lshr<mode>3"
- [(set (match_operand:ALL4 0 "register_operand" "=r,r,r,r,r,r ,r,r")
- (lshiftrt:ALL4 (match_operand:ALL4 1 "register_operand" "0,0,0,r,0,r ,0,0")
- (match_operand:QI 2 "nop_general_operand" "r,L,P,O,K,C31,n,Qm")))
+ [(set (match_operand:ALL4 0 "register_operand" "=r,r ,r ,r ,r ,r,r")
+ (lshiftrt:ALL4 (match_operand:ALL4 1 "register_operand" "0,0 ,r ,0 ,r ,0,0")
+ (match_operand:QI 2 "nop_general_operand" "r,LPK,O C15 C31,C4r,C4r,n,Qm")))
(clobber (reg:CC REG_CC))]
"reload_completed"
{
return lshrsi3_out (insn, operands, NULL);
}
- [(set_attr "adjust_len" "lshrsi")])
+ [(set_attr "isa" "*,*,*,2op,3op,*,*")
+ (set_attr "adjust_len" "lshrsi")])
;; Optimize if a scratch register from LD_REGS happens to be available.
@@ -5933,41 +5888,15 @@ (define_peephole2 ; lshrqi3_l_const6
operands[2] = avr_to_int_mode (operands[0]);
})
-(define_peephole2 ; "*lshrhi3_const"
- [(match_scratch:QI 3 "d")
- (parallel [(set (match_operand:ALL2 0 "register_operand" "")
- (lshiftrt:ALL2 (match_operand:ALL2 1 "register_operand" "")
- (match_operand:QI 2 "const_int_operand" "")))
- (clobber (reg:CC REG_CC))])]
- ""
- [(parallel [(set (match_dup 0)
- (lshiftrt:ALL2 (match_dup 1)
- (match_dup 2)))
- (clobber (match_dup 3))
- (clobber (reg:CC REG_CC))])])
;; "*lshrhi3_const"
;; "*lshrhq3_const" "*lshruhq3_const"
;; "*lshrha3_const" "*lshruha3_const"
-(define_insn_and_split "*lshr<mode>3_const_split"
- [(set (match_operand:ALL2 0 "register_operand" "=r,r,r,r ,r,r")
- (lshiftrt:ALL2 (match_operand:ALL2 1 "register_operand" "0,0,r,r ,0,0")
- (match_operand:QI 2 "const_int_operand" "L,P,O,C15,K,n")))
- (clobber (match_scratch:QI 3 "=X,X,X,X ,X,&d"))]
- "reload_completed"
- "#"
- "&& reload_completed"
- [(parallel [(set (match_dup 0)
- (lshiftrt:ALL2 (match_dup 1)
- (match_dup 2)))
- (clobber (match_dup 3))
- (clobber (reg:CC REG_CC))])])
-
(define_insn "*lshr<mode>3_const"
- [(set (match_operand:ALL2 0 "register_operand" "=r,r,r,r ,r,r")
- (lshiftrt:ALL2 (match_operand:ALL2 1 "register_operand" "0,0,r,r ,0,0")
- (match_operand:QI 2 "const_int_operand" "L,P,O,C15,K,n")))
- (clobber (match_scratch:QI 3 "=X,X,X,X ,X,&d"))
+ [(set (match_operand:ALL2 0 "register_operand" "=r ,r ,r")
+ (lshiftrt:ALL2 (match_operand:ALL2 1 "register_operand" "0 ,r ,0")
+ (match_operand:QI 2 "const_int_operand" "LPK,O C7c C15,n")))
+ (clobber (match_scratch:QI 3 "=X ,X ,&d"))
(clobber (reg:CC REG_CC))]
"reload_completed"
{
@@ -5975,47 +5904,22 @@ (define_insn "*lshr<mode>3_const"
}
[(set_attr "adjust_len" "lshrhi")])
-(define_peephole2 ; "*lshrsi3_const"
- [(match_scratch:QI 3 "d")
- (parallel [(set (match_operand:ALL4 0 "register_operand" "")
- (lshiftrt:ALL4 (match_operand:ALL4 1 "register_operand" "")
- (match_operand:QI 2 "const_int_operand" "")))
- (clobber (reg:CC REG_CC))])]
- ""
- [(parallel [(set (match_dup 0)
- (lshiftrt:ALL4 (match_dup 1)
- (match_dup 2)))
- (clobber (match_dup 3))
- (clobber (reg:CC REG_CC))])])
;; "*lshrsi3_const"
;; "*lshrsq3_const" "*lshrusq3_const"
;; "*lshrsa3_const" "*lshrusa3_const"
-(define_insn_and_split "*lshr<mode>3_const_split"
- [(set (match_operand:ALL4 0 "register_operand" "=r,r,r,r ,r")
- (lshiftrt:ALL4 (match_operand:ALL4 1 "register_operand" "0,0,r,r ,0")
- (match_operand:QI 2 "const_int_operand" "L,P,O,C31,n")))
- (clobber (match_scratch:QI 3 "=X,X,X,X ,&d"))]
- "reload_completed"
- "#"
- "&& reload_completed"
- [(parallel [(set (match_dup 0)
- (lshiftrt:ALL4 (match_dup 1)
- (match_dup 2)))
- (clobber (match_dup 3))
- (clobber (reg:CC REG_CC))])])
-
(define_insn "*lshr<mode>3_const"
- [(set (match_operand:ALL4 0 "register_operand" "=r,r,r,r ,r")
- (lshiftrt:ALL4 (match_operand:ALL4 1 "register_operand" "0,0,r,r ,0")
- (match_operand:QI 2 "const_int_operand" "L,P,O,C31,n")))
- (clobber (match_scratch:QI 3 "=X,X,X,X ,&d"))
+ [(set (match_operand:ALL4 0 "register_operand" "=r ,r ,r ,r ,r")
+ (lshiftrt:ALL4 (match_operand:ALL4 1 "register_operand" "0 ,r ,0 ,r ,0")
+ (match_operand:QI 2 "const_int_operand" "LP,O C15 C31,C4r,C4r,n")))
+ (clobber (match_operand:QI 3 "scratch_or_dreg_operand" "=X ,X ,&d ,&d ,&d"))
(clobber (reg:CC REG_CC))]
"reload_completed"
{
return lshrsi3_out (insn, operands, NULL);
}
- [(set_attr "adjust_len" "lshrsi")])
+ [(set_attr "isa" "*,*,2op,3op,*")
+ (set_attr "adjust_len" "lshrsi")])
;; abs(x) abs(x) abs(x) abs(x) abs(x) abs(x) abs(x) abs(x) abs(x) abs(x) abs(x)
;; abs
@@ -7099,7 +7003,7 @@ (define_peephole2
[(parallel [(set (match_operand:HISI 0 "register_operand")
(plus:HISI (match_dup 0)
(match_operand:HISI 1 "nonmemory_operand")))
- (clobber (match_operand:QI 3 "scratch_or_d_register_operand"))
+ (clobber (match_operand:QI 3 "scratch_or_dreg_operand"))
(clobber (reg:CC REG_CC))])
(parallel [(set (reg:CC REG_CC)
(compare:CC (match_dup 0)
@@ -8167,7 +8071,7 @@ (define_peephole ; "*dec-and-branchsi!=-1.d.clobber"
(parallel [(set (reg:CC REG_CC)
(compare:CC (match_dup 0)
(const_int -1)))
- (clobber (match_operand:QI 1 "scratch_or_d_register_operand"))])
+ (clobber (match_operand:QI 1 "scratch_or_dreg_operand"))])
(set (pc)
(if_then_else (eqne (reg:CC REG_CC)
(const_int 0))
@@ -8247,7 +8151,7 @@ (define_peephole ; "*dec-and-branchhi!=-1.d.clobber"
(parallel [(set (reg:CC REG_CC)
(compare:CC (match_dup 0)
(const_int -1)))
- (clobber (match_operand:QI 1 "scratch_or_d_register_operand"))])
+ (clobber (match_operand:QI 1 "scratch_or_dreg_operand"))])
(set (pc)
(if_then_else (eqne (reg:CC REG_CC)
(const_int 0))
diff --git a/gcc/config/avr/constraints.md b/gcc/config/avr/constraints.md
index a362f31e30b..3562aff6c71 100644
--- a/gcc/config/avr/constraints.md
+++ b/gcc/config/avr/constraints.md
@@ -133,6 +133,11 @@ (define_constraint "C07"
(and (match_code "const_int")
(match_test "ival == 7")))
+(define_constraint "C7c"
+ "Constant integer int the range 7 @dots{} 12."
+ (and (match_code "const_int")
+ (match_test "IN_RANGE (ival, 7, 12)")))
+
(define_constraint "C15"
"Constant integer 15."
(and (match_code "const_int")
diff --git a/gcc/config/avr/predicates.md b/gcc/config/avr/predicates.md
index d852f1c9e08..a28c63a6478 100644
--- a/gcc/config/avr/predicates.md
+++ b/gcc/config/avr/predicates.md
@@ -27,7 +27,7 @@ (define_predicate "d_register_operand"
(and (match_code "reg")
(match_test "REGNO (op) >= 16 && REGNO (op) <= 31")))
-(define_predicate "scratch_or_d_register_operand"
+(define_predicate "scratch_or_dreg_operand"
(ior (match_operand 0 "d_register_operand")
(and (match_code ("scratch"))
(match_operand 0 "scratch_operand"))))
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index c62c6bc5903..91126387694 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -903,7 +903,7 @@ Objective-C and Objective-C++ Dialects}.
-mdouble=@var{bits} -mlong-double=@var{bits}
-mn_flash=@var{size} -mno-interrupts
-mmain-is-OS_task -mrelax -mrmw -mstrict-X -mtiny-stack
--mrodata-in-ram -mfract-convert-truncate
+-mrodata-in-ram -mfract-convert-truncate -msplit-bit-shift
-mshort-calls -mskip-bug -nodevicelib -nodevicespecs
-Waddr-space-convert -Wmisspelled-isr}
@@ -24221,6 +24221,15 @@ ld @var{Rn}, X ; @var{Rn} = *X
sbiw r26, const ; X -= const
@end example
+@opindex msplit-bit-shift
+@item -msplit-bit-shift
+Split multi-byte shifts into a shift with a byte offset and a residual
+shift with a non-byte offset. This optimization is turned on per default
+for @option{-O2} and higher, including @option{-Os} but excluding
+@option{-Oz}. To date, only 4-byte shifts with a shift offset of
+at least 17 are split. Splitting of shifts with an offset that is
+a multiple of 8 is controlled by @option{-mfuse-move}.
+
@opindex mtiny-stack
@item -mtiny-stack
Only change the lower 8@tie{}bits of the stack pointer.