aboutsummaryrefslogtreecommitdiff
path: root/gcc/config/avr
diff options
context:
space:
mode:
authorAndy Hutchinson <hutchinsonandy@aim.com>2008-06-02 22:08:25 +0000
committerAndy Hutchinson <hutchinsonandy@gcc.gnu.org>2008-06-02 22:08:25 +0000
commit1bf296437b0a3361c2b005c03204c16b3f0de234 (patch)
treeec060fe0e4e74cf60d9c621edb36eea9bcc9c23c /gcc/config/avr
parente62532afd777edea4d3eeb1963060f75952319ca (diff)
downloadgcc-1bf296437b0a3361c2b005c03204c16b3f0de234.zip
gcc-1bf296437b0a3361c2b005c03204c16b3f0de234.tar.gz
gcc-1bf296437b0a3361c2b005c03204c16b3f0de234.tar.bz2
re PR target/34879 (__builtin_setjmp / __builtin_longjmp fails stack frame address with O2, O3 and Os)
PR target/34879 * config/avr/avr.c (TARGET_BUILTIN_SETJMP_FRAME_VALUE): Redefine. (avr_builtin_setjmp_frame_value): New function. * config/avr/avr.md (nonlocal_goto_receiver): Define. (nonlocal_goto): Define. From-SVN: r136297
Diffstat (limited to 'gcc/config/avr')
-rw-r--r--gcc/config/avr/avr.c16
-rw-r--r--gcc/config/avr/avr.md60
2 files changed, 75 insertions, 1 deletions
diff --git a/gcc/config/avr/avr.c b/gcc/config/avr/avr.c
index 7135c79..405f42f 100644
--- a/gcc/config/avr/avr.c
+++ b/gcc/config/avr/avr.c
@@ -83,6 +83,8 @@ static bool avr_rtx_costs (rtx, int, int, int *);
static int avr_address_cost (rtx);
static bool avr_return_in_memory (const_tree, const_tree);
static struct machine_function * avr_init_machine_status (void);
+static rtx avr_builtin_setjmp_frame_value (void);
+
/* Allocate registers from r25 to r8 for parameters for function calls. */
#define FIRST_CUM_REG 26
@@ -323,6 +325,9 @@ int avr_case_values_threshold = 30000;
#undef TARGET_STRICT_ARGUMENT_NAMING
#define TARGET_STRICT_ARGUMENT_NAMING hook_bool_CUMULATIVE_ARGS_true
+#undef TARGET_BUILTIN_SETJMP_FRAME_VALUE
+#define TARGET_BUILTIN_SETJMP_FRAME_VALUE avr_builtin_setjmp_frame_value
+
struct gcc_target targetm = TARGET_INITIALIZER;
void
@@ -523,6 +528,17 @@ initial_elimination_offset (int from, int to)
}
}
+/* Actual start of frame is virtual_stack_vars_rtx this is offset from
+ frame pointer by +STARTING_FRAME_OFFSET.
+ Using saved frame = virtual_stack_vars_rtx - STARTING_FRAME_OFFSET
+ avoids creating add/sub of offset in nonlocal goto and setjmp. */
+
+rtx avr_builtin_setjmp_frame_value (void)
+{
+ return gen_rtx_MINUS (Pmode, virtual_stack_vars_rtx,
+ gen_int_mode (STARTING_FRAME_OFFSET, Pmode));
+}
+
/* Return 1 if the function epilogue is just a single "ret". */
int
diff --git a/gcc/config/avr/avr.md b/gcc/config/avr/avr.md
index a4914c4..0fd3712 100644
--- a/gcc/config/avr/avr.md
+++ b/gcc/config/avr/avr.md
@@ -58,7 +58,8 @@
(UNSPECV_PROLOGUE_SAVES 0)
(UNSPECV_EPILOGUE_RESTORES 1)
(UNSPECV_WRITE_SP_IRQ_ON 2)
- (UNSPECV_WRITE_SP_IRQ_OFF 3)])
+ (UNSPECV_WRITE_SP_IRQ_OFF 3)
+ (UNSPECV_GOTO_RECEIVER 4)])
(include "predicates.md")
(include "constraints.md")
@@ -115,6 +116,63 @@
(const_int 2))]
(const_int 2)))
+;;========================================================================
+;; The following is used by nonlocal_goto and setjmp.
+;; The receiver pattern will create no instructions since internally
+;; virtual_stack_vars = hard_frame_pointer + 1 so the RTL become R28=R28
+;; This avoids creating add/sub offsets in frame_pointer save/resore.
+;; The 'null' receiver also avoids problems with optimisation
+;; not recognising incoming jmp and removing code that resets frame_pointer.
+;; The code derived from builtins.c.
+
+(define_expand "nonlocal_goto_receiver"
+ [(set (reg:HI REG_Y)
+ (unspec_volatile:HI [(const_int 0)] UNSPECV_GOTO_RECEIVER))]
+ ""
+ {
+ emit_move_insn (virtual_stack_vars_rtx,
+ gen_rtx_PLUS (Pmode, hard_frame_pointer_rtx,
+ gen_int_mode (STARTING_FRAME_OFFSET,
+ Pmode)));
+ /* This might change the hard frame pointer in ways that aren't
+ apparent to early optimization passes, so force a clobber. */
+ emit_clobber (hard_frame_pointer_rtx);
+ DONE;
+ })
+
+
+;; Defining nonlocal_goto_receiver means we must also define this.
+;; even though its function is identical to that in builtins.c
+
+(define_expand "nonlocal_goto"
+ [
+ (use (match_operand 0 "general_operand"))
+ (use (match_operand 1 "general_operand"))
+ (use (match_operand 2 "general_operand"))
+ (use (match_operand 3 "general_operand"))
+ ]
+ ""
+{
+ rtx r_label = copy_to_reg (operands[1]);
+ rtx r_fp = operands[3];
+ rtx r_sp = operands[2];
+
+ emit_clobber (gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (VOIDmode)));
+
+ emit_clobber (gen_rtx_MEM (BLKmode, hard_frame_pointer_rtx));
+
+ emit_move_insn (hard_frame_pointer_rtx, r_fp);
+ emit_stack_restore (SAVE_NONLOCAL, r_sp, NULL_RTX);
+
+ emit_use (hard_frame_pointer_rtx);
+ emit_use (stack_pointer_rtx);
+
+ emit_indirect_jump (r_label);
+
+ DONE;
+})
+
+
(define_insn "*pushqi"
[(set (mem:QI (post_dec (reg:HI REG_SP)))
(match_operand:QI 0 "reg_or_0_operand" "r,L"))]