}
-int avr_optimize_size_level ()
+int
+avr_optimize_size_level ()
{
return cfun && cfun->decl
? opt_for_fn (cfun->decl, optimize_size)
}
+static bool
+avr_optimize_size_max_p ()
+{
+ return avr_optimize_size_level () == OPTIMIZE_SIZE_MAX;
+}
+
+
/* Implement `INIT_EXPANDERS'. */
/* The function works like a singleton. */
}
+/* Output a 16-bit left shift XOP[0] = XOP[1] << XOP[2] using MUL.
+ XOP[3] is an upper 8-bit scratch register. This function is currently
+ only used for offsets 5 and 6 but works for offsets 1...7 as well. */
+
+static const char*
+avr_out_ashlhi3_mul (rtx *xop, bool scratch_p, int *plen)
+{
+ gcc_assert (scratch_p && AVR_HAVE_MUL);
+
+ // Takes 7 words and 9 cycles.
+ return avr_asm_len ("ldi %3,1<<%2" CR_TAB
+ "mul %B1,%3" CR_TAB
+ "mov %B0,r0" CR_TAB
+ "mul %A1,%3" CR_TAB
+ "mov %A0,r0" CR_TAB
+ "or %B0,r1" CR_TAB
+ "clr __zero_reg__", xop, plen, -7);
+}
+
+
/* 16bit shift left ((short)x << i) */
const char *
&& 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]);
+ int size;
+ int reg0 = REGNO (operands[0]);
+ int reg1 = REGNO (operands[1]);
+ bool use_mul_p = reg1 != reg0 || (scratch && AVR_HAVE_MUL);
if (plen)
*plen = 0;
return avr_asm_len ("clr %B0" CR_TAB
"clr %A0", operands, plen, 2);
case 4:
- if (optimize_size && scratch)
+ if (avr_optimize_size_max_p () && scratch)
break; /* 5 */
if (ldi_ok)
return avr_asm_len ("swap %A0" CR_TAB
break; /* optimize_size ? 6 : 8 */
case 5:
+ size = (scratch ? 5 : 6) + (reg1 != reg0) * (2 - AVR_HAVE_MOVW);
+ if (avr_optimize_size_max_p () && (size < 7 || !use_mul_p))
+ {
+ if (reg0 != reg1)
+ {
+ if (AVR_HAVE_MOVW)
+ avr_asm_len ("movw %0,%1", operands, plen, 1);
+ else
+ avr_asm_len ("mov %A0,%A1" CR_TAB
+ "mov %B0,%B1", operands, plen, 2);
+ }
+ break; // scratch ? 5 : 6
+ }
+
+ if (use_mul_p)
+ return avr_out_ashlhi3_mul (operands, scratch, plen); // 7
+
if (optimize_size)
break; /* scratch ? 5 : 6 */
if (ldi_ok)
break; /* 10 */
case 6:
+ size = (scratch ? 5 : 6) + (reg1 != reg0) * (2 - AVR_HAVE_MOVW);
+ if (avr_optimize_size_max_p () && (size < 7 || !use_mul_p))
+ {
+ if (reg0 != reg1)
+ {
+ if (AVR_HAVE_MOVW)
+ avr_asm_len ("movw %0,%1", operands, plen, 1);
+ else
+ avr_asm_len ("mov %A0,%A1" CR_TAB
+ "mov %B0,%B1", operands, plen, 2);
+ }
+ break; // scratch ? 5 : 6
+ }
+
+ if (use_mul_p)
+ return avr_out_ashlhi3_mul (operands, scratch, plen); // 7
+
if (optimize_size)
break; /* scratch ? 5 : 6 */
return avr_asm_len ("clr __tmp_reg__" CR_TAB
}
out_shift_with_cnt ("lsl %A0" CR_TAB
- "rol %B0", insn, operands, plen, 2);
+ "rol %B0", insn, operands, plen, 2);
return "";
}
;; elpm : ISA has ELPM but no ELPMX elpmx : ISA has ELPMX
;; no_xmega: non-XMEGA core xmega : XMEGA core
;; no_adiw: ISA has no ADIW, SBIW adiw : ISA has ADIW, SBIW
+;; no_mul: ISA has no MUL mul : ISA has [F]MUL[S[U]]
;; The following ISA attributes are actually not architecture specific,
;; but depend on (optimization) options. This is because the "enabled"
(define_attr "isa"
"mov,movw, rjmp,jmp, ijmp,eijmp, lpm,lpmx, elpm,elpmx, no_xmega,xmega,
- no_adiw,adiw,
+ no_adiw,adiw, no_mul,mul,
3op,
standard"
(const_string "standard"))
(and (eq_attr "isa" "no_adiw")
(match_test "!AVR_HAVE_ADIW"))
+ (and (eq_attr "isa" "mul")
+ (match_test "AVR_HAVE_MUL"))
+
+ (and (eq_attr "isa" "no_mul")
+ (match_test "!AVR_HAVE_MUL"))
+
(and (eq_attr "isa" "3op")
(match_test "avr_shift_is_3op ()"))
)
;; "*ashlhq3_const" "*ashluhq3_const"
;; "*ashlha3_const" "*ashluha3_const"
(define_insn "*ashl<mode>3_const"
- [(set (match_operand:ALL2 0 "register_operand" "=r ,r ,r ,r")
- (ashift:ALL2 (match_operand:ALL2 1 "register_operand" "0 ,r ,r ,0")
- (match_operand:QI 2 "const_int_operand" "LPK,O C7c C15,C2l,n")))
- (clobber (match_scratch:QI 3 "=X ,X ,&d ,&d"))
+ [(set (match_operand:ALL2 0 "register_operand" "=r ,r ,r ,r ,r")
+ (ashift:ALL2 (match_operand:ALL2 1 "register_operand" "0 ,r ,r ,r ,0")
+ (match_operand:QI 2 "const_int_operand" "LPK,O C7c C15,C05 C06,C2l,n")))
+ (clobber (match_scratch:QI 3 "=X ,X ,&d ,&d ,&d"))
(clobber (reg:CC REG_CC))]
"reload_completed"
{
return ashlhi3_out (insn, operands, NULL);
}
- [(set_attr "isa" "*,*,3op,*")
+ [(set_attr "isa" "*,*,mul,3op,*")
(set_attr "length" "10")
(set_attr "adjust_len" "ashlhi")])