aboutsummaryrefslogtreecommitdiff
path: root/gcc/config/avr
diff options
context:
space:
mode:
authorGeorg-Johann Lay <avr@gjlay.de>2011-10-11 18:28:49 +0000
committerGeorg-Johann Lay <gjl@gcc.gnu.org>2011-10-11 18:28:49 +0000
commit05058b6e31ec87bb08cb9457b22080afbd2c4723 (patch)
tree014074a311e4c9e316bbded0457287a7e8b7df50 /gcc/config/avr
parenta4474a3854f4fec4bfccad91706f95a6737e6a79 (diff)
downloadgcc-05058b6e31ec87bb08cb9457b22080afbd2c4723.zip
gcc-05058b6e31ec87bb08cb9457b22080afbd2c4723.tar.gz
gcc-05058b6e31ec87bb08cb9457b22080afbd2c4723.tar.bz2
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
Diffstat (limited to 'gcc/config/avr')
-rw-r--r--gcc/config/avr/avr-protos.h2
-rw-r--r--gcc/config/avr/avr.c76
-rw-r--r--gcc/config/avr/avr.md29
3 files changed, 80 insertions, 27 deletions
diff --git a/gcc/config/avr/avr-protos.h b/gcc/config/avr/avr-protos.h
index a2a5dd0..06e412c 100644
--- a/gcc/config/avr/avr-protos.h
+++ b/gcc/config/avr/avr-protos.h
@@ -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);
diff --git a/gcc/config/avr/avr.c b/gcc/config/avr/avr.c
index d8cc84a..afc3d61 100644
--- a/gcc/config/avr/avr.c
+++ b/gcc/config/avr/avr.c
@@ -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;
diff --git a/gcc/config/avr/avr.md b/gcc/config/avr/avr.md
index 23541bf..b7fe770 100644
--- a/gcc/config/avr/avr.md
+++ b/gcc/config/avr/avr.md
@@ -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")