📄 pa.c
字号:
fprintf (file, "\"\n");}/* You may have trouble believing this, but this is the HP-PA stack layout. Wow. Offset Contents Variable arguments (optional; any number may be allocated) SP-(4*(N+9)) arg word N : : SP-56 arg word 5 SP-52 arg word 4 Fixed arguments (must be allocated; may remain unused) SP-48 arg word 3 SP-44 arg word 2 SP-40 arg word 1 SP-36 arg word 0 Frame Marker SP-32 External Data Pointer (DP) SP-28 External sr4 SP-24 External/stub RP (RP') SP-20 Current RP SP-16 Static Link SP-12 Clean up SP-8 Calling Stub RP (RP'') SP-4 Previous SP Top of Frame SP-0 Stack Pointer (points to next available address)*//* This function saves registers as follows. Registers marked with ' are this function's registers (as opposed to the previous function's). If a frame_pointer isn't needed, r4 is saved as a general register; the space for the frame pointer is still allocated, though, to keep things simple. Top of Frame SP (FP') Previous FP SP + 4 Alignment filler (sigh) SP + 8 Space for locals reserved here. . . . SP + n All call saved register used. . . . SP + o All call saved fp registers used. . . . SP + p (SP') points to next available address.*//* Emit RTL to store REG at the memory location specified by BASE+DISP. Handle case where DISP > 8k by using the add_high_const pattern. Note in DISP > 8k case, we will leave the high part of the address in %r1. There is code in expand_hppa_{prologue,epilogue} that knows this.*/static voidstore_reg (reg, disp, base) int reg, disp, base;{ if (VAL_14_BITS_P (disp)) { emit_move_insn (gen_rtx (MEM, SImode, gen_rtx (PLUS, SImode, gen_rtx (REG, SImode, base), GEN_INT (disp))), gen_rtx (REG, SImode, reg)); } else { emit_insn (gen_add_high_const (gen_rtx (REG, SImode, 1), gen_rtx (REG, SImode, base), GEN_INT (disp))); emit_move_insn (gen_rtx (MEM, SImode, gen_rtx (LO_SUM, SImode, gen_rtx (REG, SImode, 1), GEN_INT (disp))), gen_rtx (REG, SImode, reg)); }}/* Emit RTL to load REG from the memory location specified by BASE+DISP. Handle case where DISP > 8k by using the add_high_const pattern. Note in DISP > 8k case, we will leave the high part of the address in %r1. There is code in expand_hppa_{prologue,epilogue} that knows this.*/static voidload_reg (reg, disp, base) int reg, disp, base;{ if (VAL_14_BITS_P (disp)) { emit_move_insn (gen_rtx (REG, SImode, reg), gen_rtx (MEM, SImode, gen_rtx (PLUS, SImode, gen_rtx (REG, SImode, base), GEN_INT (disp)))); } else { emit_insn (gen_add_high_const (gen_rtx (REG, SImode, 1), gen_rtx (REG, SImode, base), GEN_INT (disp))); emit_move_insn (gen_rtx (REG, SImode, reg), gen_rtx (MEM, SImode, gen_rtx (LO_SUM, SImode, gen_rtx (REG, SImode, 1), GEN_INT (disp)))); }}/* Emit RTL to set REG to the value specified by BASE+DISP. Handle case where DISP > 8k by using the add_high_const pattern. Note in DISP > 8k case, we will leave the high part of the address in %r1. There is code in expand_hppa_{prologue,epilogue} that knows this.*/static voidset_reg_plus_d(reg, base, disp) int reg, base, disp;{ if (VAL_14_BITS_P (disp)) { emit_move_insn (gen_rtx (REG, SImode, reg), gen_rtx (PLUS, SImode, gen_rtx (REG, SImode, base), GEN_INT (disp))); } else { emit_insn (gen_add_high_const (gen_rtx (REG, SImode, 1), gen_rtx (REG, SImode, base), GEN_INT (disp))); emit_move_insn (gen_rtx (REG, SImode, reg), gen_rtx (LO_SUM, SImode, gen_rtx (REG, SImode, 1), GEN_INT (disp))); }}/* Global variables set by FUNCTION_PROLOGUE. *//* Size of frame. Need to know this to emit return insns from leaf procedures. */static int actual_fsize;static int local_fsize, save_fregs;intcompute_frame_size (size, fregs_live) int size; int *fregs_live;{ extern int current_function_outgoing_args_size; int i, fsize; /* 8 is space for frame pointer + filler. If any frame is allocated we need to add this in because of STARTING_FRAME_OFFSET. */ fsize = size + (size || frame_pointer_needed ? 8 : 0); for (i = 18; i >= 4; i--) { if (regs_ever_live[i]) fsize += 4; } /* If we don't have a frame pointer, the register normally used for that purpose is saved just like other registers, not in the "frame marker". */ if (! frame_pointer_needed) { if (regs_ever_live[FRAME_POINTER_REGNUM]) fsize += 4; } fsize = (fsize + 7) & ~7; for (i = 66; i >= 48; i -= 2) if (regs_ever_live[i] || regs_ever_live[i + 1]) { fsize += 8; if (fregs_live) *fregs_live = 1; } fsize += current_function_outgoing_args_size; if (! leaf_function_p () || fsize) fsize += 32; return (fsize + 63) & ~63;}rtx hp_profile_label_rtx;static char hp_profile_label_name[8];voidoutput_function_prologue (file, size) FILE *file; int size;{ /* The function's label and associated .PROC must never be separated and must be output *after* any profiling declarations to avoid changing spaces/subspaces within a procedure. */ ASM_OUTPUT_LABEL (file, XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0)); fputs ("\t.PROC\n", file); /* hppa_expand_prologue does the dirty work now. We just need to output the assembler directives which denote the start of a function. */ fprintf (file, "\t.CALLINFO FRAME=%d", actual_fsize); if (regs_ever_live[2] || profile_flag) fprintf (file, ",CALLS,SAVE_RP"); else fprintf (file, ",NO_CALLS"); if (frame_pointer_needed) fprintf (file, ",SAVE_SP"); /* Pass on information about the number of callee register saves performed in the prologue. The compiler is supposed to pass the highest register number saved, the assembler then has to adjust that number before entering it into the unwind descriptor (to account for any caller saved registers with lower register numbers than the first callee saved register). */ if (gr_saved) fprintf (file, ",ENTRY_GR=%d", gr_saved + 2); if (fr_saved) fprintf (file, ",ENTRY_FR=%d", fr_saved + 11); fprintf (file, "\n\t.ENTRY\n"); /* Horrid hack. emit_function_prologue will modify this RTL in place to get the expected results. */ if (profile_flag) ASM_GENERATE_INTERNAL_LABEL (hp_profile_label_name, "LP", hp_profile_labelno); if (insn_addresses) { unsigned int old_total = total_code_bytes; total_code_bytes += insn_addresses[INSN_UID (get_last_insn())]; total_code_bytes += FUNCTION_BOUNDARY /BITS_PER_UNIT; /* Be prepared to handle overflows. */ total_code_bytes = old_total > total_code_bytes ? -1 : total_code_bytes; } else total_code_bytes = -1;}voidhppa_expand_prologue(){ extern char call_used_regs[]; int size = get_frame_size (); int merge_sp_adjust_with_store = 0; int i, offset; rtx tmpreg, size_rtx; gr_saved = 0; fr_saved = 0; save_fregs = 0; local_fsize = size + (size || frame_pointer_needed ? 8 : 0); actual_fsize = compute_frame_size (size, &save_fregs); /* Compute a few things we will use often. */ tmpreg = gen_rtx (REG, SImode, 1); size_rtx = GEN_INT (actual_fsize); /* Save RP first. The calling conventions manual states RP will always be stored into the caller's frame at sp-20. */ if (regs_ever_live[2] || profile_flag) store_reg (2, -20, STACK_POINTER_REGNUM); /* Allocate the local frame and set up the frame pointer if needed. */ if (actual_fsize) if (frame_pointer_needed) { /* Copy the old frame pointer temporarily into %r1. Set up the new stack pointer, then store away the saved old frame pointer into the stack at sp+actual_fsize and at the same time update the stack pointer by actual_fsize bytes. Two versions, first handles small (<8k) frames. The second handles large (>8k) frames. */ emit_move_insn (tmpreg, frame_pointer_rtx); emit_move_insn (frame_pointer_rtx, stack_pointer_rtx); if (VAL_14_BITS_P (actual_fsize)) emit_insn (gen_post_stwm (stack_pointer_rtx, stack_pointer_rtx, size_rtx, tmpreg)); else { /* It is incorrect to store the saved frame pointer at *sp, then increment sp (writes beyond the current stack boundary). So instead use stwm to store at *sp and post-increment the stack pointer as an atomic operation. Then increment sp to finish allocating the new frame. */ emit_insn (gen_post_stwm (stack_pointer_rtx, stack_pointer_rtx, GEN_INT (64), tmpreg)); set_reg_plus_d (STACK_POINTER_REGNUM, STACK_POINTER_REGNUM, actual_fsize - 64); } } /* no frame pointer needed. */ else { /* In some cases we can perform the first callee register save and allocating the stack frame at the same time. If so, just make a note of it and defer allocating the frame until saving the callee registers. */ if (VAL_14_BITS_P (-actual_fsize) && local_fsize == 0 && ! profile_flag && ! flag_pic) merge_sp_adjust_with_store = 1; /* Can not optimize. Adjust the stack frame by actual_fsize bytes. */ else if (actual_fsize != 0) set_reg_plus_d (STACK_POINTER_REGNUM, STACK_POINTER_REGNUM, actual_fsize); } /* The hppa calling conventions say that that %r19, the pic offset register, is saved at sp - 32 (in this function's frame) when generating PIC code. FIXME: What is the correct thing to do for functions which make no calls and allocate no frame? Do we need to allocate a frame, or can we just omit the save? For now we'll just omit the save. */ if (actual_fsize != 0 && flag_pic) store_reg (PIC_OFFSET_TABLE_REGNUM, -32, STACK_POINTER_REGNUM); /* Profiling code. Instead of taking one argument, the counter label, as most normal mcounts do, _mcount appears to behave differently on the HPPA. It takes the return address of the caller, the address of this routine, and the address of the label. Also, it isn't magic, so argument registers have to be preserved. */ if (profile_flag) { int pc_offset, i, arg_offset, basereg, offsetadj; pc_offset = 4 + (frame_pointer_needed ? (VAL_14_BITS_P (actual_fsize) ? 12 : 20) : (VAL_14_BITS_P (actual_fsize) ? 4 : 8)); /* When the function has a frame pointer, use it as the base register for saving/restore registers. Else use the stack pointer. Adjust the offset according to the frame size if this function does not have a frame pointer. */ basereg = frame_pointer_needed ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM; offsetadj = frame_pointer_needed ? 0 : actual_fsize; /* Horrid hack. emit_function_prologue will modify this RTL in place to get the expected results. sprintf here is just to put something in the name. */ sprintf(hp_profile_label_name, "LP$%04d", -1); hp_profile_label_rtx = gen_rtx (SYMBOL_REF, SImode, hp_profile_label_name); if (current_function_returns_struct) store_reg (STRUCT_VALUE_REGNUM, - 12 - offsetadj, basereg); for (i = 26, arg_offset = -36 - offsetadj; i >= 23; i--, arg_offset -= 4) if (regs_ever_live [i]) { store_reg (i, arg_offset, basereg); /* Deal with arg_offset not fitting in 14 bits. */ pc_offset += VAL_14_BITS_P (arg_offset) ? 4 : 8; } emit_move_insn (gen_rtx (REG, SImode, 26), gen_rtx (REG, SImode, 2)); emit_move_insn (tmpreg, gen_rtx (HIGH, SImode, hp_profile_label_rtx)); emit_move_insn (gen_rtx (REG, SImode, 24), gen_rtx (LO_SUM, SImode, tmpreg, hp_profile_label_rtx)); /* %r25 is set from within the output pattern. */ emit_insn (gen_call_profiler (GEN_INT (- pc_offset - 20))); /* Restore argument registers. */ for (i = 26, arg_offset = -36 - offsetadj; i >= 23; i--, arg_offset -= 4) if (regs_ever_live [i]) load_reg (i, arg_offset, basereg); if (current_function_returns_struct) load_reg (STRUCT_VALUE_REGNUM, -12 - offsetadj, basereg); } /* Normal register save. Do not save the frame pointer in the frame_pointer_needed case. It was done earlier. */ if (frame_pointer_needed) { for (i = 18, offset = local_fsize; i >= 4; i--) if (regs_ever_live[i] && ! call_used_regs[i]) { store_reg (i, offset, FRAME_POINTER_REGNUM); offset += 4; gr_saved++; } /* Account for %r4 which is saved in a special place. */ gr_saved++; } /* No frame pointer needed. */ else { for (i = 18, offset = local_fsize - actual_fsize; i >= 3; i--) if (regs_ever_live[i] && ! call_used_regs[i]) { /* If merge_sp_adjust_with_store is nonzero, then we can optimize the first GR save. */ if (merge_sp_adjust_with_store) { merge_sp_adjust_with_store = 0; emit_insn (gen_post_stwm (stack_pointer_rtx, stack_pointer_rtx, GEN_INT (-offset), gen_rtx (REG, SImode, i))); } else store_reg (i, offset, STACK_POINTER_REGNUM); offset += 4; gr_saved++; } /* If we wanted to merge the SP adjustment with a GR save, but we never did any GR saves, then just emit the adjustment here. */ if (merge_sp_adjust_with_store) set_reg_plus_d (STACK_POINTER_REGNUM, STACK_POINTER_REGNUM, actual_fsize); } /* Align pointer properly (doubleword boundary). */ offset = (offset + 7) & ~7; /* Floating point register store. */ if (save_fregs) { /* First get the frame or stack pointer to the start of the FP register save area. */ if (frame_pointer_needed) set_reg_plus_d (1, FRAME_POINTER_REGNUM, offset); else set_reg_plus_d (1, STACK_POINTER_REGNUM, offset); /* Now actually save the FP registers. */ for (i = 66; i >= 48; i -= 2) if (regs_ever_live[i] || regs_ever_live[i + 1]) { emit_move_insn (gen_rtx (MEM, DFmode,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -