diff options
author | Georg-Johann Lay <avr@gjlay.de> | 2012-02-22 09:25:35 +0000 |
---|---|---|
committer | Georg-Johann Lay <gjl@gcc.gnu.org> | 2012-02-22 09:25:35 +0000 |
commit | 0b262c28c6bc818e3b93577f0354b7d61cd23c84 (patch) | |
tree | d09627a405e1eed17dec350d03c873a0a6a03ea2 /gcc | |
parent | 8d071654dcaf410e5aa9905676d26ff09b5f6a10 (diff) | |
download | gcc-0b262c28c6bc818e3b93577f0354b7d61cd23c84.zip gcc-0b262c28c6bc818e3b93577f0354b7d61cd23c84.tar.gz gcc-0b262c28c6bc818e3b93577f0354b7d61cd23c84.tar.bz2 |
re PR rtl-optimization/50063 (DSE: wrong code for gcc.dg/torture/pta-ptrarith-3.c)
PR rtl-optimization/50063
* config/avr/avr.md (movhi_sp_r): Handle -1 (unknown IRQ state)
and 2 (8-bit SP) in operand 2.
* config/avr/avr.c (avr_prologue_setup_frame): Adjust prologue
setup to use movhi_sp_r instead of vanilla move to write SP.
Adjust REG_CFA notes to superseed unspec.
(expand_epilogue): Adjust epilogue setup to use movhi_sp_r instead
of vanilla move.
As function body might contain CLI or SEI: Use irq_state 0 (IRQ
known to be off) only with TARGET_NO_INTERRUPTS. Never use
irq_state 1 (IRQ known to be on) here.
From-SVN: r184461
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 14 | ||||
-rw-r--r-- | gcc/config/avr/avr.c | 100 | ||||
-rw-r--r-- | gcc/config/avr/avr.md | 29 |
3 files changed, 82 insertions, 61 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 88c01d4..d5aa911 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,17 @@ +2012-02-22 Georg-Johann Lay <avr@gjlay.de> + + PR rtl-optimization/50063 + * config/avr/avr.md (movhi_sp_r): Handle -1 (unknown IRQ state) + and 2 (8-bit SP) in operand 2. + * config/avr/avr.c (avr_prologue_setup_frame): Adjust prologue + setup to use movhi_sp_r instead of vanilla move to write SP. + Adjust REG_CFA notes to superseed unspec. + (expand_epilogue): Adjust epilogue setup to use movhi_sp_r instead + of vanilla move. + As function body might contain CLI or SEI: Use irq_state 0 (IRQ + known to be off) only with TARGET_NO_INTERRUPTS. Never use + irq_state 1 (IRQ known to be on) here. + 2012-02-21 Bernd Schmidt <bernds@codesourcery.com> * ira.c (check_allocation): Use REG_WORDS_BIG_ENDIAN, not diff --git a/gcc/config/avr/avr.c b/gcc/config/avr/avr.c index 8a0d69a..2a46292 100644 --- a/gcc/config/avr/avr.c +++ b/gcc/config/avr/avr.c @@ -1062,8 +1062,8 @@ avr_prologue_setup_frame (HOST_WIDE_INT size, HARD_REG_SET set) !frame_pointer_needed can only occur if the function is not a leaf function and thus X has already been saved. */ + int irq_state = -1; rtx fp_plus_insns, fp, my_fp; - rtx sp_minus_size = plus_constant (stack_pointer_rtx, -size); gcc_assert (frame_pointer_needed || !isr_p @@ -1076,7 +1076,7 @@ avr_prologue_setup_frame (HOST_WIDE_INT size, HARD_REG_SET set) if (AVR_HAVE_8BIT_SP) { /* The high byte (r29) does not change: - Prefer SUBI (1 cycle) over ABIW (2 cycles, same size). */ + Prefer SUBI (1 cycle) over SBIW (2 cycles, same size). */ my_fp = all_regs_rtx[FRAME_POINTER_REGNUM]; } @@ -1092,43 +1092,50 @@ avr_prologue_setup_frame (HOST_WIDE_INT size, HARD_REG_SET set) the frame pointer subtraction is done. */ insn = emit_move_insn (fp, stack_pointer_rtx); - if (!frame_pointer_needed) - RTX_FRAME_RELATED_P (insn) = 1; + if (frame_pointer_needed) + { + RTX_FRAME_RELATED_P (insn) = 1; + add_reg_note (insn, REG_CFA_ADJUST_CFA, + gen_rtx_SET (VOIDmode, fp, stack_pointer_rtx)); + } insn = emit_move_insn (my_fp, plus_constant (my_fp, -size)); - RTX_FRAME_RELATED_P (insn) = 1; - if (frame_pointer_needed) { + RTX_FRAME_RELATED_P (insn) = 1; add_reg_note (insn, REG_CFA_ADJUST_CFA, - gen_rtx_SET (VOIDmode, fp, sp_minus_size)); + gen_rtx_SET (VOIDmode, fp, + plus_constant (fp, -size))); } /* Copy to stack pointer. Note that since we've already changed the CFA to the frame pointer this operation - need not be annotated if frame pointer is needed. */ - - if (AVR_HAVE_8BIT_SP || AVR_XMEGA) - { - insn = emit_move_insn (stack_pointer_rtx, fp); - } - else if (TARGET_NO_INTERRUPTS - || isr_p - || cfun->machine->is_OS_main) - { - rtx irqs_are_on = GEN_INT (!!cfun->machine->is_interrupt); - - insn = emit_insn (gen_movhi_sp_r (stack_pointer_rtx, - fp, irqs_are_on)); - } - else - { - insn = emit_move_insn (stack_pointer_rtx, fp); - } + need not be annotated if frame pointer is needed. + Always move through unspec, see PR50063. + For meaning of irq_state see movhi_sp_r insn. */ - if (!frame_pointer_needed) - RTX_FRAME_RELATED_P (insn) = 1; + if (cfun->machine->is_interrupt) + irq_state = 1; + + if (TARGET_NO_INTERRUPTS + || cfun->machine->is_signal + || cfun->machine->is_OS_main) + irq_state = 0; + if (AVR_HAVE_8BIT_SP) + irq_state = 2; + + insn = emit_insn (gen_movhi_sp_r (stack_pointer_rtx, + fp, GEN_INT (irq_state))); + if (!frame_pointer_needed) + { + RTX_FRAME_RELATED_P (insn) = 1; + add_reg_note (insn, REG_CFA_ADJUST_CFA, + gen_rtx_SET (VOIDmode, stack_pointer_rtx, + plus_constant (stack_pointer_rtx, + -size))); + } + fp_plus_insns = get_insns (); end_sequence (); @@ -1143,9 +1150,13 @@ avr_prologue_setup_frame (HOST_WIDE_INT size, HARD_REG_SET set) start_sequence (); - insn = emit_move_insn (stack_pointer_rtx, sp_minus_size); + insn = emit_move_insn (stack_pointer_rtx, + plus_constant (stack_pointer_rtx, -size)); RTX_FRAME_RELATED_P (insn) = 1; - + add_reg_note (insn, REG_CFA_ADJUST_CFA, + gen_rtx_SET (VOIDmode, stack_pointer_rtx, + plus_constant (stack_pointer_rtx, + -size))); if (frame_pointer_needed) { insn = emit_move_insn (fp, stack_pointer_rtx); @@ -1376,7 +1387,8 @@ expand_epilogue (bool sibcall_p) if (size) { /* Try two methods to adjust stack and select shortest. */ - + + int irq_state = -1; rtx fp, my_fp; rtx fp_plus_insns; @@ -1406,23 +1418,15 @@ expand_epilogue (bool sibcall_p) emit_move_insn (my_fp, plus_constant (my_fp, size)); /* Copy to stack pointer. */ - - if (AVR_HAVE_8BIT_SP || AVR_XMEGA) - { - emit_move_insn (stack_pointer_rtx, fp); - } - else if (TARGET_NO_INTERRUPTS - || isr_p - || cfun->machine->is_OS_main) - { - rtx irqs_are_on = GEN_INT (!!cfun->machine->is_interrupt); - - emit_insn (gen_movhi_sp_r (stack_pointer_rtx, fp, irqs_are_on)); - } - else - { - emit_move_insn (stack_pointer_rtx, fp); - } + + if (TARGET_NO_INTERRUPTS) + irq_state = 0; + + if (AVR_HAVE_8BIT_SP) + irq_state = 2; + + emit_insn (gen_movhi_sp_r (stack_pointer_rtx, fp, + GEN_INT (irq_state))); fp_plus_insns = get_insns (); end_sequence (); diff --git a/gcc/config/avr/avr.md b/gcc/config/avr/avr.md index a7fa04c..b217d03 100644 --- a/gcc/config/avr/avr.md +++ b/gcc/config/avr/avr.md @@ -583,23 +583,26 @@ ;; Move register $1 to the Stack Pointer register SP. ;; This insn is emit during function prologue/epilogue generation. -;; $2 = 0: We know that IRQs are off -;; $2 = 1: We know that IRQs are on -;; Remaining cases when the state of the I-Flag is unknown are -;; handled by generic movhi insn. +;; $2 = 0: We know that IRQs are off +;; $2 = 1: We know that IRQs are on +;; $2 = 2: SP has 8 bits only, IRQ state does not matter +;; $2 = -1: We don't know anything about IRQ on/off +;; Always write SP via unspec, see PR50063 (define_insn "movhi_sp_r" - [(set (match_operand:HI 0 "stack_register_operand" "=q,q,q") - (unspec_volatile:HI [(match_operand:HI 1 "register_operand" "r,r,r") - (match_operand:HI 2 "const_int_operand" "L,P,LP")] + [(set (match_operand:HI 0 "stack_register_operand" "=q,q,q,q,q") + (unspec_volatile:HI [(match_operand:HI 1 "register_operand" "r,r,r,r,r") + (match_operand:HI 2 "const_int_operand" "L,P,N,K,LPN")] UNSPECV_WRITE_SP))] - "!AVR_HAVE_8BIT_SP" + "" "@ - out __SP_H__,%B1\;out __SP_L__,%A1 - cli\;out __SP_H__,%B1\;sei\;out __SP_L__,%A1 - out __SP_L__,%A1\;out __SP_H__,%B1" - [(set_attr "length" "2,4,2") - (set_attr "isa" "no_xmega,no_xmega,xmega") + out %B0,%B1\;out %A0,%A1 + cli\;out %B0,%B1\;sei\;out %A0,%A1 + in __tmp_reg__,__SREG__\;cli\;out %B0,%B1\;out __SREG__,__tmp_reg__\;out %A0,%A1 + out %A0,%A1 + out %A0,%A1\;out %B0,%B1" + [(set_attr "length" "2,4,5,1,2") + (set_attr "isa" "no_xmega,no_xmega,no_xmega,*,xmega") (set_attr "cc" "none")]) (define_peephole2 |