--- config/alpha/alpha.h.x Mon Sep 29 02:02:34 1997 +++ config/alpha/alpha.h Mon Sep 29 02:33:40 1997 @@ -378,9 +378,11 @@ extern void override_options (); Likewise, we use $f31 for the frame pointer, which will always be eliminated in favor of the hardware frame pointer or the - stack pointer. */ + stack pointer. -#define FIRST_PSEUDO_REGISTER 64 + Finally, we use 64 for the return address pointer elimination target. */ + +#define FIRST_PSEUDO_REGISTER 65 /* 1 for registers that have pervasive standard uses and are not available for the register allocator. */ @@ -389,7 +391,7 @@ extern void override_options (); {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, \ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 } + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1 } /* 1 for registers not available across function calls. These must include the FIXED_REGISTERS and also any @@ -401,7 +403,7 @@ extern void override_options (); {1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, \ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, \ 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, \ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } /* List the order in which to allocate registers. Each register must be listed once, even those in FIXED_REGISTERS. @@ -442,7 +444,7 @@ extern void override_options (); 26, \ 15, \ 29, \ - 30, 31, 63 } + 30, 31, 63, 64 } /* Return number of consecutive hard regs needed starting at reg REGNO to hold something of mode MODE. @@ -496,6 +498,10 @@ extern int alpha_frame_pointer_required; /* Base register for access to local variables of function. */ #define FRAME_POINTER_REGNUM 63 +/* Fake register that holds the address on the stack of the current + function's return address. */ +#define RETURN_ADDRESS_POINTER_REGNUM 64 + /* Register in which static-chain is passed to a function. For the Alpha, this is based on an example; the calling sequence @@ -771,11 +777,13 @@ enum reg_class { NO_REGS, GENERAL_REGS, followed by "to". Eliminations of the same "from" register are listed in order of preference. */ -#define ELIMINABLE_REGS \ -{{ ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ - { ARG_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}, \ - { FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ - { FRAME_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}} +#define ELIMINABLE_REGS \ +{{ ARG_POINTER_REGNUM, STACK_POINTER_REGNUM }, \ + { ARG_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM }, \ + { FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM }, \ + { FRAME_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM }, \ + { RETURN_ADDRESS_POINTER_REGNUM, STACK_POINTER_REGNUM }, \ + { RETURN_ADDRESS_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM }} /* Given FROM and TO register numbers, say whether this elimination is allowed. Frame pointer elimination is automatically handled. @@ -783,7 +791,8 @@ enum reg_class { NO_REGS, GENERAL_REGS, All eliminations are valid since the cases where FP can't be eliminated are already handled. */ -#define CAN_ELIMINATE(FROM, TO) 1 +#define CAN_ELIMINATE(FROM, TO) \ + (!frame_pointer_needed || (TO) == HARD_FRAME_POINTER_REGNUM) /* Round up to a multiple of 16 bytes. */ #define ALPHA_ROUND(X) (((X) + 15) & ~ 15) @@ -791,16 +800,24 @@ enum reg_class { NO_REGS, GENERAL_REGS, /* Define the offset between two registers, one to be eliminated, and the other its replacement, at the start of a routine. */ #define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \ -{ if ((FROM) == FRAME_POINTER_REGNUM) \ - (OFFSET) = (ALPHA_ROUND (current_function_outgoing_args_size) \ - + alpha_sa_size ()); \ - else if ((FROM) == ARG_POINTER_REGNUM) \ - (OFFSET) = (ALPHA_ROUND (current_function_outgoing_args_size) \ - + alpha_sa_size () \ - + (ALPHA_ROUND (get_frame_size () \ - + current_function_pretend_args_size) \ - - current_function_pretend_args_size)); \ -} +do { \ + (OFFSET) = 0; \ + switch (FROM) \ + { \ + default: \ + abort(); \ + \ + /* Accumulate by falling through the rest. */ \ + case ARG_POINTER_REGNUM: \ + (OFFSET) += (ALPHA_ROUND (get_frame_size () \ + + current_function_pretend_args_size) \ + - current_function_pretend_args_size); \ + case FRAME_POINTER_REGNUM: \ + (OFFSET) += alpha_sa_size (); \ + case RETURN_ADDRESS_POINTER_REGNUM: \ + (OFFSET) += ALPHA_ROUND (current_function_outgoing_args_size); \ + } \ +} while (0) /* Define this if stack space is still allocated for a parameter passed in a register. */ @@ -1178,9 +1195,26 @@ __enable_execute_stack (addr) \ FRAMEADDR is the frame pointer of the COUNT frame, or the frame pointer of the COUNT-1 frame if RETURN_ADDR_IN_PREVIOUS_FRAME} is defined. */ -#define RETURN_ADDR_RTX alpha_return_addr_rtx +/* Sadly, the exception handling bits expect this to be a *writable* + value, so we can't use the trick of copying $26 to a pseudo at the + beginning of the function -- unless we can somehow arrange for it + to get copied back at the end. Messy messy. + + So we do elimiation to the stack slot instead. */ + +extern int alpha_function_save_ra; + +#define RETURN_ADDR_RTX(COUNT, FRAME) \ + ((COUNT) == 0 \ + ? alpha_function_save_ra = 1, \ + gen_rtx (MEM, Pmode, \ + gen_rtx (REG, Pmode, RETURN_ADDRESS_POINTER_REGNUM)) \ + : const0_rtx) + +/* Initialize data used by insn expanders. This is called from init_emit, + once for each function, before code is generated. */ -extern struct rtx_def *alpha_return_addr_rtx ( /* int count, rtx frame */ ); +#define INIT_EXPANDERS alpha_init_expanders() /* Addressing modes, and classification of registers for them. */ @@ -1200,9 +1234,12 @@ extern struct rtx_def *alpha_return_addr has been allocated, which happens in local-alloc.c. */ #define REGNO_OK_FOR_INDEX_P(REGNO) 0 -#define REGNO_OK_FOR_BASE_P(REGNO) \ -((REGNO) < 32 || (unsigned) reg_renumber[REGNO] < 32 \ - || (REGNO) == 63 || reg_renumber[REGNO] == 63) +#define REGNO_OK_FOR_BASE_P(REGNO) \ + ((REGNO) < 32 || (unsigned) reg_renumber[REGNO] < 32 \ + || (REGNO) == FRAME_POINTER_REGNUM \ + || reg_renumber[REGNO] == FRAME_POINTER_REGNUM \ + || (REGNO) == RETURN_ADDRESS_POINTER_REGNUM \ + || reg_renumber[REGNO] == RETURN_ADDRESS_POINTER_REGNUM) /* Maximum number of registers that can appear in a valid memory address. */ #define MAX_REGS_PER_ADDRESS 1 @@ -1242,8 +1279,11 @@ extern struct rtx_def *alpha_return_addr #define REG_OK_FOR_INDEX_P(X) 0 /* Nonzero if X is a hard reg that can be used as a base reg or if it is a pseudo reg. */ -#define REG_OK_FOR_BASE_P(X) \ - (REGNO (X) < 32 || REGNO (X) == 63 || REGNO (X) >= FIRST_PSEUDO_REGISTER) +#define REG_OK_FOR_BASE_P(X) \ + (REGNO (X) < 32 \ + || REGNO (X) == FRAME_POINTER_REGNUM \ + || REGNO (X) == RETURN_ADDRESS_POINTER_REGNUM \ + || REGNO (X) >= FIRST_PSEUDO_REGISTER) #else @@ -1659,7 +1699,7 @@ literal_section () \ "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", "$f8", \ "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15", \ "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23",\ - "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "FP"} + "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "FP", "RAP" } /* How to renumber registers for dbx and gdb. */ --- config/alpha/alpha.c.x Mon Sep 29 02:22:15 1997 +++ config/alpha/alpha.c Mon Sep 29 02:47:48 1997 @@ -38,6 +38,7 @@ Boston, MA 02111-1307, USA. */ #include "expr.h" #include "obstack.h" #include "tree.h" +#include "function.h" enum alpha_trap_precision alpha_tp; enum alpha_fp_rounding_mode alpha_fprm; @@ -71,6 +72,10 @@ static int trap_pending = 0; int alpha_function_needs_gp; +/* Nonzero if the current function needs ra to be saved. */ + +int alpha_function_save_ra; + /* Nonzero if the current function is forcing a frame pointer. */ int alpha_frame_pointer_required; @@ -1096,6 +1101,50 @@ alpha_adjust_cost (insn, link, dep_insn, return cost; } +/* Functions to save and restore alpha_function_save_ra. These will + be called, via pointer variables, from push_function_context and + pop_function_context. */ + +struct machine_function +{ + int save_ra; +}; + +static void +alpha_save_machine_status (p) + struct function *p; +{ + struct machine_function *m = (struct machine_function *) + xmalloc (sizeof (struct machine_function)); + + p->machine = m; + m->save_ra = alpha_function_save_ra; +} + +static void +alpha_restore_machine_status (p) + struct function *p; +{ + struct machine_function *m = p->machine; + + alpha_function_save_ra = m->save_ra; + + p->machine = NULL; + free(m); +} + +/* Do anything needed before RTL is emitted for each function. */ + +void +alpha_init_expanders () +{ + alpha_function_save_ra = 0; + + /* Arrange to dave and restore machine status across nested functions. */ + save_machine_status = alpha_save_machine_status; + restore_machine_status = alpha_restore_machine_status; +} + /* Print an operand. Recognize special options, documented below. */ void @@ -1444,7 +1493,7 @@ alpha_sa_size () /* If some registers were saved but not reg 26, reg 26 must also be saved, so leave space for it. */ - if (size != 0 && ! regs_ever_live[26]) + if ((size != 0 || alpha_function_save_ra) && ! regs_ever_live[26]) size++; /* Our size must be even (multiple of 16 bytes). */ --- emit-rtl.c.alphara Thu Sep 14 16:09:30 1995 +++ emit-rtl.c Mon Sep 29 20:55:57 1997 @@ -159,6 +159,10 @@ rtx static_chain_rtx; /* (REG:Pmode STA rtx static_chain_incoming_rtx; /* (REG:Pmode STATIC_CHAIN_INCOMING_REGNUM) */ rtx pic_offset_table_rtx; /* (REG:Pmode PIC_OFFSET_TABLE_REGNUM) */ +/* This is used to implement __builtin_return_address for some machines. + See for instance the MIPS port. */ +rtx return_address_pointer_rtx; /* (REG:Pmode RETURN_ADDRESS_POINTER_REGNUM) */ + rtx virtual_incoming_args_rtx; /* (REG:Pmode VIRTUAL_INCOMING_ARGS_REGNUM) */ rtx virtual_stack_vars_rtx; /* (REG:Pmode VIRTUAL_STACK_VARS_REGNUM) */ rtx virtual_stack_dynamic_rtx; /* (REG:Pmode VIRTUAL_STACK_DYNAMIC_REGNUM) */ @@ -345,6 +349,11 @@ gen_rtx VPROTO((enum rtx_code code, enum && ! reload_in_progress) return arg_pointer_rtx; #endif +#ifdef RETURN_ADDRESS_POINTER_REGNUM + if (return_address_pointer_rtx && regno == RETURN_ADDRESS_POINTER_REGNUM + && mode == Pmode && ! reload_in_progress) + return return_address_pointer_rtx; +#endif if (stack_pointer_rtx && regno == STACK_POINTER_REGNUM && mode == Pmode && ! reload_in_progress) return stack_pointer_rtx; @@ -3391,6 +3400,11 @@ init_emit_once (line_numbers) arg_pointer_rtx = stack_pointer_rtx; else arg_pointer_rtx = gen_rtx (REG, Pmode, ARG_POINTER_REGNUM); + +#ifdef RETURN_ADDRESS_POINTER_REGNUM + return_address_pointer_rtx = gen_rtx (REG, Pmode, + RETURN_ADDRESS_POINTER_REGNUM); +#endif /* Create the virtual registers. Do so here since the following objects might reference them. */