re PR target/50447 ([avr] Better support of AND, OR, XOR and PLUS with constant integers for 16- and 32-bit values)
PR target/50447 * config/avr/avr.md (cc): Add out_plus attribute alternative. (addsi3): Use it. Adapt avr_out_plus to new prototype. Use avr_out_plus for all CONST_INT addends. * config/avr/avr-protos.h (avr_out_plus): Change prototype. * config/avr/avr.c (notice_update_cc): Call avr_out_plus on CC_OUT_PLUS. (avr_out_plus_1): Change prototype and report effect on cc0. (avr_out_plus): Ditto. (adjust_insn_length): Adapt call to avr_out_plus to new prototype. From-SVN: r179816
This commit is contained in:
parent
a4474a3854
commit
05058b6e31
@ -1,3 +1,16 @@
|
||||
2011-10-11 Georg-Johann Lay <avr@gjlay.de>
|
||||
|
||||
PR target/50447
|
||||
* config/avr/avr.md (cc): Add out_plus attribute alternative.
|
||||
(addsi3): Use it. Adapt avr_out_plus to new prototype. Use
|
||||
avr_out_plus for all CONST_INT addends.
|
||||
* config/avr/avr-protos.h (avr_out_plus): Change prototype.
|
||||
* config/avr/avr.c (notice_update_cc): Call avr_out_plus on
|
||||
CC_OUT_PLUS.
|
||||
(avr_out_plus_1): Change prototype and report effect on cc0.
|
||||
(avr_out_plus): Ditto.
|
||||
(adjust_insn_length): Adapt call to avr_out_plus to new prototype.
|
||||
|
||||
2011-10-11 H.J. Lu <hongjiu.lu@intel.com>
|
||||
|
||||
* config/i386/i386.c (ix86_expand_special_args_builtin): Remove
|
||||
|
@ -82,7 +82,7 @@ extern void avr_output_bld (rtx operands[], int bit_nr);
|
||||
extern void avr_output_addr_vec_elt (FILE *stream, int value);
|
||||
extern const char *avr_out_sbxx_branch (rtx insn, rtx operands[]);
|
||||
extern const char* avr_out_bitop (rtx, rtx*, int*);
|
||||
extern const char* avr_out_plus (rtx*, int*);
|
||||
extern const char* avr_out_plus (rtx*, int*, int*);
|
||||
extern const char* avr_out_addto_sp (rtx*, int*);
|
||||
extern bool avr_popcount_each_byte (rtx, int, int);
|
||||
|
||||
|
@ -1630,9 +1630,37 @@ void
|
||||
notice_update_cc (rtx body ATTRIBUTE_UNUSED, rtx insn)
|
||||
{
|
||||
rtx set;
|
||||
enum attr_cc cc = get_attr_cc (insn);
|
||||
|
||||
switch (get_attr_cc (insn))
|
||||
switch (cc)
|
||||
{
|
||||
default:
|
||||
break;
|
||||
|
||||
case CC_OUT_PLUS:
|
||||
{
|
||||
rtx *op = recog_data.operand;
|
||||
int len_dummy, icc;
|
||||
|
||||
/* Extract insn's operands. */
|
||||
extract_constrain_insn_cached (insn);
|
||||
|
||||
avr_out_plus (op, &len_dummy, &icc);
|
||||
cc = (enum attr_cc) icc;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (cc)
|
||||
{
|
||||
default:
|
||||
/* Special values like CC_OUT_PLUS from above have been
|
||||
mapped to "standard" CC_* values so we never come here. */
|
||||
|
||||
gcc_unreachable();
|
||||
break;
|
||||
|
||||
case CC_NONE:
|
||||
/* Insn does not affect CC at all. */
|
||||
break;
|
||||
@ -4673,10 +4701,11 @@ lshrsi3_out (rtx insn, rtx operands[], int *len)
|
||||
addition; otherwise, set *PLEN to the length of the instruction sequence (in
|
||||
words) printed with PLEN == NULL. XOP[3] is an 8-bit scratch register.
|
||||
CODE == PLUS: perform addition by using ADD instructions.
|
||||
CODE == MINUS: perform addition by using SUB instructions. */
|
||||
CODE == MINUS: perform addition by using SUB instructions.
|
||||
Set *PCC to effect on cc0 according to respective CC_* insn attribute. */
|
||||
|
||||
static void
|
||||
avr_out_plus_1 (rtx *xop, int *plen, enum rtx_code code)
|
||||
avr_out_plus_1 (rtx *xop, int *plen, enum rtx_code code, int *pcc)
|
||||
{
|
||||
/* MODE of the operation. */
|
||||
enum machine_mode mode = GET_MODE (xop[0]);
|
||||
@ -4700,6 +4729,10 @@ avr_out_plus_1 (rtx *xop, int *plen, enum rtx_code code)
|
||||
/* Value to add. There are two ways to add VAL: R += VAL and R -= -VAL. */
|
||||
rtx xval = xop[2];
|
||||
|
||||
/* Addition does not set cc0 in a usable way. */
|
||||
|
||||
*pcc = (MINUS == code) ? CC_SET_CZN : CC_CLOBBER;
|
||||
|
||||
if (MINUS == code)
|
||||
xval = gen_int_mode (-UINTVAL (xval), mode);
|
||||
|
||||
@ -4722,6 +4755,11 @@ avr_out_plus_1 (rtx *xop, int *plen, enum rtx_code code)
|
||||
|
||||
op[0] = reg8;
|
||||
op[1] = GEN_INT (val8);
|
||||
|
||||
/* To get usable cc0 no low-bytes must have been skipped. */
|
||||
|
||||
if (i && !started)
|
||||
*pcc = CC_CLOBBER;
|
||||
|
||||
if (!started && i % 2 == 0
|
||||
&& test_hard_reg_class (ADDW_REGS, reg8))
|
||||
@ -4794,6 +4832,11 @@ avr_out_plus_1 (rtx *xop, int *plen, enum rtx_code code)
|
||||
started = true;
|
||||
|
||||
} /* for all sub-bytes */
|
||||
|
||||
/* No output doesn't change cc0. */
|
||||
|
||||
if (plen && *plen == 0)
|
||||
*pcc = CC_NONE;
|
||||
}
|
||||
|
||||
|
||||
@ -4803,24 +4846,35 @@ avr_out_plus_1 (rtx *xop, int *plen, enum rtx_code code)
|
||||
|
||||
and return "". If PLEN == NULL, print assembler instructions to perform the
|
||||
addition; otherwise, set *PLEN to the length of the instruction sequence (in
|
||||
words) printed with PLEN == NULL. */
|
||||
words) printed with PLEN == NULL.
|
||||
If PCC != 0 then set *PCC to the the instruction sequence's effect on the
|
||||
condition code (with respect to XOP[0]). */
|
||||
|
||||
const char*
|
||||
avr_out_plus (rtx *xop, int *plen)
|
||||
avr_out_plus (rtx *xop, int *plen, int *pcc)
|
||||
{
|
||||
int len_plus, len_minus;
|
||||
int cc_plus, cc_minus, cc_dummy;
|
||||
|
||||
if (!pcc)
|
||||
pcc = &cc_dummy;
|
||||
|
||||
/* Work out if XOP[0] += XOP[2] is better or XOP[0] -= -XOP[2]. */
|
||||
|
||||
avr_out_plus_1 (xop, &len_plus, PLUS);
|
||||
avr_out_plus_1 (xop, &len_minus, MINUS);
|
||||
avr_out_plus_1 (xop, &len_plus, PLUS, &cc_plus);
|
||||
avr_out_plus_1 (xop, &len_minus, MINUS, &cc_minus);
|
||||
|
||||
/* Prefer MINUS over PLUS if size is equal because it sets cc0. */
|
||||
|
||||
if (plen)
|
||||
*plen = (len_minus <= len_plus) ? len_minus : len_plus;
|
||||
{
|
||||
*plen = (len_minus <= len_plus) ? len_minus : len_plus;
|
||||
*pcc = (len_minus <= len_plus) ? cc_minus : cc_plus;
|
||||
}
|
||||
else if (len_minus <= len_plus)
|
||||
avr_out_plus_1 (xop, NULL, MINUS);
|
||||
avr_out_plus_1 (xop, NULL, MINUS, pcc);
|
||||
else
|
||||
avr_out_plus_1 (xop, NULL, PLUS);
|
||||
avr_out_plus_1 (xop, NULL, PLUS, pcc);
|
||||
|
||||
return "";
|
||||
}
|
||||
@ -5209,7 +5263,7 @@ adjust_insn_length (rtx insn, int len)
|
||||
|
||||
case ADJUST_LEN_OUT_BITOP: avr_out_bitop (insn, op, &len); break;
|
||||
|
||||
case ADJUST_LEN_OUT_PLUS: avr_out_plus (op, &len); break;
|
||||
case ADJUST_LEN_OUT_PLUS: avr_out_plus (op, &len, NULL); break;
|
||||
|
||||
case ADJUST_LEN_ADDTO_SP: avr_out_addto_sp (op, &len); break;
|
||||
|
||||
|
@ -77,7 +77,8 @@
|
||||
(include "constraints.md")
|
||||
|
||||
;; Condition code settings.
|
||||
(define_attr "cc" "none,set_czn,set_zn,set_n,compare,clobber"
|
||||
(define_attr "cc" "none,set_czn,set_zn,set_n,compare,clobber,
|
||||
out_plus"
|
||||
(const_string "none"))
|
||||
|
||||
(define_attr "type" "branch,branch1,arith,xcall"
|
||||
@ -786,30 +787,28 @@
|
||||
(set_attr "cc" "set_n,set_czn,set_czn,set_czn,set_n,set_n")])
|
||||
|
||||
(define_insn "addsi3"
|
||||
[(set (match_operand:SI 0 "register_operand" "=r,!w,!w,d,l,l ,d,r")
|
||||
(plus:SI (match_operand:SI 1 "register_operand" "%0,0 ,0 ,0,0,0 ,0,0")
|
||||
(match_operand:SI 2 "nonmemory_operand" "r,I ,J ,s,P,N ,n,n")))
|
||||
(clobber (match_scratch:QI 3 "=X,X ,X ,X,X,X ,X,&d"))]
|
||||
[(set (match_operand:SI 0 "register_operand" "=r,d ,d,r")
|
||||
(plus:SI (match_operand:SI 1 "register_operand" "%0,0 ,0,0")
|
||||
(match_operand:SI 2 "nonmemory_operand" "r,s ,n,n")))
|
||||
(clobber (match_scratch:QI 3 "=X,X ,X,&d"))]
|
||||
""
|
||||
{
|
||||
static const char * const asm_code[] =
|
||||
{
|
||||
"add %A0,%A2\;adc %B0,%B2\;adc %C0,%C2\;adc %D0,%D2",
|
||||
"adiw %0,%2\;adc %C0,__zero_reg__\;adc %D0,__zero_reg__",
|
||||
"sbiw %0,%n2\;sbc %C0,__zero_reg__\;sbc %D0,__zero_reg__",
|
||||
"subi %0,lo8(-(%2))\;sbci %B0,hi8(-(%2))\;sbci %C0,hlo8(-(%2))\;sbci %D0,hhi8(-(%2))",
|
||||
"sec\;adc %A0,__zero_reg__\;adc %B0,__zero_reg__\;adc %C0,__zero_reg__\;adc %D0,__zero_reg__",
|
||||
"sec\;sbc %A0,__zero_reg__\;sbc %B0,__zero_reg__\;sbc %C0,__zero_reg__\;sbc %D0,__zero_reg__"
|
||||
"",
|
||||
""
|
||||
};
|
||||
|
||||
if (which_alternative >= (signed) (sizeof (asm_code) / sizeof (*asm_code)))
|
||||
return avr_out_plus (operands, NULL);
|
||||
if (*asm_code[which_alternative])
|
||||
return asm_code [which_alternative];
|
||||
|
||||
return asm_code [which_alternative];
|
||||
return avr_out_plus (operands, NULL, NULL);
|
||||
}
|
||||
[(set_attr "length" "4,3,3,4,5,5,8,8")
|
||||
(set_attr "adjust_len" "*,*,*,*,*,*,out_plus,out_plus")
|
||||
(set_attr "cc" "set_n,set_n,set_czn,set_czn,set_n,set_n,clobber,clobber")])
|
||||
[(set_attr "length" "4,4,4,8")
|
||||
(set_attr "adjust_len" "*,*,out_plus,out_plus")
|
||||
(set_attr "cc" "set_n,set_czn,out_plus,out_plus")])
|
||||
|
||||
(define_insn "*addsi3_zero_extend"
|
||||
[(set (match_operand:SI 0 "register_operand" "=r")
|
||||
|
Loading…
Reference in New Issue
Block a user