}
+/* Return true iff REGNO is in R16...R31. */
+
+static bool
+avr_ld_regno_p (int regno)
+{
+ return TEST_HARD_REG_CLASS (LD_REGS, regno);
+}
+
+
static bool
ra_in_progress ()
{
{
if (CONST_INT_P (operands[2]))
{
+ int off = INTVAL (operands[2]);
int reg0 = true_regnum (operands[0]);
int reg1 = true_regnum (operands[1]);
bool reg1_unused_after = reg_unused_after (insn, operands[1]);
-
+ bool scratch_p = (GET_CODE (PATTERN (insn)) == PARALLEL
+ && XVECLEN (PATTERN (insn), 0) == 3
+ && REG_P (operands[3]));
if (plen)
*plen = 0;
- switch (INTVAL (operands[2]))
+ switch (off)
{
default:
- if (INTVAL (operands[2]) < 32)
+ if (off < 32)
break;
return AVR_HAVE_MOVW
"mov %D0,%B1" CR_TAB
"clr %B0" CR_TAB
"clr %A0", operands, plen, 4);
+ case 30:
+ if (AVR_HAVE_MUL && scratch_p)
+ return avr_asm_len ("ldi %3,1<<6" CR_TAB
+ "mul %3,%A1" CR_TAB
+ "mov %D0,r0" CR_TAB
+ "clr __zero_reg__" CR_TAB
+ "clr %C0" CR_TAB
+ "clr %B0" CR_TAB
+ "clr %A0", operands, plen, 7);
+ // Fallthrough
+
+ case 28:
+ case 29:
+ {
+ const bool ld_reg0_p = avr_ld_regno_p (reg0 + 3); // %D0
+ const bool ld_reg1_p = avr_ld_regno_p (reg1 + 0); // %A1
+ if (ld_reg0_p
+ || (ld_reg1_p && reg1_unused_after)
+ || scratch_p)
+ {
+ if (ld_reg0_p)
+ avr_asm_len ("mov %D0,%A1" CR_TAB
+ "swap %D0" CR_TAB
+ "andi %D0,0xf0", operands, plen, 3);
+ else if (ld_reg1_p && reg1_unused_after)
+ avr_asm_len ("swap %A1" CR_TAB
+ "andi %A1,0xf0" CR_TAB
+ "mov %D0,%A1", operands, plen, 3);
+ else
+ avr_asm_len ("mov %D0,%A1" CR_TAB
+ "swap %D0" CR_TAB
+ "ldi %3,0xf0" CR_TAB
+ "and %D0,%3", operands, plen, 4);
+ for (int i = 28; i < off; ++i)
+ avr_asm_len ("lsl %D0", operands, plen, 1);
+ return avr_asm_len ("clr %C0" CR_TAB
+ "clr %B0" CR_TAB
+ "clr %A0", operands, plen, 3);
+ }
+ }
+ // Fallthrough
+
case 24:
- return avr_asm_len ("mov %D0,%A1" CR_TAB
- "clr %C0" CR_TAB
+ case 25:
+ case 26:
+ case 27:
+ avr_asm_len ("mov %D0,%A1", operands, plen, 1);
+ for (int i = 24; i < off; ++i)
+ avr_asm_len ("lsl %D0", operands, plen, 1);
+ return avr_asm_len ("clr %C0" CR_TAB
"clr %B0" CR_TAB
- "clr %A0", operands, plen, 4);
+ "clr %A0", operands, plen, 3);
case 31:
return AVR_HAVE_MOVW
? avr_asm_len ("bst %A1,0" CR_TAB
{
if (CONST_INT_P (operands[2]))
{
+ int off = INTVAL (operands[2]);
int reg0 = true_regnum (operands[0]);
int reg1 = true_regnum (operands[1]);
bool reg1_unused_after = reg_unused_after (insn, operands[1]);
-
+ bool scratch_p = (GET_CODE (PATTERN (insn)) == PARALLEL
+ && XVECLEN (PATTERN (insn), 0) == 3
+ && REG_P (operands[3]));
if (plen)
*plen = 0;
- switch (INTVAL (operands[2]))
+ switch (off)
{
default:
- if (INTVAL (operands[2]) < 32)
+ if (off < 32)
break;
return AVR_HAVE_MOVW
"mov %A0,%C1" CR_TAB
"clr %C0" CR_TAB
"clr %D0", operands, plen, 4);
+ case 30:
+ if (AVR_HAVE_MUL && scratch_p)
+ return avr_asm_len ("ldi %3,1<<2" CR_TAB
+ "mul %3,%D1" CR_TAB
+ "mov %A0,r1" CR_TAB
+ "clr __zero_reg__" CR_TAB
+ "clr %B0" CR_TAB
+ "clr %C0" CR_TAB
+ "clr %D0", operands, plen, 7);
+ // Fallthrough
+
+ case 29:
+ case 28:
+ {
+ const bool ld_reg0_p = avr_ld_regno_p (reg0 + 0); // %A0
+ const bool ld_reg1_p = avr_ld_regno_p (reg1 + 3); // %D1
+ if (ld_reg0_p
+ || (ld_reg1_p && reg1_unused_after)
+ || scratch_p)
+ {
+ if (ld_reg0_p)
+ avr_asm_len ("mov %A0,%D1" CR_TAB
+ "swap %A0" CR_TAB
+ "andi %A0,0x0f", operands, plen, 3);
+ else if (ld_reg1_p && reg1_unused_after)
+ avr_asm_len ("swap %D1" CR_TAB
+ "andi %D1,0x0f" CR_TAB
+ "mov %A0,%D1", operands, plen, 3);
+ else
+ avr_asm_len ("mov %A0,%D1" CR_TAB
+ "swap %A0" CR_TAB
+ "ldi %3,0x0f" CR_TAB
+ "and %A0,%3", operands, plen, 4);
+ for (int i = 28; i < off; ++i)
+ avr_asm_len ("lsr %A0", operands, plen, 1);
+ return avr_asm_len ("clr %B0" CR_TAB
+ "clr %C0" CR_TAB
+ "clr %D0", operands, plen, 3);
+ }
+ }
+ // Fallthrough
+
+ case 27:
+ case 26:
+ case 25:
case 24:
- return avr_asm_len ("mov %A0,%D1" CR_TAB
- "clr %B0" CR_TAB
+ avr_asm_len ("mov %A0,%D1", operands, plen, 1);
+ for (int i = 24; i < off; ++i)
+ avr_asm_len ("lsr %A0", operands, plen, 1);
+ return avr_asm_len ("clr %B0" CR_TAB
"clr %C0" CR_TAB
- "clr %D0", operands, plen, 4);
+ "clr %D0", operands, plen, 3);
case 31:
return AVR_HAVE_MOVW
? avr_asm_len ("bst %D1,7" CR_TAB
case 0:
*total = 0;
break;
- case 24:
- *total = COSTS_N_INSNS (3);
- break;
case 1:
case 8:
*total = COSTS_N_INSNS (4);
case 16:
*total = COSTS_N_INSNS (4 - AVR_HAVE_MOVW);
break;
+ case 24:
+ case 25:
+ case 26:
+ case 27:
+ *total = COSTS_N_INSNS (4 + val1 - 24);
+ break;
+ case 28:
+ case 29:
+ *total = COSTS_N_INSNS (6 + val1 - 28);
+ break;
+ case 30:
+ *total = COSTS_N_INSNS (!speed && AVR_HAVE_MUL ? 7 : 8);
+ break;
case 31:
*total = COSTS_N_INSNS (6);
break;
*total = 0;
break;
case 1:
+ case 8:
*total = COSTS_N_INSNS (4);
break;
case 2:
case 16:
*total = COSTS_N_INSNS (4 - AVR_HAVE_MOVW);
break;
- case 8:
case 24:
- *total = COSTS_N_INSNS (4);
+ case 25:
+ case 26:
+ case 27:
+ *total = COSTS_N_INSNS (4 + val1 - 24);
+ break;
+ case 28:
+ case 29:
+ *total = COSTS_N_INSNS (6 + val1 - 28);
+ break;
+ case 30:
+ *total = COSTS_N_INSNS (!speed && AVR_HAVE_MUL ? 7 : 8);
break;
case 31:
*total = COSTS_N_INSNS (6);
;; "ashlsq3" "ashlusq3"
;; "ashlsa3" "ashlusa3"
(define_insn_and_split "ashl<mode>3"
- [(set (match_operand:ALL4 0 "register_operand" "=r,r ,r ,r ,r,r")
- (ashift:ALL4 (match_operand:ALL4 1 "register_operand" "0,0 ,r ,r ,0,0")
- (match_operand:QI 2 "nop_general_operand" "r,LPK,O C15 C31,C4l,n,Qm")))]
+ [(set (match_operand:ALL4 0 "register_operand" "=r,r ,r ,r ,r,r")
+ (ashift:ALL4 (match_operand:ALL4 1 "register_operand" "0,0 ,r ,r ,0,0")
+ (match_operand:QI 2 "nop_general_operand" "r,LPK,O C4L,C4l,n,Qm")))]
""
"#"
"&& reload_completed"
[(set_attr "isa" "*,*,*,3op,*,*")])
(define_insn "*ashl<mode>3"
- [(set (match_operand:ALL4 0 "register_operand" "=r,r ,r ,r ,r,r")
- (ashift:ALL4 (match_operand:ALL4 1 "register_operand" "0,0 ,r ,r ,0,0")
- (match_operand:QI 2 "nop_general_operand" "r,LPK,O C15 C31,C4l,n,Qm")))
+ [(set (match_operand:ALL4 0 "register_operand" "=r,r ,r ,r ,r,r")
+ (ashift:ALL4 (match_operand:ALL4 1 "register_operand" "0,0 ,r ,r ,0,0")
+ (match_operand:QI 2 "nop_general_operand" "r,LPK,O C4L,C4l,n,Qm")))
(clobber (reg:CC REG_CC))]
"reload_completed"
{
;; "*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")
- (ashift:ALL4 (match_operand:ALL4 1 "register_operand" "0 ,r ,r ,0")
- (match_operand:QI 2 "const_int_operand" "LP,O C15 C31,C4l,n")))
- (clobber (match_operand:QI 3 "scratch_or_dreg_operand" "=X ,X ,&d ,&d"))
+ [(set (match_operand:ALL4 0 "register_operand" "=r ,r ,r ,r")
+ (ashift:ALL4 (match_operand:ALL4 1 "register_operand" "0 ,r ,r ,0")
+ (match_operand:QI 2 "const_int_operand" "LP,O C4L,C4l,n")))
+ (clobber (match_operand:QI 3 "scratch_or_dreg_operand" "=X ,X ,&d ,&d"))
(clobber (reg:CC REG_CC))]
"reload_completed"
{
;; "lshrsq3" "lshrusq3"
;; "lshrsa3" "lshrusa3"
(define_insn_and_split "lshr<mode>3"
- [(set (match_operand:ALL4 0 "register_operand" "=r,r ,r ,r ,r,r")
- (lshiftrt:ALL4 (match_operand:ALL4 1 "register_operand" "0,0 ,r ,r ,0,0")
- (match_operand:QI 2 "nop_general_operand" "r,LPK,O C15 C31,C4r,n,Qm")))]
+ [(set (match_operand:ALL4 0 "register_operand" "=r,r ,r ,r ,r,r")
+ (lshiftrt:ALL4 (match_operand:ALL4 1 "register_operand" "0,0 ,r ,r ,0,0")
+ (match_operand:QI 2 "nop_general_operand" "r,LPK,O C4R,C4r,n,Qm")))]
""
"#"
"&& reload_completed"
[(set_attr "isa" "*,*,*,3op,*,*")])
(define_insn "*lshr<mode>3"
- [(set (match_operand:ALL4 0 "register_operand" "=r,r ,r ,r ,r,r")
- (lshiftrt:ALL4 (match_operand:ALL4 1 "register_operand" "0,0 ,r ,r ,0,0")
- (match_operand:QI 2 "nop_general_operand" "r,LPK,O C15 C31,C4r,n,Qm")))
+ [(set (match_operand:ALL4 0 "register_operand" "=r,r ,r ,r ,r,r")
+ (lshiftrt:ALL4 (match_operand:ALL4 1 "register_operand" "0,0 ,r ,r ,0,0")
+ (match_operand:QI 2 "nop_general_operand" "r,LPK,O C4R,C4r,n,Qm")))
(clobber (reg:CC REG_CC))]
"reload_completed"
{
;; "*lshrsq3_const" "*lshrusq3_const"
;; "*lshrsa3_const" "*lshrusa3_const"
(define_insn "*lshr<mode>3_const"
- [(set (match_operand:ALL4 0 "register_operand" "=r ,r ,r ,r")
- (lshiftrt:ALL4 (match_operand:ALL4 1 "register_operand" "0 ,r ,r ,0")
- (match_operand:QI 2 "const_int_operand" "LP,O C15 C31,C4r,n")))
- (clobber (match_operand:QI 3 "scratch_or_dreg_operand" "=X ,X ,&d ,&d"))
+ [(set (match_operand:ALL4 0 "register_operand" "=r ,r ,r ,r")
+ (lshiftrt:ALL4 (match_operand:ALL4 1 "register_operand" "0 ,r ,r ,0")
+ (match_operand:QI 2 "const_int_operand" "LP,O C4R,C4r,n")))
+ (clobber (match_operand:QI 3 "scratch_or_dreg_operand" "=X ,X ,&d ,&d"))
(clobber (reg:CC REG_CC))]
"reload_completed"
{
(and (match_code "const_int")
(match_test "avr_split_shift_p (4, ival, ASHIFT)")))
+(define_constraint "C4R"
+ "A constant integer shift offset for a 4-byte LSHIFTRT that's a 3-operand insn independent of options."
+ (and (match_code "const_int")
+ (match_test "ival == 15 || IN_RANGE (ival, 25, 31)")))
+
+(define_constraint "C4L"
+ "A constant integer shift offset for a 4-byte ASHIFT that's a 3-operand insn independent of options."
+ (and (match_code "const_int")
+ (match_test "ival == 15 || IN_RANGE (ival, 25, 31)")))
;; CONST_FIXED is no element of 'n' so cook our own.
;; "i" or "s" would match but because the insn uses iterators that cover
{ -Os -fomit-frame-pointer } \
{ -Os -fomit-frame-pointer -finline-functions } \
{ -O3 -g } \
- { -Os -mcall-prologues} ]
+ { -Oz -mcall-prologues} ]
#Initialize use of torture lists.