re PR target/9350 (-fomit-frame-pointer does not work for main)

PR target/9350
        PR target/24374
        * dwarf2out.c (dwarf2out_reg_save_reg): New.
        (dwarf2out_frame_debug_expr): Return after dwarf_handle_frame_unspec.
        * function.c (assign_parms): Use calls.internal_arg_pointer.
        (expand_main_function): Remove FORCE_PREFERRED_STACK_BOUNDARY_IN_MAIN
        code.
        * target-def.h (TARGET_INTERNAL_ARG_POINTER): New.
        (TARGET_CALLS): Add it.
        * target.h (struct gcc_target): Add calls.internal_arg_pointer.
        * targhooks.c (default_internal_arg_pointer): New.
        * targhooks.h (default_internal_arg_pointer): Declare.
        * tree.h (dwarf2out_reg_save_reg): Declare.
        * doc/tm.texi (FORCE_PREFERRED_STACK_BOUNDARY_IN_MAIN): Remove.
        * config/i386/i386.c (dbx_register_map): Add return column.
        (dbx64_register_map, svr4_dbx_register_map): Likewise.
        (TARGET_INTERNAL_ARG_POINTER, ix86_internal_arg_pointer): New.
        (TARGET_DWARF_HANDLE_FRAME_UNSPEC, ix86_dwarf_handle_frame_unspec): New.        (ix86_function_ok_for_sibcall): Disable if force_align_arg_pointer.
        (ix86_save_reg): Save force_align_arg_pointer.
        (ix86_emit_save_regs): Make regno unsigned.
        (ix86_emit_save_regs_using_mov): Likewise.
        (ix86_expand_prologue): Handle force_align_arg_pointer.
        (ix86_expand_epilogue): Likewise.
        * config/i386/i386.h: (dbx_register_map): Update.
        (dbx64_register_map, svr4_dbx_register_map): Update.
        (struct machine_function): Add force_align_arg_pointer.
        * config/i386/i386.md (UNSPEC_REG_SAVE, UNSPEC_DEF_CFA): New.
        (UNSPEC_TP, UNSPEC_TLS_GD, UNSPEC_TLS_LD_BASE): Renumber.
        (TARGET_PUSH_MEMORY peepholes): Disable if RTX_FRAME_RELATED_P.

From-SVN: r106420
This commit is contained in:
Richard Henderson 2005-11-02 17:40:33 -08:00 committed by Richard Henderson
parent 3a0588c4e0
commit 150cdc9e16
12 changed files with 216 additions and 77 deletions

View file

@ -1,3 +1,36 @@
2005-11-02 Richard Henderson <rth@redhat.com>
PR target/9350
PR target/24374
* dwarf2out.c (dwarf2out_reg_save_reg): New.
(dwarf2out_frame_debug_expr): Return after dwarf_handle_frame_unspec.
* function.c (assign_parms): Use calls.internal_arg_pointer.
(expand_main_function): Remove FORCE_PREFERRED_STACK_BOUNDARY_IN_MAIN
code.
* target-def.h (TARGET_INTERNAL_ARG_POINTER): New.
(TARGET_CALLS): Add it.
* target.h (struct gcc_target): Add calls.internal_arg_pointer.
* targhooks.c (default_internal_arg_pointer): New.
* targhooks.h (default_internal_arg_pointer): Declare.
* tree.h (dwarf2out_reg_save_reg): Declare.
* doc/tm.texi (FORCE_PREFERRED_STACK_BOUNDARY_IN_MAIN): Remove.
* config/i386/i386.c (dbx_register_map): Add return column.
(dbx64_register_map, svr4_dbx_register_map): Likewise.
(TARGET_INTERNAL_ARG_POINTER, ix86_internal_arg_pointer): New.
(TARGET_DWARF_HANDLE_FRAME_UNSPEC, ix86_dwarf_handle_frame_unspec): New.
(ix86_function_ok_for_sibcall): Disable if force_align_arg_pointer.
(ix86_save_reg): Save force_align_arg_pointer.
(ix86_emit_save_regs): Make regno unsigned.
(ix86_emit_save_regs_using_mov): Likewise.
(ix86_expand_prologue): Handle force_align_arg_pointer.
(ix86_expand_epilogue): Likewise.
* config/i386/i386.h: (dbx_register_map): Update.
(dbx64_register_map, svr4_dbx_register_map): Update.
(struct machine_function): Add force_align_arg_pointer.
* config/i386/i386.md (UNSPEC_REG_SAVE, UNSPEC_DEF_CFA): New.
(UNSPEC_TP, UNSPEC_TLS_GD, UNSPEC_TLS_LD_BASE): Renumber.
(TARGET_PUSH_MEMORY peepholes): Disable if RTX_FRAME_RELATED_P.
2005-11-02 Jan Hubicka <jh@suse.cz>
PR target/23303

View file

@ -913,6 +913,8 @@ static void ix86_init_builtins (void);
static rtx ix86_expand_builtin (tree, rtx, rtx, enum machine_mode, int);
static const char *ix86_mangle_fundamental_type (tree);
static tree ix86_stack_protect_fail (void);
static rtx ix86_internal_arg_pointer (void);
static void ix86_dwarf_handle_frame_unspec (const char *, rtx, int);
/* This function is only used on Solaris. */
static void i386_solaris_elf_named_section (const char *, unsigned int, tree)
@ -1081,6 +1083,10 @@ static void x86_64_elf_select_section (tree decl, int reloc,
#define TARGET_MUST_PASS_IN_STACK ix86_must_pass_in_stack
#undef TARGET_PASS_BY_REFERENCE
#define TARGET_PASS_BY_REFERENCE ix86_pass_by_reference
#undef TARGET_INTERNAL_ARG_POINTER
#define TARGET_INTERNAL_ARG_POINTER ix86_internal_arg_pointer
#undef TARGET_DWARF_HANDLE_FRAME_UNSPEC
#define TARGET_DWARF_HANDLE_FRAME_UNSPEC ix86_dwarf_handle_frame_unspec
#undef TARGET_GIMPLIFY_VA_ARG_EXPR
#define TARGET_GIMPLIFY_VA_ARG_EXPR ix86_gimplify_va_arg
@ -1987,6 +1993,11 @@ ix86_function_ok_for_sibcall (tree decl, tree exp)
return false;
#endif
/* If we forced aligned the stack, then sibcalling would unalign the
stack, which may break the called function. */
if (cfun->machine->force_align_arg_pointer)
return false;
/* Otherwise okay. That also includes certain types of indirect calls. */
return true;
}
@ -4508,6 +4519,10 @@ ix86_save_reg (unsigned int regno, int maybe_eh_return)
}
}
if (cfun->machine->force_align_arg_pointer
&& regno == REGNO (cfun->machine->force_align_arg_pointer))
return 1;
return (regs_ever_live[regno]
&& !call_used_regs[regno]
&& !fixed_regs[regno]
@ -4719,10 +4734,10 @@ ix86_compute_frame_layout (struct ix86_frame *frame)
static void
ix86_emit_save_regs (void)
{
int regno;
unsigned int regno;
rtx insn;
for (regno = FIRST_PSEUDO_REGISTER - 1; regno >= 0; regno--)
for (regno = FIRST_PSEUDO_REGISTER; regno-- > 0; )
if (ix86_save_reg (regno, true))
{
insn = emit_insn (gen_push (gen_rtx_REG (Pmode, regno)));
@ -4735,7 +4750,7 @@ ix86_emit_save_regs (void)
static void
ix86_emit_save_regs_using_mov (rtx pointer, HOST_WIDE_INT offset)
{
int regno;
unsigned int regno;
rtx insn;
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
@ -4783,6 +4798,47 @@ pro_epilogue_adjust_stack (rtx dest, rtx src, rtx offset, int style)
RTX_FRAME_RELATED_P (insn) = 1;
}
/* Handle the TARGET_INTERNAL_ARG_POINTER hook. */
static rtx
ix86_internal_arg_pointer (void)
{
if (FORCE_PREFERRED_STACK_BOUNDARY_IN_MAIN
&& DECL_NAME (current_function_decl)
&& MAIN_NAME_P (DECL_NAME (current_function_decl))
&& DECL_FILE_SCOPE_P (current_function_decl))
{
cfun->machine->force_align_arg_pointer = gen_rtx_REG (Pmode, 2);
return copy_to_reg (cfun->machine->force_align_arg_pointer);
}
else
return virtual_incoming_args_rtx;
}
/* Handle the TARGET_DWARF_HANDLE_FRAME_UNSPEC hook.
This is called from dwarf2out.c to emit call frame instructions
for frame-related insns containing UNSPECs and UNSPEC_VOLATILEs. */
static void
ix86_dwarf_handle_frame_unspec (const char *label, rtx pattern, int index)
{
rtx unspec = SET_SRC (pattern);
gcc_assert (GET_CODE (unspec) == UNSPEC);
switch (index)
{
case UNSPEC_REG_SAVE:
dwarf2out_reg_save_reg (label, XVECEXP (unspec, 0, 0),
SET_DEST (pattern));
break;
case UNSPEC_DEF_CFA:
dwarf2out_def_cfa (label, REGNO (SET_DEST (pattern)),
INTVAL (XVECEXP (unspec, 0, 0)));
break;
default:
gcc_unreachable ();
}
}
/* Expand the prologue into a bunch of separate insns. */
void
@ -4795,6 +4851,52 @@ ix86_expand_prologue (void)
ix86_compute_frame_layout (&frame);
if (cfun->machine->force_align_arg_pointer)
{
rtx x, y;
/* Grab the argument pointer. */
x = plus_constant (stack_pointer_rtx, 4);
y = cfun->machine->force_align_arg_pointer;
insn = emit_insn (gen_rtx_SET (VOIDmode, y, x));
RTX_FRAME_RELATED_P (insn) = 1;
/* The unwind info consists of two parts: install the fafp as the cfa,
and record the fafp as the "save register" of the stack pointer.
The later is there in order that the unwinder can see where it
should restore the stack pointer across the and insn. */
x = gen_rtx_UNSPEC (VOIDmode, gen_rtvec (1, const0_rtx), UNSPEC_DEF_CFA);
x = gen_rtx_SET (VOIDmode, y, x);
RTX_FRAME_RELATED_P (x) = 1;
y = gen_rtx_UNSPEC (VOIDmode, gen_rtvec (1, stack_pointer_rtx),
UNSPEC_REG_SAVE);
y = gen_rtx_SET (VOIDmode, cfun->machine->force_align_arg_pointer, y);
RTX_FRAME_RELATED_P (y) = 1;
x = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, x, y));
x = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, x, NULL);
REG_NOTES (insn) = x;
/* Align the stack. */
emit_insn (gen_andsi3 (stack_pointer_rtx, stack_pointer_rtx,
GEN_INT (-16)));
/* And here we cheat like madmen with the unwind info. We force the
cfa register back to sp+4, which is exactly what it was at the
start of the function. Re-pushing the return address results in
the return at the same spot relative to the cfa, and thus is
correct wrt the unwind info. */
x = cfun->machine->force_align_arg_pointer;
x = gen_frame_mem (Pmode, plus_constant (x, -4));
insn = emit_insn (gen_push (x));
RTX_FRAME_RELATED_P (insn) = 1;
x = GEN_INT (4);
x = gen_rtx_UNSPEC (VOIDmode, gen_rtvec (1, x), UNSPEC_DEF_CFA);
x = gen_rtx_SET (VOIDmode, stack_pointer_rtx, x);
x = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, x, NULL);
REG_NOTES (insn) = x;
}
/* Note: AT&T enter does NOT have reversed args. Enter is probably
slower on all targets. Also sdb doesn't like it. */
@ -5072,6 +5174,13 @@ ix86_expand_epilogue (int style)
}
}
if (cfun->machine->force_align_arg_pointer)
{
emit_insn (gen_addsi3 (stack_pointer_rtx,
cfun->machine->force_align_arg_pointer,
GEN_INT (-4)));
}
/* Sibcall epilogues don't want a return instruction. */
if (style == 0)
return;

View file

@ -2263,6 +2263,7 @@ struct machine_function GTY(())
{
struct stack_local_entry *stack_locals;
const char *some_ld_name;
rtx force_align_arg_pointer;
int save_varrargs_registers;
int accesses_prev_frame;
int optimize_mode_switching[MAX_386_ENTITIES];

View file

@ -66,11 +66,13 @@
(UNSPEC_STACK_ALLOC 11)
(UNSPEC_SET_GOT 12)
(UNSPEC_SSE_PROLOGUE_SAVE 13)
(UNSPEC_REG_SAVE 14)
(UNSPEC_DEF_CFA 15)
; TLS support
(UNSPEC_TP 15)
(UNSPEC_TLS_GD 16)
(UNSPEC_TLS_LD_BASE 17)
(UNSPEC_TP 16)
(UNSPEC_TLS_GD 17)
(UNSPEC_TLS_LD_BASE 18)
; Other random patterns
(UNSPEC_SCAS 20)
@ -18934,7 +18936,8 @@
[(set (match_operand:SI 0 "push_operand" "")
(match_operand:SI 1 "memory_operand" ""))
(match_scratch:SI 2 "r")]
"! optimize_size && ! TARGET_PUSH_MEMORY"
"!optimize_size && !TARGET_PUSH_MEMORY
&& !RTX_FRAME_RELATED_P (peep2_next_insn (0))"
[(set (match_dup 2) (match_dup 1))
(set (match_dup 0) (match_dup 2))]
"")
@ -18943,7 +18946,8 @@
[(set (match_operand:DI 0 "push_operand" "")
(match_operand:DI 1 "memory_operand" ""))
(match_scratch:DI 2 "r")]
"! optimize_size && ! TARGET_PUSH_MEMORY"
"!optimize_size && !TARGET_PUSH_MEMORY
&& !RTX_FRAME_RELATED_P (peep2_next_insn (0))"
[(set (match_dup 2) (match_dup 1))
(set (match_dup 0) (match_dup 2))]
"")
@ -18954,7 +18958,8 @@
[(set (match_operand:SF 0 "push_operand" "")
(match_operand:SF 1 "memory_operand" ""))
(match_scratch:SF 2 "r")]
"! optimize_size && ! TARGET_PUSH_MEMORY"
"!optimize_size && !TARGET_PUSH_MEMORY
&& !RTX_FRAME_RELATED_P (peep2_next_insn (0))"
[(set (match_dup 2) (match_dup 1))
(set (match_dup 0) (match_dup 2))]
"")
@ -18963,7 +18968,8 @@
[(set (match_operand:HI 0 "push_operand" "")
(match_operand:HI 1 "memory_operand" ""))
(match_scratch:HI 2 "r")]
"! optimize_size && ! TARGET_PUSH_MEMORY"
"!optimize_size && !TARGET_PUSH_MEMORY
&& !RTX_FRAME_RELATED_P (peep2_next_insn (0))"
[(set (match_dup 2) (match_dup 1))
(set (match_dup 0) (match_dup 2))]
"")
@ -18972,7 +18978,8 @@
[(set (match_operand:QI 0 "push_operand" "")
(match_operand:QI 1 "memory_operand" ""))
(match_scratch:QI 2 "q")]
"! optimize_size && ! TARGET_PUSH_MEMORY"
"!optimize_size && !TARGET_PUSH_MEMORY
&& !RTX_FRAME_RELATED_P (peep2_next_insn (0))"
[(set (match_dup 2) (match_dup 1))
(set (match_dup 0) (match_dup 2))]
"")

View file

@ -1033,18 +1033,6 @@ macro must evaluate to a value equal to or larger than
@code{STACK_BOUNDARY}.
@end defmac
@defmac FORCE_PREFERRED_STACK_BOUNDARY_IN_MAIN
A C expression that evaluates true if @code{PREFERRED_STACK_BOUNDARY} is
not guaranteed by the runtime and we should emit code to align the stack
at the beginning of @code{main}.
@cindex @code{PUSH_ROUNDING}, interaction with @code{PREFERRED_STACK_BOUNDARY}
If @code{PUSH_ROUNDING} is not defined, the stack will always be aligned
to the specified boundary. If @code{PUSH_ROUNDING} is defined and specifies
a less strict alignment than @code{PREFERRED_STACK_BOUNDARY}, the stack may
be momentarily unaligned while pushing arguments.
@end defmac
@defmac FUNCTION_BOUNDARY
Alignment required for a function entry point, in bits.
@end defmac

View file

@ -1271,6 +1271,30 @@ clobbers_queued_reg_save (rtx insn)
return false;
}
/* Entry point for saving the first register into the second. */
void
dwarf2out_reg_save_reg (const char *label, rtx reg, rtx sreg)
{
size_t i;
unsigned int regno, sregno;
for (i = 0; i < num_regs_saved_in_regs; i++)
if (REGNO (regs_saved_in_regs[i].orig_reg) == REGNO (reg))
break;
if (i == num_regs_saved_in_regs)
{
gcc_assert (i != ARRAY_SIZE (regs_saved_in_regs));
num_regs_saved_in_regs++;
}
regs_saved_in_regs[i].orig_reg = reg;
regs_saved_in_regs[i].saved_in_reg = sreg;
regno = DWARF_FRAME_REGNUM (REGNO (reg));
sregno = DWARF_FRAME_REGNUM (REGNO (sreg));
reg_save (label, regno, sregno, 0);
}
/* What register, if any, is currently saved in REG? */
static rtx
@ -1659,7 +1683,7 @@ dwarf2out_frame_debug_expr (rtx expr, const char *label)
case UNSPEC_VOLATILE:
gcc_assert (targetm.dwarf_handle_frame_unspec);
targetm.dwarf_handle_frame_unspec (label, expr, XINT (src, 1));
break;
return;
default:
gcc_unreachable ();

View file

@ -2894,22 +2894,9 @@ assign_parms (tree fndecl)
{
struct assign_parm_data_all all;
tree fnargs, parm;
rtx internal_arg_pointer;
/* If the reg that the virtual arg pointer will be translated into is
not a fixed reg or is the stack pointer, make a copy of the virtual
arg pointer, and address parms via the copy. The frame pointer is
considered fixed even though it is not marked as such.
The second time through, simply use ap to avoid generating rtx. */
if ((ARG_POINTER_REGNUM == STACK_POINTER_REGNUM
|| ! (fixed_regs[ARG_POINTER_REGNUM]
|| ARG_POINTER_REGNUM == FRAME_POINTER_REGNUM)))
internal_arg_pointer = copy_to_reg (virtual_incoming_args_rtx);
else
internal_arg_pointer = virtual_incoming_args_rtx;
current_function_internal_arg_pointer = internal_arg_pointer;
current_function_internal_arg_pointer
= targetm.calls.internal_arg_pointer ();
assign_parms_initialize_all (&all);
fnargs = assign_parms_augmented_arg_list (&all);
@ -3916,42 +3903,6 @@ struct tree_opt_pass pass_init_function =
void
expand_main_function (void)
{
#ifdef FORCE_PREFERRED_STACK_BOUNDARY_IN_MAIN
if (FORCE_PREFERRED_STACK_BOUNDARY_IN_MAIN)
{
int align = PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT;
rtx tmp, seq;
start_sequence ();
/* Forcibly align the stack. */
#ifdef STACK_GROWS_DOWNWARD
tmp = expand_simple_binop (Pmode, AND, stack_pointer_rtx, GEN_INT(-align),
stack_pointer_rtx, 1, OPTAB_WIDEN);
#else
tmp = expand_simple_binop (Pmode, PLUS, stack_pointer_rtx,
GEN_INT (align - 1), NULL_RTX, 1, OPTAB_WIDEN);
tmp = expand_simple_binop (Pmode, AND, tmp, GEN_INT (-align),
stack_pointer_rtx, 1, OPTAB_WIDEN);
#endif
if (tmp != stack_pointer_rtx)
emit_move_insn (stack_pointer_rtx, tmp);
/* Enlist allocate_dynamic_stack_space to pick up the pieces. */
tmp = force_reg (Pmode, const0_rtx);
allocate_dynamic_stack_space (tmp, NULL_RTX, BIGGEST_ALIGNMENT);
seq = get_insns ();
end_sequence ();
for (tmp = get_last_insn (); tmp; tmp = PREV_INSN (tmp))
if (NOTE_P (tmp) && NOTE_LINE_NUMBER (tmp) == NOTE_INSN_FUNCTION_BEG)
break;
if (tmp)
emit_insn_before (seq, tmp);
else
emit_insn (seq);
}
#endif
#if (defined(INVOKE__main) \
|| (!defined(HAS_INIT_SECTION) \
&& !defined(INIT_SECTION_ASM_OP) \

View file

@ -445,6 +445,7 @@ Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#define TARGET_ARG_PARTIAL_BYTES hook_int_CUMULATIVE_ARGS_mode_tree_bool_0
#define TARGET_FUNCTION_VALUE default_function_value
#define TARGET_INTERNAL_ARG_POINTER default_internal_arg_pointer
#define TARGET_CALLS { \
TARGET_PROMOTE_FUNCTION_ARGS, \
@ -463,7 +464,8 @@ Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
TARGET_CALLEE_COPIES, \
TARGET_ARG_PARTIAL_BYTES, \
TARGET_INVALID_ARG_FOR_UNPROTOTYPED_FN, \
TARGET_FUNCTION_VALUE \
TARGET_FUNCTION_VALUE, \
TARGET_INTERNAL_ARG_POINTER \
}
#ifndef TARGET_UNWIND_TABLES_DEFAULT

View file

@ -613,6 +613,10 @@ struct gcc_target
specified by FN_DECL_OR_TYPE with a return type of RET_TYPE. */
rtx (*function_value) (tree ret_type, tree fn_decl_or_type,
bool outgoing);
/* Return an rtx for the argument pointer incoming to the
current function. */
rtx (*internal_arg_pointer) (void);
} calls;
/* Return the diagnostic message string if conversion from FROMTYPE

View file

@ -62,6 +62,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
#include "tm_p.h"
#include "target-def.h"
#include "ggc.h"
#include "hard-reg-set.h"
void
@ -439,4 +440,19 @@ default_function_value (tree ret_type ATTRIBUTE_UNUSED,
#endif
}
rtx
default_internal_arg_pointer (void)
{
/* If the reg that the virtual arg pointer will be translated into is
not a fixed reg or is the stack pointer, make a copy of the virtual
arg pointer, and address parms via the copy. The frame pointer is
considered fixed even though it is not marked as such. */
if ((ARG_POINTER_REGNUM == STACK_POINTER_REGNUM
|| ! (fixed_regs[ARG_POINTER_REGNUM]
|| ARG_POINTER_REGNUM == FRAME_POINTER_REGNUM)))
return copy_to_reg (virtual_incoming_args_rtx);
else
return virtual_incoming_args_rtx;
}
#include "gt-targhooks.h"

View file

@ -68,4 +68,4 @@ extern const char *hook_invalid_arg_for_unprototyped_fn
(tree, tree, tree);
extern bool hook_bool_rtx_commutative_p (rtx, int);
extern rtx default_function_value (tree, tree, bool);
extern rtx default_internal_arg_pointer (void);

View file

@ -4119,6 +4119,10 @@ extern void dwarf2out_return_save (const char *, HOST_WIDE_INT);
extern void dwarf2out_return_reg (const char *, unsigned);
/* Entry point for saving the first register into the second. */
extern void dwarf2out_reg_save_reg (const char *, rtx, rtx);
/* In tree-inline.c */
/* The type of a set of already-visited pointers. Functions for creating