📄 m88k.c
字号:
/* If a frame is requested, save the previous FP, and the return address (r1), so that a traceback can be done without using tdesc information. Otherwise, simply save the FP if it is used as a preserve register. */ if (frame_pointer_needed) save_regs[FRAME_POINTER_REGNUM] = save_regs[1] = 1; else if (regs_ever_live[FRAME_POINTER_REGNUM]) save_regs[FRAME_POINTER_REGNUM] = 1; /* Figure out which extended register(s) needs to be saved. */ for (regno = FIRST_EXTENDED_REGISTER + 1; regno < FIRST_PSEUDO_REGISTER; regno++) if (regs_ever_live[regno] && ! call_used_regs[regno]) { save_regs[regno] = 1; nxregs++; } /* Figure out which normal register(s) needs to be saved. */ for (regno = 2; regno < FRAME_POINTER_REGNUM; regno++) if (regs_ever_live[regno] && ! call_used_regs[regno]) { save_regs[regno] = 1; nregs++; } /* Achieve greatest use of double memory ops. Either we end up saving r30 or we use that slot to align the registers we do save. */ if (nregs >= 2 && save_regs[1] && !save_regs[FRAME_POINTER_REGNUM]) sp_size += 4; nregs += save_regs[1] + save_regs[FRAME_POINTER_REGNUM]; /* if we need to align extended registers, add a word */ if (nxregs > 0 && (nregs & 1) != 0) sp_size +=4; sp_size += 4 * nregs; sp_size += 8 * nxregs; sp_size += current_function_outgoing_args_size; /* The first two saved registers are placed above the new frame pointer if any. In the only case this matters, they are r1 and r30. */ if (frame_pointer_needed || sp_size) m88k_fp_offset = ROUND_CALL_BLOCK_SIZE (sp_size - STARTING_FRAME_OFFSET); else m88k_fp_offset = -STARTING_FRAME_OFFSET; m88k_stack_size = m88k_fp_offset + STARTING_FRAME_OFFSET; /* First, combine m88k_stack_size and size. If m88k_stack_size is nonzero, align the frame size to 8 mod 16; otherwise align the frame size to 0 mod 16. (If stacks are 8 byte aligned, this ends up as a NOP. */ { int need = ((m88k_stack_size ? STACK_UNIT_BOUNDARY - STARTING_FRAME_OFFSET : 0) - (frame_size % STACK_UNIT_BOUNDARY)); if (need < 0) need += STACK_UNIT_BOUNDARY; m88k_stack_size = ROUND_CALL_BLOCK_SIZE (m88k_stack_size + frame_size + need + current_function_pretend_args_size); }}/* Return true if this function is known to have a null prologue. */intnull_prologue (){ if (! reload_completed) return 0; if (! frame_laid_out) m88k_layout_frame (); return (! frame_pointer_needed && nregs == 0 && nxregs == 0 && m88k_stack_size == 0);}/* Determine if the current function has any references to the arg pointer. This is done indirectly by examining the DECL_ARGUMENTS' DECL_RTL. It is OK to return TRUE if there are no references, but FALSE must be correct. */static intuses_arg_area_p (){ register tree parm; if (current_function_decl == 0 || variable_args_p) return 1; for (parm = DECL_ARGUMENTS (current_function_decl); parm; parm = TREE_CHAIN (parm)) { if (DECL_RTL (parm) == 0 || GET_CODE (DECL_RTL (parm)) == MEM) return 1; if (DECL_INCOMING_RTL (parm) == 0 || GET_CODE (DECL_INCOMING_RTL (parm)) == MEM) return 1; } return 0;}static voidm88k_output_function_prologue (stream, size) FILE *stream ATTRIBUTE_UNUSED; HOST_WIDE_INT size ATTRIBUTE_UNUSED;{ if (TARGET_OMIT_LEAF_FRAME_POINTER && ! quiet_flag && leaf_function_p ()) fprintf (stderr, "$"); m88k_prologue_done = 1; /* it's ok now to put out ln directives */}static voidm88k_output_function_end_prologue (stream) FILE *stream;{ if (TARGET_OCS_DEBUG_INFO && !prologue_marked) { PUT_OCS_FUNCTION_START (stream); prologue_marked = 1; /* If we've already passed the start of the epilogue, say that it starts here. This marks the function as having a null body, but at a point where the return address is in a known location. Originally, I thought this couldn't happen, but the pic prologue for leaf functions ends with the instruction that restores the return address from the temporary register. If the temporary register is never used, that instruction can float all the way to the end of the function. */ if (epilogue_marked) PUT_OCS_FUNCTION_END (stream); }}voidm88k_expand_prologue (){ m88k_layout_frame (); if (TARGET_OPTIMIZE_ARG_AREA && m88k_stack_size && ! uses_arg_area_p ()) { /* The incoming argument area is used for stack space if it is not used (or if -mno-optimize-arg-area is given). */ if ((m88k_stack_size -= REG_PARM_STACK_SPACE (0)) < 0) m88k_stack_size = 0; } if (m88k_stack_size) emit_add (stack_pointer_rtx, stack_pointer_rtx, -m88k_stack_size); if (nregs || nxregs) preserve_registers (m88k_fp_offset + 4, 1); if (frame_pointer_needed) emit_add (frame_pointer_rtx, stack_pointer_rtx, m88k_fp_offset); if (flag_pic && save_regs[PIC_OFFSET_TABLE_REGNUM]) { rtx return_reg = gen_rtx_REG (SImode, 1); rtx label = gen_label_rtx (); rtx temp_reg = NULL_RTX; if (! save_regs[1]) { temp_reg = gen_rtx_REG (SImode, TEMP_REGNUM); emit_move_insn (temp_reg, return_reg); } emit_insn (gen_locate1 (pic_offset_table_rtx, label)); emit_insn (gen_locate2 (pic_offset_table_rtx, label)); emit_insn (gen_addsi3 (pic_offset_table_rtx, pic_offset_table_rtx, return_reg)); if (! save_regs[1]) emit_move_insn (return_reg, temp_reg); } if (current_function_profile) emit_insn (gen_blockage ());}/* This function generates the assembly code for function exit, on machines that need it. The function epilogue should not depend on the current stack pointer! It should use the frame pointer only, if there is a frame pointer. This is mandatory because of alloca; we also take advantage of it to omit stack adjustments before returning. */static voidm88k_output_function_begin_epilogue (stream) FILE *stream;{ if (TARGET_OCS_DEBUG_INFO && !epilogue_marked && prologue_marked) { PUT_OCS_FUNCTION_END (stream); } epilogue_marked = 1;}static voidm88k_output_function_epilogue (stream, size) FILE *stream; HOST_WIDE_INT size ATTRIBUTE_UNUSED;{ rtx insn = get_last_insn (); if (TARGET_OCS_DEBUG_INFO && !epilogue_marked) PUT_OCS_FUNCTION_END (stream); /* If the last insn isn't a BARRIER, we must write a return insn. This should only happen if the function has no prologue and no body. */ if (GET_CODE (insn) == NOTE) insn = prev_nonnote_insn (insn); if (insn == 0 || GET_CODE (insn) != BARRIER) fprintf (stream, "\tjmp\t %s\n", reg_names[1]); /* If the last insn is a barrier, and the insn before that is a call, then add a nop instruction so that tdesc can walk the stack correctly even though there is no epilogue. (Otherwise, the label for the end of the tdesc region ends up at the start of the next function. */ if (insn && GET_CODE (insn) == BARRIER) { insn = prev_nonnote_insn (insn); if (insn && GET_CODE (insn) == CALL_INSN) fprintf (stream, "\tor\t %s,%s,%s\n",reg_names[0],reg_names[0],reg_names[0]); } output_short_branch_defs (stream); fprintf (stream, "\n"); if (TARGET_OCS_DEBUG_INFO) output_tdesc (stream, m88k_fp_offset + 4); m88k_function_number++; m88k_prologue_done = 0; /* don't put out ln directives */ variable_args_p = 0; /* has variable args */ frame_laid_out = 0; epilogue_marked = 0; prologue_marked = 0;}voidm88k_expand_epilogue (){#if (MONITOR_GCC & 0x4) /* What are interesting prologue/epilogue values? */ fprintf (stream, "; size = %d, m88k_fp_offset = %d, m88k_stack_size = %d\n", size, m88k_fp_offset, m88k_stack_size);#endif if (frame_pointer_needed) emit_add (stack_pointer_rtx, frame_pointer_rtx, -m88k_fp_offset); if (nregs || nxregs) preserve_registers (m88k_fp_offset + 4, 0); if (m88k_stack_size) emit_add (stack_pointer_rtx, stack_pointer_rtx, m88k_stack_size);}/* Emit insns to set DSTREG to SRCREG + AMOUNT during the prologue or epilogue. */static voidemit_add (dstreg, srcreg, amount) rtx dstreg; rtx srcreg; int amount;{ rtx incr = GEN_INT (abs (amount)); if (! ADD_INTVAL (amount)) { rtx temp = gen_rtx_REG (SImode, TEMP_REGNUM); emit_move_insn (temp, incr); incr = temp; } emit_insn ((amount < 0 ? gen_subsi3 : gen_addsi3) (dstreg, srcreg, incr));}/* Save/restore the preserve registers. base is the highest offset from r31 at which a register is stored. store_p is true if stores are to be done; otherwise loads. */static voidpreserve_registers (base, store_p) int base; int store_p;{ int regno, offset; struct mem_op { int regno; int nregs; int offset; } mem_op[FIRST_PSEUDO_REGISTER]; struct mem_op *mo_ptr = mem_op; /* The 88open OCS mandates that preserved registers be stored in increasing order. For compatibility with current practice, the order is r1, r30, then the preserve registers. */ offset = base; if (save_regs[1]) { /* An extra word is given in this case to make best use of double memory ops. */ if (nregs > 2 && !save_regs[FRAME_POINTER_REGNUM]) offset -= 4; emit_ldst (store_p, 1, SImode, offset); offset -= 4; base = offset; } /* Walk the registers to save recording all single memory operations. */ for (regno = FRAME_POINTER_REGNUM; regno > 1; regno--) if (save_regs[regno]) { if ((offset & 7) != 4 || (regno & 1) != 1 || !save_regs[regno-1]) { mo_ptr->nregs = 1; mo_ptr->regno = regno; mo_ptr->offset = offset; mo_ptr++; offset -= 4; } else { regno--; offset -= 2*4; } } /* Walk the registers to save recording all double memory operations. This avoids a delay in the epilogue (ld.d/ld). */ offset = base; for (regno = FRAME_POINTER_REGNUM; regno > 1; regno--) if (save_regs[regno]) { if ((offset & 7) != 4 || (regno & 1) != 1 || !save_regs[regno-1]) { offset -= 4; } else { mo_ptr->nregs = 2; mo_ptr->regno = regno-1; mo_ptr->offset = offset-4; mo_ptr++; regno--; offset -= 2*4; } } /* Walk the extended registers to record all memory operations. */ /* Be sure the offset is double word aligned. */ offset = (offset - 1) & ~7; for (regno = FIRST_PSEUDO_REGISTER - 1; regno > FIRST_EXTENDED_REGISTER; regno--) if (save_regs[regno]) { mo_ptr->nregs = 2; mo_ptr->regno = regno; mo_ptr->offset = offset; mo_ptr++; offset -= 2*4; } mo_ptr->regno = 0; /* Output the memory operations. */ for (mo_ptr = mem_op; mo_ptr->regno; mo_ptr++) { if (mo_ptr->nregs) emit_ldst (store_p, mo_ptr->regno, (mo_ptr->nregs > 1 ? DImode : SImode), mo_ptr->offset); }}static voidemit_ldst (store_p, regno, mode, offset) int store_p; int regno; enum machine_mode mode; int offset;{ rtx reg = gen_rtx_REG (mode, regno); rtx mem; if (SMALL_INTVAL (offset)) { mem = gen_rtx_MEM (mode, plus_constant (stack_pointer_rtx, offset)); } else { /* offset is too large for immediate index must use register */ rtx disp = GEN_INT (offset); rtx temp = gen_rtx_REG (SImode, TEMP_REGNUM); rtx regi = gen_rtx_PLUS (SImode, stack_pointer_rtx, temp); emit_move_insn (temp, disp); mem = gen_rtx_MEM (mode, regi); } if (store_p) emit_move_insn (mem, reg); else emit_move_insn (reg, mem);}/* Convert the address expression REG to a CFA offset. */intm88k_debugger_offset (reg, offset) register rtx reg; register int offset;{ if (GET_CODE (reg) == PLUS) { offset = INTVAL (XEXP (reg, 1)); reg = XEXP (reg, 0); } /* Put the offset in terms of the CFA (arg pointer). */ if (reg == frame_pointer_rtx) offset += m88k_fp_offset - m88k_stack_size; else if (reg == stack_pointer_rtx) offset -= m88k_stack_size; else if (reg != arg_pointer_rtx) {#if (MONITOR_GCC & 0x10) /* Watch for suspicious symbolic locations. */ if (! (GET_CODE (reg) == REG && REGNO (reg) >= FIRST_PSEUDO_REGISTER)) warning ("internal gcc error: Can't express symbolic location");#endif return 0; } return offset;}/* Output the 88open OCS proscribed text description information. The information is: 0 8: zero 0 22: info-byte-length (16 or 20 bytes) 0 2: info-alignment (word 2) 1 32: info-protocol (version 1 or 2(pic)) 2 32: starting-address (inclusive, not counting prologue) 3 32: ending-address (exclusive, not counting epilog) 4 8: info-variant (version 1 or 3(extended registers)) 4 17: register-save-mask (from register 14 to 30) 4 1: zero 4 1: return-address-info-discrimin
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -