avr-protos.h (output_reload_inhi): Change prototype.
* config/avr/avr-protos.h (output_reload_inhi): Change prototype. * config/avr/avr.md (adjust_len): Add "reload_in16" alternative. (*reload_inhi): Use it. Adapt call to output_reload_inhi to new prototype. (*movhi): Split constraint alternative "r,rL" into "r,r" and "r,L". * config/avr/avr.c: Rename output_reload_insisf_1 to output_reload_in_const. (avr_popcount_each_byte): Handle SFmode, too. (output_reload_in_const): Change so it can handle HI loads, too. Use avr_popcount_each_byte to work out if scratch register must be created on the fly. (output_reload_inhi): Rewrite using output_reload_in_const and... (output_movhi): ...use it to print constants' loads. (adjust_insn_length): New case ADJUST_LEN_RELOAD_IN16. Cleanup code. From-SVN: r179181
This commit is contained in:
parent
50179d5882
commit
20633efc34
|
@ -1,3 +1,20 @@
|
|||
2011-09-26 Georg-Johann Lay <avr@gjlay.de>
|
||||
|
||||
* config/avr/avr-protos.h (output_reload_inhi): Change prototype.
|
||||
* config/avr/avr.md (adjust_len): Add "reload_in16" alternative.
|
||||
(*reload_inhi): Use it. Adapt call to output_reload_inhi to new
|
||||
prototype.
|
||||
(*movhi): Split constraint alternative "r,rL" into "r,r" and "r,L".
|
||||
* config/avr/avr.c: Rename output_reload_insisf_1 to
|
||||
output_reload_in_const.
|
||||
(avr_popcount_each_byte): Handle SFmode, too.
|
||||
(output_reload_in_const): Change so it can handle HI loads, too.
|
||||
Use avr_popcount_each_byte to work out if scratch register must be
|
||||
created on the fly.
|
||||
(output_reload_inhi): Rewrite using output_reload_in_const and...
|
||||
(output_movhi): ...use it to print constants' loads.
|
||||
(adjust_insn_length): New case ADJUST_LEN_RELOAD_IN16. Cleanup code.
|
||||
|
||||
2011-09-25 David S. Miller <davem@davemloft.net>
|
||||
|
||||
* config/sparc/constraints.md (C, P, Z): New constraints for
|
||||
|
|
|
@ -87,7 +87,7 @@ extern bool avr_popcount_each_byte (rtx, int, int);
|
|||
|
||||
extern int extra_constraint_Q (rtx x);
|
||||
extern int adjust_insn_length (rtx insn, int len);
|
||||
extern const char *output_reload_inhi (rtx insn, rtx *operands, int *len);
|
||||
extern const char* output_reload_inhi (rtx*, rtx, int*);
|
||||
extern const char *output_reload_insisf (rtx insn, rtx *operands, rtx clobber, int *len);
|
||||
extern void notice_update_cc (rtx body, rtx insn);
|
||||
extern void print_operand (FILE *file, rtx x, int code);
|
||||
|
|
|
@ -319,19 +319,24 @@ avr_popcount (unsigned int val)
|
|||
}
|
||||
|
||||
|
||||
/* Constraint helper function. XVAL is an CONST_INT. Return true if the least
|
||||
significant N_BYTES bytes of XVAL all have a popcount in POP_MASK and false,
|
||||
otherwise. POP_MASK represents a subset of integers which contains an
|
||||
integer N iff bit N of POP_MASK is set. */
|
||||
/* Constraint helper function. XVAL is a CONST_INT or a CONST_DOUBLE.
|
||||
Return true if the least significant N_BYTES bytes of XVAL all have a
|
||||
popcount in POP_MASK and false, otherwise. POP_MASK represents a subset
|
||||
of integers which contains an integer N iff bit N of POP_MASK is set. */
|
||||
|
||||
bool
|
||||
avr_popcount_each_byte (rtx xval, int n_bytes, int pop_mask)
|
||||
{
|
||||
int i;
|
||||
|
||||
enum machine_mode mode = GET_MODE (xval);
|
||||
|
||||
if (VOIDmode == mode)
|
||||
mode = SImode;
|
||||
|
||||
for (i = 0; i < n_bytes; i++)
|
||||
{
|
||||
rtx xval8 = simplify_gen_subreg (QImode, xval, SImode, i);
|
||||
rtx xval8 = simplify_gen_subreg (QImode, xval, mode, i);
|
||||
unsigned int val8 = UINTVAL (xval8) & GET_MODE_MASK (QImode);
|
||||
|
||||
if (0 == (pop_mask & (1 << avr_popcount (val8))))
|
||||
|
@ -2077,84 +2082,9 @@ output_movhi (rtx insn, rtx operands[], int *l)
|
|||
}
|
||||
}
|
||||
else if (CONSTANT_P (src))
|
||||
{
|
||||
if (test_hard_reg_class (LD_REGS, dest)) /* ldi d,i */
|
||||
{
|
||||
*l = 2;
|
||||
return (AS2 (ldi,%A0,lo8(%1)) CR_TAB
|
||||
AS2 (ldi,%B0,hi8(%1)));
|
||||
}
|
||||
|
||||
if (GET_CODE (src) == CONST_INT)
|
||||
{
|
||||
if (src == const0_rtx) /* mov r,L */
|
||||
{
|
||||
*l = 2;
|
||||
return (AS1 (clr,%A0) CR_TAB
|
||||
AS1 (clr,%B0));
|
||||
}
|
||||
else if (src == const1_rtx)
|
||||
{
|
||||
*l = 3;
|
||||
return (AS1 (clr,%A0) CR_TAB
|
||||
AS1 (clr,%B0) CR_TAB
|
||||
AS1 (inc,%A0));
|
||||
}
|
||||
else if (src == constm1_rtx)
|
||||
{
|
||||
/* Immediate constants -1 to any register */
|
||||
*l = 3;
|
||||
return (AS1 (clr,%0) CR_TAB
|
||||
AS1 (dec,%A0) CR_TAB
|
||||
AS2 (mov,%B0,%A0));
|
||||
}
|
||||
else
|
||||
{
|
||||
int bit_nr = exact_log2 (INTVAL (src));
|
||||
|
||||
if (bit_nr >= 0)
|
||||
{
|
||||
*l = 4;
|
||||
if (!real_l)
|
||||
output_asm_insn ((AS1 (clr,%A0) CR_TAB
|
||||
AS1 (clr,%B0) CR_TAB
|
||||
"set"), operands);
|
||||
if (!real_l)
|
||||
avr_output_bld (operands, bit_nr);
|
||||
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
if ((INTVAL (src) & 0xff) == 0)
|
||||
{
|
||||
*l = 5;
|
||||
return (AS2 (mov,__tmp_reg__,r31) CR_TAB
|
||||
AS1 (clr,%A0) CR_TAB
|
||||
AS2 (ldi,r31,hi8(%1)) CR_TAB
|
||||
AS2 (mov,%B0,r31) CR_TAB
|
||||
AS2 (mov,r31,__tmp_reg__));
|
||||
}
|
||||
else if ((INTVAL (src) & 0xff00) == 0)
|
||||
{
|
||||
*l = 5;
|
||||
return (AS2 (mov,__tmp_reg__,r31) CR_TAB
|
||||
AS2 (ldi,r31,lo8(%1)) CR_TAB
|
||||
AS2 (mov,%A0,r31) CR_TAB
|
||||
AS1 (clr,%B0) CR_TAB
|
||||
AS2 (mov,r31,__tmp_reg__));
|
||||
}
|
||||
}
|
||||
|
||||
/* Last resort, equal to loading from memory. */
|
||||
*l = 6;
|
||||
return (AS2 (mov,__tmp_reg__,r31) CR_TAB
|
||||
AS2 (ldi,r31,lo8(%1)) CR_TAB
|
||||
AS2 (mov,%A0,r31) CR_TAB
|
||||
AS2 (ldi,r31,hi8(%1)) CR_TAB
|
||||
AS2 (mov,%B0,r31) CR_TAB
|
||||
AS2 (mov,r31,__tmp_reg__));
|
||||
}
|
||||
{
|
||||
return output_reload_inhi (operands, NULL, real_l);
|
||||
}
|
||||
else if (GET_CODE (src) == MEM)
|
||||
return out_movhi_r_mr (insn, operands, real_l); /* mov r,m */
|
||||
}
|
||||
|
@ -5125,6 +5055,10 @@ adjust_insn_length (rtx insn, int len)
|
|||
|
||||
switch (adjust_len)
|
||||
{
|
||||
case ADJUST_LEN_RELOAD_IN16:
|
||||
output_reload_inhi (op, op[2], &len);
|
||||
break;
|
||||
|
||||
case ADJUST_LEN_RELOAD_IN32:
|
||||
output_reload_insisf (insn, op, op[2], &len);
|
||||
break;
|
||||
|
@ -5185,31 +5119,7 @@ adjust_insn_length (rtx insn, int len)
|
|||
op[1] = SET_SRC (set);
|
||||
op[0] = SET_DEST (set);
|
||||
|
||||
if (GET_CODE (patt) == PARALLEL
|
||||
&& general_operand (op[1], VOIDmode)
|
||||
&& general_operand (op[0], VOIDmode))
|
||||
{
|
||||
if (XVECLEN (patt, 0) == 2)
|
||||
op[2] = XVECEXP (patt, 0, 1);
|
||||
|
||||
switch (GET_MODE (op[0]))
|
||||
{
|
||||
case QImode:
|
||||
len = 2;
|
||||
break;
|
||||
case HImode:
|
||||
output_reload_inhi (insn, op, &len);
|
||||
break;
|
||||
case SImode:
|
||||
case SFmode:
|
||||
/* Handled by ADJUST_LEN_RELOAD_INSISF above. */
|
||||
gcc_unreachable();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (GET_CODE (op[1]) == ASHIFT
|
||||
if (GET_CODE (op[1]) == ASHIFT
|
||||
|| GET_CODE (op[1]) == ASHIFTRT
|
||||
|| GET_CODE (op[1]) == LSHIFTRT)
|
||||
{
|
||||
|
@ -7153,45 +7063,6 @@ avr_hard_regno_mode_ok (int regno, enum machine_mode mode)
|
|||
return !(regno & 1);
|
||||
}
|
||||
|
||||
const char *
|
||||
output_reload_inhi (rtx insn ATTRIBUTE_UNUSED, rtx *operands, int *len)
|
||||
{
|
||||
int tmp;
|
||||
if (!len)
|
||||
len = &tmp;
|
||||
|
||||
if (GET_CODE (operands[1]) == CONST_INT)
|
||||
{
|
||||
int val = INTVAL (operands[1]);
|
||||
if ((val & 0xff) == 0)
|
||||
{
|
||||
*len = 3;
|
||||
return (AS2 (mov,%A0,__zero_reg__) CR_TAB
|
||||
AS2 (ldi,%2,hi8(%1)) CR_TAB
|
||||
AS2 (mov,%B0,%2));
|
||||
}
|
||||
else if ((val & 0xff00) == 0)
|
||||
{
|
||||
*len = 3;
|
||||
return (AS2 (ldi,%2,lo8(%1)) CR_TAB
|
||||
AS2 (mov,%A0,%2) CR_TAB
|
||||
AS2 (mov,%B0,__zero_reg__));
|
||||
}
|
||||
else if ((val & 0xff) == ((val & 0xff00) >> 8))
|
||||
{
|
||||
*len = 3;
|
||||
return (AS2 (ldi,%2,lo8(%1)) CR_TAB
|
||||
AS2 (mov,%A0,%2) CR_TAB
|
||||
AS2 (mov,%B0,%2));
|
||||
}
|
||||
}
|
||||
*len = 4;
|
||||
return (AS2 (ldi,%2,lo8(%1)) CR_TAB
|
||||
AS2 (mov,%A0,%2) CR_TAB
|
||||
AS2 (ldi,%2,hi8(%1)) CR_TAB
|
||||
AS2 (mov,%B0,%2));
|
||||
}
|
||||
|
||||
|
||||
/* A helper for `output_reload_insisf'. */
|
||||
/* Set 32-bit register OP[0] to compile-time constant OP[1].
|
||||
|
@ -7203,7 +7074,7 @@ output_reload_inhi (rtx insn ATTRIBUTE_UNUSED, rtx *operands, int *len)
|
|||
If CLEAR_P is false, nothing is known about OP[0]. */
|
||||
|
||||
static void
|
||||
output_reload_insisf_1 (rtx *op, rtx clobber_reg, int *len, bool clear_p)
|
||||
output_reload_in_const (rtx *op, rtx clobber_reg, int *len, bool clear_p)
|
||||
{
|
||||
rtx src = op[1];
|
||||
rtx dest = op[0];
|
||||
|
@ -7223,7 +7094,8 @@ output_reload_insisf_1 (rtx *op, rtx clobber_reg, int *len, bool clear_p)
|
|||
/* (REG:SI 14) is special: It's neither in LD_REGS nor in NO_LD_REGS
|
||||
but has some subregs that are in LD_REGS. Use the MSB (REG:QI 17). */
|
||||
|
||||
if (14 == REGNO (dest))
|
||||
if (14 == REGNO (dest)
|
||||
&& 4 == GET_MODE_SIZE (mode))
|
||||
{
|
||||
clobber_reg = gen_rtx_REG (QImode, 17);
|
||||
}
|
||||
|
@ -7233,25 +7105,16 @@ output_reload_insisf_1 (rtx *op, rtx clobber_reg, int *len, bool clear_p)
|
|||
a byte that is neither 0, -1 or a power of 2. */
|
||||
|
||||
if (NULL_RTX == clobber_reg
|
||||
&& !test_hard_reg_class (LD_REGS, dest))
|
||||
&& !test_hard_reg_class (LD_REGS, dest)
|
||||
&& !avr_popcount_each_byte (src, GET_MODE_SIZE (mode),
|
||||
(1 << 0) | (1 << 1) | (1 << 8)))
|
||||
{
|
||||
for (n = 0; n < GET_MODE_SIZE (mode); n++)
|
||||
{
|
||||
xval = simplify_gen_subreg (QImode, src, mode, n);
|
||||
|
||||
if (!(const0_rtx == xval
|
||||
|| constm1_rtx == xval
|
||||
|| single_one_operand (xval, QImode)))
|
||||
{
|
||||
/* We have no clobber reg but need one. Cook one up.
|
||||
That's cheaper than loading from constant pool. */
|
||||
|
||||
cooked_clobber_p = true;
|
||||
clobber_reg = gen_rtx_REG (QImode, REG_Z + 1);
|
||||
avr_asm_len ("mov __tmp_reg__,%0", &clobber_reg, len, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* We have no clobber register but need one. Cook one up.
|
||||
That's cheaper than loading from constant pool. */
|
||||
|
||||
cooked_clobber_p = true;
|
||||
clobber_reg = gen_rtx_REG (QImode, REG_Z + 1);
|
||||
avr_asm_len ("mov __tmp_reg__,%0", &clobber_reg, len, 1);
|
||||
}
|
||||
|
||||
/* Now start filling DEST from LSB to MSB. */
|
||||
|
@ -7396,6 +7259,63 @@ output_reload_insisf_1 (rtx *op, rtx clobber_reg, int *len, bool clear_p)
|
|||
}
|
||||
|
||||
|
||||
/* Reload the constant OP[1] into the HI register OP[0].
|
||||
CLOBBER_REG is a QI clobber reg needed to move vast majority of consts
|
||||
into a NO_LD_REGS register. If CLOBBER_REG is NULL_RTX we either don't
|
||||
need a clobber reg or have to cook one up.
|
||||
|
||||
PLEN == NULL: Output instructions.
|
||||
PLEN != NULL: Output nothing. Set *PLEN to number of words occupied
|
||||
by the insns printed.
|
||||
|
||||
Return "". */
|
||||
|
||||
const char*
|
||||
output_reload_inhi (rtx *op, rtx clobber_reg, int *plen)
|
||||
{
|
||||
if (CONST_INT_P (op[1]))
|
||||
{
|
||||
output_reload_in_const (op, clobber_reg, plen, false);
|
||||
}
|
||||
else if (test_hard_reg_class (LD_REGS, op[0]))
|
||||
{
|
||||
avr_asm_len ("ldi %A0,lo8(%1)" CR_TAB
|
||||
"ldi %B0,hi8(%1)", op, plen, -2);
|
||||
}
|
||||
else
|
||||
{
|
||||
rtx xop[3];
|
||||
|
||||
xop[0] = op[0];
|
||||
xop[1] = op[1];
|
||||
xop[2] = clobber_reg;
|
||||
|
||||
if (plen)
|
||||
*plen = 0;
|
||||
|
||||
if (clobber_reg == NULL_RTX)
|
||||
{
|
||||
/* No scratch register provided: cook une up. */
|
||||
|
||||
xop[2] = gen_rtx_REG (QImode, REG_Z + 1);
|
||||
avr_asm_len ("mov __tmp_reg__,%2", xop, plen, 1);
|
||||
}
|
||||
|
||||
avr_asm_len ("ldi %2,lo8(%1)" CR_TAB
|
||||
"mov %A0,%2" CR_TAB
|
||||
"ldi %2,hi8(%1)" CR_TAB
|
||||
"mov %B0,%2", xop, plen, 4);
|
||||
|
||||
if (clobber_reg == NULL_RTX)
|
||||
{
|
||||
avr_asm_len ("mov %2,__tmp_reg__", xop, plen, 1);
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
/* Reload a SI or SF compile time constant OP[1] into the register OP[0].
|
||||
CLOBBER_REG is a QI clobber reg needed to move vast majority of consts
|
||||
into a NO_LD_REGS register. If CLOBBER_REG is NULL_RTX we either don't
|
||||
|
@ -7432,8 +7352,8 @@ output_reload_insisf (rtx insn ATTRIBUTE_UNUSED,
|
|||
Instead, we call the print function twice to get the lengths of
|
||||
both methods and use the shortest one. */
|
||||
|
||||
output_reload_insisf_1 (op, clobber_reg, &len_clr, true);
|
||||
output_reload_insisf_1 (op, clobber_reg, &len_noclr, false);
|
||||
output_reload_in_const (op, clobber_reg, &len_clr, true);
|
||||
output_reload_in_const (op, clobber_reg, &len_noclr, false);
|
||||
|
||||
if (len_noclr - len_clr == 4)
|
||||
{
|
||||
|
@ -7443,7 +7363,7 @@ output_reload_insisf (rtx insn ATTRIBUTE_UNUSED,
|
|||
"clr %B0" CR_TAB
|
||||
"movw %C0,%A0", &op[0], len, 3);
|
||||
|
||||
output_reload_insisf_1 (op, clobber_reg, len, true);
|
||||
output_reload_in_const (op, clobber_reg, len, true);
|
||||
|
||||
if (len)
|
||||
*len += 3;
|
||||
|
@ -7454,7 +7374,7 @@ output_reload_insisf (rtx insn ATTRIBUTE_UNUSED,
|
|||
|
||||
/* Default: destination not pre-cleared. */
|
||||
|
||||
output_reload_insisf_1 (op, clobber_reg, len, false);
|
||||
output_reload_in_const (op, clobber_reg, len, false);
|
||||
return "";
|
||||
}
|
||||
|
||||
|
|
|
@ -136,7 +136,7 @@
|
|||
;; Otherwise do special processing depending on the attribute.
|
||||
|
||||
(define_attr "adjust_len"
|
||||
"yes,no,reload_in32,out_bitop,out_plus,tsthi,tstsi,compare"
|
||||
"yes,no,reload_in16,reload_in32,out_bitop,out_plus,tsthi,tstsi,compare"
|
||||
(const_string "yes"))
|
||||
|
||||
;; Define mode iterators
|
||||
|
@ -387,18 +387,21 @@
|
|||
(match_operand:HI 1 "immediate_operand" "i"))
|
||||
(clobber (match_operand:QI 2 "register_operand" "=&d"))]
|
||||
"reload_completed"
|
||||
"* return output_reload_inhi (insn, operands, NULL);"
|
||||
{
|
||||
return output_reload_inhi (operands, operands[2], NULL);
|
||||
}
|
||||
[(set_attr "length" "4")
|
||||
(set_attr "adjust_len" "reload_in16")
|
||||
(set_attr "cc" "none")])
|
||||
|
||||
(define_insn "*movhi"
|
||||
[(set (match_operand:HI 0 "nonimmediate_operand" "=r,r,m,d,*r,q,r")
|
||||
(match_operand:HI 1 "general_operand" "rL,m,rL,i,i,r,q"))]
|
||||
[(set (match_operand:HI 0 "nonimmediate_operand" "=r,r,r,m,d,*r,q,r")
|
||||
(match_operand:HI 1 "general_operand" "r,L,m,rL,i,i,r,q"))]
|
||||
"(register_operand (operands[0],HImode)
|
||||
|| register_operand (operands[1],HImode) || const0_rtx == operands[1])"
|
||||
"* return output_movhi (insn, operands, NULL);"
|
||||
[(set_attr "length" "2,6,7,2,6,5,2")
|
||||
(set_attr "cc" "none,clobber,clobber,none,clobber,none,none")])
|
||||
[(set_attr "length" "2,2,6,7,2,6,5,2")
|
||||
(set_attr "cc" "none,clobber,clobber,clobber,none,clobber,none,none")])
|
||||
|
||||
(define_peephole2 ; movw
|
||||
[(set (match_operand:QI 0 "even_register_operand" "")
|
||||
|
|
Loading…
Reference in New Issue