diff --git a/gcc/ChangeLog b/gcc/ChangeLog index f359bd1cb63..e34cfa07d30 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,12 @@ +2012-01-04 Georg-Johann Lay + + Fix clearing ZERO_REG + * config/avr/avr.md (cc): Add alternative "ldi". + (movqi_insn): Use it in cc attribute. + * config/avr/avr.c (notice_update_cc): Handle CC_LDI. + (output_reload_in_const): Use CLR to move 0 to ZERO_REG. + (output_reload_insisf): Use ZERO_REG to pre-clear register. + 2012-01-04 Andreas Krebbel * configure: Regenerate. diff --git a/gcc/config/avr/avr.c b/gcc/config/avr/avr.c index e2cd1355992..48306329a72 100644 --- a/gcc/config/avr/avr.c +++ b/gcc/config/avr/avr.c @@ -1994,6 +1994,7 @@ notice_update_cc (rtx body ATTRIBUTE_UNUSED, rtx insn) case CC_OUT_PLUS: case CC_OUT_PLUS_NOCLOBBER: + case CC_LDI: { rtx *op = recog_data.operand; int len_dummy, icc; @@ -2001,16 +2002,36 @@ notice_update_cc (rtx body ATTRIBUTE_UNUSED, rtx insn) /* Extract insn's operands. */ extract_constrain_insn_cached (insn); - if (CC_OUT_PLUS == cc) - avr_out_plus (op, &len_dummy, &icc); - else - avr_out_plus_noclobber (op, &len_dummy, &icc); - - cc = (enum attr_cc) icc; - + switch (cc) + { + default: + gcc_unreachable(); + + case CC_OUT_PLUS: + avr_out_plus (op, &len_dummy, &icc); + cc = (enum attr_cc) icc; + break; + + case CC_OUT_PLUS_NOCLOBBER: + avr_out_plus_noclobber (op, &len_dummy, &icc); + cc = (enum attr_cc) icc; + break; + + case CC_LDI: + + cc = (op[1] == CONST0_RTX (GET_MODE (op[0])) + && reg_overlap_mentioned_p (op[0], zero_reg_rtx)) + /* Loading zero-reg with 0 uses CLI and thus clobbers cc0. */ + ? CC_CLOBBER + /* Any other "r,rL" combination does not alter cc0. */ + : CC_NONE; + + break; + } /* inner switch */ + break; } - } + } /* outer swicth */ switch (cc) { @@ -8945,9 +8966,9 @@ avr_regno_mode_code_ok_for_base_p (int regno, The effect on cc0 is as follows: - Load 0 to any register : NONE - Load ld register with any value : NONE - Anything else: : CLOBBER */ + Load 0 to any register except ZERO_REG : NONE + Load ld register with any value : NONE + Anything else: : CLOBBER */ static void output_reload_in_const (rtx *op, rtx clobber_reg, int *len, bool clear_p) @@ -9062,7 +9083,9 @@ output_reload_in_const (rtx *op, rtx clobber_reg, int *len, bool clear_p) if (ival[n] == 0) { if (!clear_p) - avr_asm_len (ldreg_p ? "ldi %0,0" : "mov %0,__zero_reg__", + avr_asm_len (ldreg_p ? "ldi %0,0" + : ZERO_REGNO == REGNO (xdest[n]) ? "clr %0" + : "mov %0,__zero_reg__", &xdest[n], len, 1); continue; } @@ -9224,8 +9247,8 @@ output_reload_insisf (rtx *op, rtx clobber_reg, int *len) { /* Default needs 4 CLR instructions: clear register beforehand. */ - avr_asm_len ("clr %A0" CR_TAB - "clr %B0" CR_TAB + avr_asm_len ("mov %A0,__zero_reg__" CR_TAB + "mov %B0,__zero_reg__" CR_TAB "movw %C0,%A0", &op[0], len, 3); output_reload_in_const (op, clobber_reg, len, true); diff --git a/gcc/config/avr/avr.md b/gcc/config/avr/avr.md index 9222f0b6fff..9f3c3f107a0 100644 --- a/gcc/config/avr/avr.md +++ b/gcc/config/avr/avr.md @@ -95,7 +95,7 @@ ;; Condition code settings. (define_attr "cc" "none,set_czn,set_zn,set_n,compare,clobber, - out_plus, out_plus_noclobber" + out_plus, out_plus_noclobber,ldi" (const_string "none")) (define_attr "type" "branch,branch1,arith,xcall" @@ -584,7 +584,7 @@ } [(set_attr "length" "1,1,5,5,1,1,4") (set_attr "adjust_len" "mov8") - (set_attr "cc" "none,none,clobber,clobber,none,none,clobber")]) + (set_attr "cc" "ldi,none,clobber,clobber,none,none,clobber")]) ;; This is used in peephole2 to optimize loading immediate constants ;; if a scratch register from LD_REGS happens to be available.