diff options
author | Richard Henderson <rth@redhat.com> | 2001-03-28 03:14:40 -0800 |
---|---|---|
committer | Richard Henderson <rth@gcc.gnu.org> | 2001-03-28 03:14:40 -0800 |
commit | 1020a5ab7ee1a39c3d2be3d3bdb4242985d75812 (patch) | |
tree | bfbf4f1be1b6e8c2d914a24827a3b06178106afc /gcc | |
parent | 4573b4de233cd221a8ecbb8fee3ad533dc68ce93 (diff) | |
download | gcc-1020a5ab7ee1a39c3d2be3d3bdb4242985d75812.zip gcc-1020a5ab7ee1a39c3d2be3d3bdb4242985d75812.tar.gz gcc-1020a5ab7ee1a39c3d2be3d3bdb4242985d75812.tar.bz2 |
i386.c (general_no_elim_operand): Disallow virtual regs.
* config/i386/i386.c (general_no_elim_operand): Disallow virtual regs.
(ix86_save_reg): If maybe_eh_return, true for EH_RETURN_DATA_REGNOs.
True for pic register if current_function_calls_eh_return.
(ix86_expand_epilogue): Change "emit_return" argument into "style".
Handle eh_return requirements.
* config/i386/i386.h (EH_RETURN_DATA_REGNO): New.
(EH_RETURN_STACKADJ_RTX): New.
* config/i386/i386.md (exception_receiver): Remove.
(eh_return, eh_return_1): New.
* config/i386/linux.h (MD_FALLBACK_FRAME_STATE_FOR): New.
From-SVN: r40926
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 27 | ||||
-rw-r--r-- | gcc/config/i386/i386.c | 107 | ||||
-rw-r--r-- | gcc/config/i386/i386.h | 12 | ||||
-rw-r--r-- | gcc/config/i386/i386.md | 39 | ||||
-rw-r--r-- | gcc/config/i386/linux.h | 62 |
5 files changed, 199 insertions, 48 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 66122d4..c94073ed 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,13 +1,24 @@ 2001-03-28 Richard Henderson <rth@redhat.com> - * config/alpha/alpha.c (alpha_sa_mask): Add EH_RETURN_DATA_REGNOs. - (alpha_mark_machine_status): No eh_epilogue_sp_ofs ... - (alpha_expand_epilogue): ... use EH_RETURN_STACKADJ_RTX instead. - * config/alpha/alpha.h (machine_function): Remove eh_epilogue_sp_ofs. - (EH_RETURN_DATA_REGNO): New. - (EH_RETURN_STACKADJ_RTX, EH_RETURN_HANDLER_RTX): New. - * config/alpha/alpha.md (eh_epilogue): Remove. - (exception_receiver): Use $26 for ldgp input. + * config/i386/i386.c (general_no_elim_operand): Disallow virtual regs. + (ix86_save_reg): If maybe_eh_return, true for EH_RETURN_DATA_REGNOs. + True for pic register if current_function_calls_eh_return. + (ix86_expand_epilogue): Change "emit_return" argument into "style". + Handle eh_return requirements. + * config/i386/i386.h (EH_RETURN_DATA_REGNO): New. + (EH_RETURN_STACKADJ_RTX): New. + * config/i386/i386.md (exception_receiver): Remove. + (eh_return, eh_return_1): New. + * config/i386/linux.h (MD_FALLBACK_FRAME_STATE_FOR): New. + + * config/alpha/alpha.c (alpha_sa_mask): Add EH_RETURN_DATA_REGNOs. + (alpha_mark_machine_status): No eh_epilogue_sp_ofs ... + (alpha_expand_epilogue): ... use EH_RETURN_STACKADJ_RTX instead. + * config/alpha/alpha.h (machine_function): Remove eh_epilogue_sp_ofs. + (EH_RETURN_DATA_REGNO): New. + (EH_RETURN_STACKADJ_RTX, EH_RETURN_HANDLER_RTX): New. + * config/alpha/alpha.md (eh_epilogue): Remove. + (exception_receiver): Use $26 for ldgp input. * config/alpha/linux.h (MD_FALLBACK_FRAME_STATE_FOR): New. 2001-03-28 Richard Henderson <rth@redhat.com> diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index b12d625..57db899 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -566,7 +566,7 @@ static int ix86_split_to_parts PARAMS ((rtx, rtx *, enum machine_mode)); static int ix86_safe_length_prefix PARAMS ((rtx)); static int ix86_nsaved_regs PARAMS((void)); static void ix86_emit_save_regs PARAMS((void)); -static void ix86_emit_restore_regs_using_mov PARAMS ((rtx, int)); +static void ix86_emit_restore_regs_using_mov PARAMS ((rtx, int, bool)); static void ix86_emit_epilogue_esp_adjustment PARAMS((int)); static void ix86_set_move_mem_attrs_1 PARAMS ((rtx, rtx, rtx, rtx, rtx)); static void ix86_sched_reorder_pentium PARAMS((rtx *, rtx *)); @@ -606,7 +606,7 @@ static int ix86_fp_comparison_arithmetics_cost PARAMS ((enum rtx_code code)); static int ix86_fp_comparison_fcomi_cost PARAMS ((enum rtx_code code)); static int ix86_fp_comparison_sahf_cost PARAMS ((enum rtx_code code)); static int ix86_fp_comparison_cost PARAMS ((enum rtx_code code)); -static int ix86_save_reg PARAMS ((int)); +static int ix86_save_reg PARAMS ((int, bool)); static void ix86_compute_frame_layout PARAMS ((struct ix86_frame *)); /* Sometimes certain combinations of command options do not make @@ -1475,6 +1475,10 @@ general_no_elim_operand (op, mode) || t == virtual_incoming_args_rtx || t == virtual_stack_vars_rtx || t == virtual_stack_dynamic_rtx) return 0; + if (REG_P (t) + && REGNO (t) >= FIRST_VIRTUAL_REGISTER + && REGNO (t) <= LAST_VIRTUAL_REGISTER) + return 0; return general_operand (op, mode); } @@ -2249,17 +2253,35 @@ gen_push (arg) /* Return 1 if we need to save REGNO. */ static int -ix86_save_reg (regno) - int regno; -{ - int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table - || current_function_uses_const_pool) - && !TARGET_64BIT; - return ((regs_ever_live[regno] && !call_used_regs[regno] - && !fixed_regs[regno] - && (regno != HARD_FRAME_POINTER_REGNUM || !frame_pointer_needed)) - || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used)); +ix86_save_reg (regno, maybe_eh_return) + int regno; + bool maybe_eh_return; +{ + if (flag_pic + && ! TARGET_64BIT + && regno == PIC_OFFSET_TABLE_REGNUM + && (current_function_uses_pic_offset_table + || current_function_uses_const_pool + || current_function_calls_eh_return)) + return 1; + + if (current_function_calls_eh_return && maybe_eh_return) + { + unsigned i; + for (i = 0; ; i++) + { + unsigned test = EH_RETURN_DATA_REGNO(i); + if (test == INVALID_REGNUM) + break; + if (test == (unsigned) regno) + return 1; + } + } + return (regs_ever_live[regno] + && !call_used_regs[regno] + && !fixed_regs[regno] + && (regno != HARD_FRAME_POINTER_REGNUM || !frame_pointer_needed)); } /* Return number of registers to be saved on the stack. */ @@ -2271,7 +2293,7 @@ ix86_nsaved_regs () int regno; for (regno = FIRST_PSEUDO_REGISTER - 1; regno >= 0; regno--) - if (ix86_save_reg (regno)) + if (ix86_save_reg (regno, true)) nregs++; return nregs; } @@ -2423,7 +2445,7 @@ ix86_emit_save_regs () rtx insn; for (regno = FIRST_PSEUDO_REGISTER - 1; regno >= 0; regno--) - if (ix86_save_reg (regno)) + if (ix86_save_reg (regno, true)) { insn = emit_insn (gen_push (gen_rtx_REG (Pmode, regno))); RTX_FRAME_RELATED_P (insn) = 1; @@ -2535,14 +2557,15 @@ ix86_emit_epilogue_esp_adjustment (tsize) /* Emit code to restore saved registers using MOV insns. First register is restored from POINTER + OFFSET. */ static void -ix86_emit_restore_regs_using_mov (pointer, offset) - rtx pointer; - int offset; +ix86_emit_restore_regs_using_mov (pointer, offset, maybe_eh_return) + rtx pointer; + int offset; + bool maybe_eh_return; { int regno; for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) - if (ix86_save_reg (regno)) + if (ix86_save_reg (regno, maybe_eh_return)) { emit_move_insn (gen_rtx_REG (Pmode, regno), adj_offsettable_operand (gen_rtx_MEM (Pmode, @@ -2555,8 +2578,8 @@ ix86_emit_restore_regs_using_mov (pointer, offset) /* Restore function stack, frame, and registers. */ void -ix86_expand_epilogue (emit_return) - int emit_return; +ix86_expand_epilogue (style) + int style; { int regno; int sp_valid = !frame_pointer_needed || current_function_sp_is_unchanging; @@ -2588,7 +2611,8 @@ ix86_expand_epilogue (emit_return) if ((!sp_valid && frame.nregs <= 1) || (frame_pointer_needed && !frame.nregs && frame.to_allocate) || (frame_pointer_needed && TARGET_USE_LEAVE && !optimize_size - && frame.nregs == 1)) + && frame.nregs == 1) + || style == 2) { /* Restore registers. We can use ebp or esp to address the memory locations. If both are available, default to ebp, since offsets @@ -2597,12 +2621,41 @@ ix86_expand_epilogue (emit_return) mode. */ if (!frame_pointer_needed || (sp_valid && !frame.to_allocate)) - ix86_emit_restore_regs_using_mov (stack_pointer_rtx, frame.to_allocate); + ix86_emit_restore_regs_using_mov (stack_pointer_rtx, + frame.to_allocate, style == 2); else - ix86_emit_restore_regs_using_mov (hard_frame_pointer_rtx, offset); + ix86_emit_restore_regs_using_mov (hard_frame_pointer_rtx, + offset, style == 2); - if (!frame_pointer_needed) - ix86_emit_epilogue_esp_adjustment (frame.to_allocate + frame.nregs * UNITS_PER_WORD); + /* eh_return epilogues need %ecx added to the stack pointer. */ + if (style == 2) + { + rtx tmp, sa = EH_RETURN_STACKADJ_RTX; + + if (frame_pointer_needed) + { + tmp = gen_rtx_PLUS (Pmode, hard_frame_pointer_rtx, sa); + tmp = plus_constant (tmp, UNITS_PER_WORD); + emit_insn (gen_rtx_SET (VOIDmode, sa, tmp)); + + tmp = gen_rtx_MEM (Pmode, hard_frame_pointer_rtx); + emit_move_insn (hard_frame_pointer_rtx, tmp); + + emit_insn (gen_pro_epilogue_adjust_stack + (stack_pointer_rtx, sa, const0_rtx, + hard_frame_pointer_rtx)); + } + else + { + tmp = gen_rtx_PLUS (Pmode, stack_pointer_rtx, sa); + tmp = plus_constant (tmp, (frame.to_allocate + + frame.nregs * UNITS_PER_WORD)); + emit_insn (gen_rtx_SET (VOIDmode, stack_pointer_rtx, tmp)); + } + } + else if (!frame_pointer_needed) + ix86_emit_epilogue_esp_adjustment (frame.to_allocate + + frame.nregs * UNITS_PER_WORD); /* If not an i386, mov & pop is faster than "leave". */ else if (TARGET_USE_LEAVE || optimize_size) emit_insn (TARGET_64BIT ? gen_leave_rex64 () : gen_leave ()); @@ -2635,7 +2688,7 @@ ix86_expand_epilogue (emit_return) ix86_emit_epilogue_esp_adjustment (frame.to_allocate); for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) - if (ix86_save_reg (regno)) + if (ix86_save_reg (regno, false)) { if (TARGET_64BIT) emit_insn (gen_popdi1 (gen_rtx_REG (Pmode, regno))); @@ -2652,7 +2705,7 @@ ix86_expand_epilogue (emit_return) } /* Sibcall epilogues don't want a return instruction. */ - if (! emit_return) + if (style == 0) return; if (current_function_pops_args && current_function_args_size) diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h index 1552b41..cd9e54a 100644 --- a/gcc/config/i386/i386.h +++ b/gcc/config/i386/i386.h @@ -2779,10 +2779,10 @@ extern int const svr4_dbx_register_map[FIRST_PSEUDO_REGISTER]; gen_rtx_MEM (VOIDmode, gen_rtx_REG (VOIDmode, STACK_POINTER_REGNUM)) /* After the prologue, RA is at -4(AP) in the current frame. */ -#define RETURN_ADDR_RTX(COUNT, FRAME) \ - ((COUNT) == 0 \ - ? gen_rtx_MEM (Pmode, plus_constant (arg_pointer_rtx, TARGET_64BIT ? -8 : -4))\ - : gen_rtx_MEM (Pmode, plus_constant (FRAME, TARGET_64BIT ? 8 : 4))) +#define RETURN_ADDR_RTX(COUNT, FRAME) \ + ((COUNT) == 0 \ + ? gen_rtx_MEM (Pmode, plus_constant (arg_pointer_rtx, -UNITS_PER_WORD)) \ + : gen_rtx_MEM (Pmode, plus_constant (FRAME, UNITS_PER_WORD))) /* PC is dbx register 8; let's use that column for RA. */ #define DWARF_FRAME_RETURN_COLUMN (TARGET_64BIT ? 16 : 8) @@ -2790,6 +2790,10 @@ extern int const svr4_dbx_register_map[FIRST_PSEUDO_REGISTER]; /* Before the prologue, the top of the frame is at 4(%esp). */ #define INCOMING_FRAME_SP_OFFSET UNITS_PER_WORD +/* Describe how we implement __builtin_eh_return. */ +#define EH_RETURN_DATA_REGNO(N) ((N) < 2 ? (N) : INVALID_REGNUM) +#define EH_RETURN_STACKADJ_RTX gen_rtx_REG (Pmode, 2) + /* This is how to output the definition of a user-level label named NAME, such as the label on a static function or variable NAME. */ diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index 8f6c36b..0d61b8e 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -73,6 +73,7 @@ ;; 10 This is a `sahf' operation. ;; 11 This is a `fstcw' operation ;; 12 This is behaviour of add when setting carry flag. +;; 13 This is a `eh_return' placeholder. ;; For SSE/MMX support: ;; 30 This is `fix', guaranteed to be truncating. @@ -13017,6 +13018,35 @@ "" "ix86_expand_epilogue (0); DONE;") +(define_expand "eh_return" + [(use (match_operand 0 "register_operand" "")) + (use (match_operand 1 "register_operand" ""))] + "" + " +{ + rtx tmp, sa = operands[0], ra = operands[1]; + + /* Tricky bit: we write the address of the handler to which we will + be returning into someone else's stack frame, one word below the + stack address we wish to restore. */ + tmp = gen_rtx_PLUS (Pmode, arg_pointer_rtx, sa); + tmp = plus_constant (tmp, -UNITS_PER_WORD); + tmp = gen_rtx_MEM (Pmode, tmp); + emit_move_insn (tmp, ra); + + emit_insn (gen_eh_return_1 (sa)); + emit_barrier (); + DONE; +}") + +(define_insn_and_split "eh_return_1" + [(unspec_volatile [(match_operand 0 "register_operand" "c")] 13)] + "" + "#" + "reload_completed" + [(const_int 1)] + "ix86_expand_epilogue (2); DONE;") + (define_insn "leave" [(set (reg:SI 7) (reg:SI 6)) (set (reg:SI 6) (mem:SI (pre_dec:SI (reg:SI 7))))] @@ -15754,15 +15784,6 @@ DONE; }") -(define_expand "exception_receiver" - [(const_int 0)] - "flag_pic" - " -{ - load_pic_register (); - DONE; -}") - (define_expand "builtin_setjmp_receiver" [(label_ref (match_operand 0 "" ""))] "flag_pic" diff --git a/gcc/config/i386/linux.h b/gcc/config/i386/linux.h index a5c725a..138a246 100644 --- a/gcc/config/i386/linux.h +++ b/gcc/config/i386/linux.h @@ -188,3 +188,65 @@ Boston, MA 02111-1307, USA. */ } \ while (0) #endif + +/* Do code reading to identify a signal frame, and set the frame + state data appropriately. See unwind-dw2.c for the structs. */ + +#ifdef IN_LIBGCC2 +#include <signal.h> +#include <sys/ucontext.h> +#endif + +#define MD_FALLBACK_FRAME_STATE_FOR(CONTEXT, FS, SUCCESS) \ + do { \ + unsigned char *pc_ = (CONTEXT)->ra; \ + struct sigcontext *sc_; \ + long new_cfa_; \ + \ + /* popl %eax ; movl $__NR_sigreturn,%eax ; int $0x80 */ \ + if (*(unsigned short *)(pc_+0) == 0xb858 \ + && *(unsigned int *)(pc_+2) == 119 \ + && *(unsigned short *)(pc_+6) == 0x80cd) \ + sc_ = (CONTEXT)->cfa + 4; \ + /* movl $__NR_rt_sigreturn,%eax ; int $0x80 */ \ + else if (*(unsigned char *)(pc_+0) == 0xb8 \ + && *(unsigned int *)(pc_+1) == 173 \ + && *(unsigned short *)(pc_+5) == 0x80cd) \ + { \ + struct rt_sigframe { \ + int sig; \ + struct siginfo *pinfo; \ + void *puc; \ + struct siginfo info; \ + struct ucontext uc; \ + } *rt_ = (CONTEXT)->cfa; \ + sc_ = (struct sigcontext *) &rt_->uc.uc_mcontext; \ + } \ + else \ + break; \ + \ + new_cfa_ = sc_->esp; \ + (FS)->cfa_how = CFA_REG_OFFSET; \ + (FS)->cfa_reg = 4; \ + (FS)->cfa_offset = new_cfa_ - (long) (CONTEXT)->cfa; \ + \ + /* The SVR4 register numbering macros aren't usable in libgcc. */ \ + (FS)->regs.reg[0].how = REG_SAVED_OFFSET; \ + (FS)->regs.reg[0].loc.offset = (long)&sc_->eax - new_cfa_; \ + (FS)->regs.reg[3].how = REG_SAVED_OFFSET; \ + (FS)->regs.reg[3].loc.offset = (long)&sc_->ebx - new_cfa_; \ + (FS)->regs.reg[1].how = REG_SAVED_OFFSET; \ + (FS)->regs.reg[1].loc.offset = (long)&sc_->ecx - new_cfa_; \ + (FS)->regs.reg[2].how = REG_SAVED_OFFSET; \ + (FS)->regs.reg[2].loc.offset = (long)&sc_->edx - new_cfa_; \ + (FS)->regs.reg[6].how = REG_SAVED_OFFSET; \ + (FS)->regs.reg[6].loc.offset = (long)&sc_->esi - new_cfa_; \ + (FS)->regs.reg[7].how = REG_SAVED_OFFSET; \ + (FS)->regs.reg[7].loc.offset = (long)&sc_->edi - new_cfa_; \ + (FS)->regs.reg[5].how = REG_SAVED_OFFSET; \ + (FS)->regs.reg[5].loc.offset = (long)&sc_->ebp - new_cfa_; \ + (FS)->regs.reg[8].how = REG_SAVED_OFFSET; \ + (FS)->regs.reg[8].loc.offset = (long)&sc_->eip - new_cfa_; \ + (FS)->retaddr_column = 8; \ + goto SUCCESS; \ + } while (0) |