From 4dd2ac2c3546edfcfb2bcba303378dd59c51e70a Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Sat, 24 Feb 2001 03:34:05 +0100 Subject: [PATCH] i386.c (ix86_frame): New structure. * i386.c (ix86_frame): New structure. (ix86_compute_frame_size): Kill. (ix86_compute_frame_layout): New. (ix86_save_reg): New. (ix86_can_use_return_insn_p): Use frame layout stuff. (ix86_expand_prologue): Likewise. (ix86_expand_epilogue): Likewise. (ix86_initial_elimination_offset): Likewise. (ix86_nsaved_regs): Use ix86_save_reg. (ix86_emit_save_regs): Likewise. From-SVN: r40022 --- gcc/ChangeLog | 13 ++ gcc/config/i386/i386.c | 281 ++++++++++++++++++++++------------------- 2 files changed, 161 insertions(+), 133 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index d3f1da5600f..5699d93605e 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,16 @@ +Sat Feb 24 03:32:50 CET 2001 Jan Hubicka + + * i386.c (ix86_frame): New structure. + (ix86_compute_frame_size): Kill. + (ix86_compute_frame_layout): New. + (ix86_save_reg): New. + (ix86_can_use_return_insn_p): Use frame layout stuff. + (ix86_expand_prologue): Likewise. + (ix86_expand_epilogue): Likewise. + (ix86_initial_elimination_offset): Likewise. + (ix86_nsaved_regs): Use ix86_save_reg. + (ix86_emit_save_regs): Likewise. + Sat Feb 24 03:30:38 CET 2001 Jan Hubicka * flow.c (find_sub_basic_blocks): New function. diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index 74565198ab8..e90cc0da6c1 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -402,6 +402,40 @@ struct machine_function #define ix86_stack_locals (cfun->machine->stack_locals) +/* Structure describing stack frame layout. + Stack grows downward: + + [arguments] + <- ARG_POINTER + saved pc + + saved frame pointer if frame_pointer_needed + <- HARD_FRAME_POINTER + [saved regs] + + [padding1] \ + ) + [va_arg registers] ( + > to_allocate <- FRAME_POINTER + [frame] ( + ) + [padding2] / + */ +struct ix86_frame +{ + int nregs; + int padding1; + HOST_WIDE_INT frame; + int padding2; + int outgoing_arguments_size; + + HOST_WIDE_INT to_allocate; + /* The offsets relative to ARG_POINTER. */ + HOST_WIDE_INT frame_pointer_offset; + HOST_WIDE_INT hard_frame_pointer_offset; + HOST_WIDE_INT stack_pointer_offset; +}; + /* which cpu are we scheduling for */ enum processor_type ix86_cpu; @@ -469,8 +503,6 @@ static void ix86_mark_machine_status PARAMS ((struct function *)); static void ix86_free_machine_status PARAMS ((struct function *)); static int ix86_split_to_parts PARAMS ((rtx, rtx *, enum machine_mode)); static int ix86_safe_length_prefix PARAMS ((rtx)); -static HOST_WIDE_INT ix86_compute_frame_size PARAMS((HOST_WIDE_INT, - int *, int *, int *)); 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)); @@ -508,6 +540,8 @@ 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 void ix86_compute_frame_layout PARAMS ((struct ix86_frame *)); /* Sometimes certain combinations of command options do not make sense on a particular target machine. You can define a macro @@ -1667,8 +1701,7 @@ symbolic_reference_mentioned_p (op) int ix86_can_use_return_insn_p () { - HOST_WIDE_INT tsize; - int nregs; + struct ix86_frame frame; #ifdef NON_SAVING_SETJMP if (NON_SAVING_SETJMP && current_function_calls_setjmp) @@ -1688,8 +1721,8 @@ ix86_can_use_return_insn_p () && current_function_args_size >= 32768) return 0; - tsize = ix86_compute_frame_size (get_frame_size (), &nregs, NULL, NULL); - return tsize == 0 && nregs == 0; + ix86_compute_frame_layout (&frame); + return frame.to_allocate == 0 && frame.nregs == 0; } /* Value should be nonzero if functions must have frame pointers. @@ -1817,24 +1850,31 @@ gen_push (arg) 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); + 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)); + +} + /* Return number of registers to be saved on the stack. */ static int ix86_nsaved_regs () { int nregs = 0; - int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table - || current_function_uses_const_pool); - int limit = (frame_pointer_needed - ? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM); int regno; - for (regno = limit - 1; regno >= 0; regno--) - if ((regs_ever_live[regno] && ! call_used_regs[regno]) - || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used)) - { - nregs ++; - } + for (regno = FIRST_PSEUDO_REGISTER - 1; regno >= 0; regno--) + if (ix86_save_reg (regno)) + nregs++; return nregs; } @@ -1846,82 +1886,46 @@ ix86_initial_elimination_offset (from, to) int from; int to; { - int padding1; - int nregs; - - /* Stack grows downward: - - [arguments] - <- ARG_POINTER - saved pc - - saved frame pointer if frame_pointer_needed - <- HARD_FRAME_POINTER - [saved regs] - - [padding1] \ - | <- FRAME_POINTER - [frame] > tsize - | - [padding2] / - */ + struct ix86_frame frame; + ix86_compute_frame_layout (&frame); if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM) - /* Skip saved PC and previous frame pointer. - Executed only when frame_pointer_needed. */ - return 8; + return frame.hard_frame_pointer_offset; else if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM) - { - ix86_compute_frame_size (get_frame_size (), &nregs, &padding1, (int *) 0); - padding1 += nregs * UNITS_PER_WORD; - return -padding1; - } + return frame.hard_frame_pointer_offset - frame.frame_pointer_offset; else { - /* ARG_POINTER or FRAME_POINTER to STACK_POINTER elimination. */ - int frame_size = frame_pointer_needed ? 8 : 4; - HOST_WIDE_INT tsize = ix86_compute_frame_size (get_frame_size (), - &nregs, &padding1, (int *) 0); - if (to != STACK_POINTER_REGNUM) abort (); else if (from == ARG_POINTER_REGNUM) - return tsize + nregs * UNITS_PER_WORD + frame_size; + return frame.stack_pointer_offset; else if (from != FRAME_POINTER_REGNUM) abort (); else - return tsize - padding1; + return frame.stack_pointer_offset - frame.frame_pointer_offset; } } -/* Compute the size of local storage taking into consideration the - desired stack alignment which is to be maintained. Also determine - the number of registers saved below the local storage. +/* Fill structure ix86_frame about frame of currently computed function. */ - PADDING1 returns padding before stack frame and PADDING2 returns - padding after stack frame; - */ - -static HOST_WIDE_INT -ix86_compute_frame_size (size, nregs_on_stack, rpadding1, rpadding2) - HOST_WIDE_INT size; - int *nregs_on_stack; - int *rpadding1; - int *rpadding2; +static void +ix86_compute_frame_layout (frame) + struct ix86_frame *frame; { - int nregs; - int padding1 = 0; - int padding2 = 0; HOST_WIDE_INT total_size; int stack_alignment_needed = cfun->stack_alignment_needed / BITS_PER_UNIT; int offset; int preferred_alignment = cfun->preferred_stack_boundary / BITS_PER_UNIT; + HOST_WIDE_INT size = get_frame_size (); - nregs = ix86_nsaved_regs (); + frame->nregs = ix86_nsaved_regs (); total_size = size; - offset = frame_pointer_needed ? 8 : 4; + /* Skip return value and save base pointer. */ + offset = frame_pointer_needed ? UNITS_PER_WORD * 2 : UNITS_PER_WORD; + + frame->hard_frame_pointer_offset = offset; /* Do some sanity checking of stack_alignment_needed and preferred_alignment, since i386 port is the only using those features @@ -1936,36 +1940,58 @@ ix86_compute_frame_size (size, nregs_on_stack, rpadding1, rpadding2) if (stack_alignment_needed > PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT) abort (); - if (stack_alignment_needed < 4) - stack_alignment_needed = 4; + if (stack_alignment_needed < STACK_BOUNDARY / BITS_PER_UNIT) + stack_alignment_needed = STACK_BOUNDARY / BITS_PER_UNIT; - offset += nregs * UNITS_PER_WORD; + /* Register save area */ + offset += frame->nregs * UNITS_PER_WORD; - if (ACCUMULATE_OUTGOING_ARGS) - total_size += current_function_outgoing_args_size; + /* Align start of frame for local function. */ + frame->padding1 = ((offset + stack_alignment_needed - 1) + & -stack_alignment_needed) - offset; - total_size += offset; + offset += frame->padding1; - /* Align start of frame for local function. */ - padding1 = ((offset + stack_alignment_needed - 1) - & -stack_alignment_needed) - offset; - total_size += padding1; + /* Frame pointer points here. */ + frame->frame_pointer_offset = offset; - /* Align stack boundary. */ - padding2 = ((total_size + preferred_alignment - 1) - & -preferred_alignment) - total_size; + offset += size; + /* Add outgoing arguments area. */ if (ACCUMULATE_OUTGOING_ARGS) - padding2 += current_function_outgoing_args_size; - - if (nregs_on_stack) - *nregs_on_stack = nregs; - if (rpadding1) - *rpadding1 = padding1; - if (rpadding2) - *rpadding2 = padding2; + { + offset += current_function_outgoing_args_size; + frame->outgoing_arguments_size = current_function_outgoing_args_size; + } + else + frame->outgoing_arguments_size = 0; - return size + padding1 + padding2; + /* Align stack boundary. */ + frame->padding2 = ((offset + preferred_alignment - 1) + & -preferred_alignment) - offset; + + offset += frame->padding2; + + /* We've reached end of stack frame. */ + frame->stack_pointer_offset = offset; + + /* Size prologue needs to allocate. */ + frame->to_allocate = + (size + frame->padding1 + frame->padding2 + + frame->outgoing_arguments_size); + +#if 0 + fprintf (stderr, "nregs: %i\n", frame->nregs); + fprintf (stderr, "size: %i\n", size); + fprintf (stderr, "alignment1: %i\n", stack_alignment_needed); + fprintf (stderr, "padding1: %i\n", frame->padding1); + fprintf (stderr, "padding2: %i\n", frame->padding2); + fprintf (stderr, "to_allocate: %i\n", frame->to_allocate); + fprintf (stderr, "frame_pointer_offset: %i\n", frame->frame_pointer_offset); + fprintf (stderr, "hard_frame_pointer_offset: %i\n", + frame->hard_frame_pointer_offset); + fprintf (stderr, "stack_pointer_offset: %i\n", frame->stack_pointer_offset); +#endif } /* Emit code to save registers in the prologue. */ @@ -1974,16 +2000,10 @@ static void ix86_emit_save_regs () { register int regno; - int limit; rtx insn; - int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table - || current_function_uses_const_pool); - limit = (frame_pointer_needed - ? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM); - for (regno = limit - 1; regno >= 0; regno--) - if ((regs_ever_live[regno] && !call_used_regs[regno]) - || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used)) + for (regno = FIRST_PSEUDO_REGISTER - 1; regno >= 0; regno--) + if (ix86_save_reg (regno)) { insn = emit_insn (gen_push (gen_rtx_REG (SImode, regno))); RTX_FRAME_RELATED_P (insn) = 1; @@ -1995,11 +2015,12 @@ ix86_emit_save_regs () void ix86_expand_prologue () { - HOST_WIDE_INT tsize = ix86_compute_frame_size (get_frame_size (), (int *) 0, - (int *) 0, (int *) 0); rtx insn; int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table || current_function_uses_const_pool); + struct ix86_frame frame; + + ix86_compute_frame_layout (&frame); /* Note: AT&T enter does NOT have reversed args. Enter is probably slower on all targets. Also sdb doesn't like it. */ @@ -2015,17 +2036,17 @@ ix86_expand_prologue () ix86_emit_save_regs (); - if (tsize == 0) + if (frame.to_allocate == 0) ; - else if (! TARGET_STACK_PROBE || tsize < CHECK_STACK_LIMIT) + else if (! TARGET_STACK_PROBE || frame.to_allocate < CHECK_STACK_LIMIT) { if (frame_pointer_needed) insn = emit_insn (gen_pro_epilogue_adjust_stack (stack_pointer_rtx, stack_pointer_rtx, - GEN_INT (-tsize), hard_frame_pointer_rtx)); + GEN_INT (-frame.to_allocate), hard_frame_pointer_rtx)); else insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, - GEN_INT (-tsize))); + GEN_INT (-frame.to_allocate))); RTX_FRAME_RELATED_P (insn) = 1; } else @@ -2035,7 +2056,7 @@ ix86_expand_prologue () rtx arg0, sym; arg0 = gen_rtx_REG (SImode, 0); - emit_move_insn (arg0, GEN_INT (tsize)); + emit_move_insn (arg0, GEN_INT (frame.to_allocate)); sym = gen_rtx_MEM (FUNCTION_MODE, gen_rtx_SYMBOL_REF (Pmode, "_alloca")); @@ -2087,20 +2108,15 @@ ix86_emit_restore_regs_using_mov (pointer, offset) int offset; { int regno; - int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table - || current_function_uses_const_pool); - int limit = (frame_pointer_needed - ? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM); - for (regno = 0; regno < limit; regno++) - if ((regs_ever_live[regno] && !call_used_regs[regno]) - || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used)) + for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) + if (ix86_save_reg (regno)) { - emit_move_insn (gen_rtx_REG (SImode, regno), - adj_offsettable_operand (gen_rtx_MEM (SImode, + emit_move_insn (gen_rtx_REG (Pmode, regno), + adj_offsettable_operand (gen_rtx_MEM (Pmode, pointer), offset)); - offset += 4; + offset += UNITS_PER_WORD; } } @@ -2110,18 +2126,15 @@ void ix86_expand_epilogue (emit_return) int emit_return; { - int nregs; int regno; - - int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table - || current_function_uses_const_pool); int sp_valid = !frame_pointer_needed || current_function_sp_is_unchanging; + struct ix86_frame frame; HOST_WIDE_INT offset; - HOST_WIDE_INT tsize = ix86_compute_frame_size (get_frame_size (), &nregs, - (int *) 0, (int *) 0); + + ix86_compute_frame_layout (&frame); /* Calculate start of saved registers relative to ebp. */ - offset = -nregs * UNITS_PER_WORD; + offset = -frame.nregs * UNITS_PER_WORD; #ifdef FUNCTION_BLOCK_PROFILER_EXIT if (profile_block_flag == 2) @@ -2140,10 +2153,10 @@ ix86_expand_epilogue (emit_return) are no registers to restore. We also use this code when TARGET_USE_LEAVE and there is exactly one register to pop. This heruistic may need some tuning in future. */ - if ((!sp_valid && nregs <= 1) - || (frame_pointer_needed && !nregs && tsize) + if ((!sp_valid && frame.nregs <= 1) + || (frame_pointer_needed && !frame.nregs && frame.to_allocate) || (frame_pointer_needed && TARGET_USE_LEAVE && !optimize_size - && nregs == 1)) + && frame.nregs == 1)) { /* Restore registers. We can use ebp or esp to address the memory locations. If both are available, default to ebp, since offsets @@ -2151,13 +2164,14 @@ ix86_expand_epilogue (emit_return) end of block of saved registers, where we may simplify addressing mode. */ - if (!frame_pointer_needed || (sp_valid && !tsize)) - ix86_emit_restore_regs_using_mov (stack_pointer_rtx, tsize); + if (!frame_pointer_needed || (sp_valid && !frame.to_allocate)) + ix86_emit_restore_regs_using_mov (stack_pointer_rtx, frame.to_allocate); else ix86_emit_restore_regs_using_mov (hard_frame_pointer_rtx, offset); if (!frame_pointer_needed) - ix86_emit_epilogue_esp_adjustment (tsize + nregs * UNITS_PER_WORD); + 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 (gen_leave ()); @@ -2183,13 +2197,14 @@ ix86_expand_epilogue (emit_return) GEN_INT (offset), hard_frame_pointer_rtx)); } - else if (tsize) - ix86_emit_epilogue_esp_adjustment (tsize); + else if (frame.to_allocate) + ix86_emit_epilogue_esp_adjustment (frame.to_allocate); - for (regno = 0; regno < STACK_POINTER_REGNUM; regno++) - if ((regs_ever_live[regno] && !call_used_regs[regno]) - || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used)) + for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) + if (ix86_save_reg (regno)) emit_insn (gen_popsi1 (gen_rtx_REG (SImode, regno))); + if (frame_pointer_needed) + emit_insn (gen_popsi1 (hard_frame_pointer_rtx)); } /* Sibcall epilogues don't want a return instruction. */ -- 2.30.2