📄 m68k.c
字号:
(frame_pointer_needed ? -UNITS_PER_WORD * 2 : -UNITS_PER_WORD); but for some obscure reason, this must be 0 to get correct code. */ if (from == ARG_POINTER_REGNUM && to == FRAME_POINTER_REGNUM) return 0; m68k_compute_frame_layout (); gcc_assert (to == STACK_POINTER_REGNUM); switch (from) { case ARG_POINTER_REGNUM: return current_frame.offset + current_frame.size + (frame_pointer_needed ? -UNITS_PER_WORD * 2 : -UNITS_PER_WORD); case FRAME_POINTER_REGNUM: return current_frame.offset + current_frame.size; default: gcc_unreachable (); }}/* Refer to the array `regs_ever_live' to determine which registers to save; `regs_ever_live[I]' is nonzero if register number I is ever used in the function. This function is responsible for knowing which registers should not be saved even if used. Return true if we need to save REGNO. */static boolm68k_save_reg (unsigned int regno, bool interrupt_handler){ if (flag_pic && regno == PIC_OFFSET_TABLE_REGNUM) { if (current_function_uses_pic_offset_table) return true; if (!current_function_is_leaf && TARGET_ID_SHARED_LIBRARY) return true; } if (current_function_calls_eh_return) { unsigned int i; for (i = 0; ; i++) { unsigned int test = EH_RETURN_DATA_REGNO (i); if (test == INVALID_REGNUM) break; if (test == regno) return true; } } /* Fixed regs we never touch. */ if (fixed_regs[regno]) return false; /* The frame pointer (if it is such) is handled specially. */ if (regno == FRAME_POINTER_REGNUM && frame_pointer_needed) return false; /* Interrupt handlers must also save call_used_regs if they are live or when calling nested functions. */ if (interrupt_handler) { if (regs_ever_live[regno]) return true; if (!current_function_is_leaf && call_used_regs[regno]) return true; } /* Never need to save registers that aren't touched. */ if (!regs_ever_live[regno]) return false; /* Otherwise save everything that isn't call-clobbered. */ return !call_used_regs[regno];}/* This function generates the assembly code for function entry. STREAM is a stdio stream to output the code to. SIZE is an int: how many units of temporary storage to allocate. */static voidm68k_output_function_prologue (FILE *stream, HOST_WIDE_INT size ATTRIBUTE_UNUSED){ HOST_WIDE_INT fsize_with_regs; HOST_WIDE_INT cfa_offset = INCOMING_FRAME_SP_OFFSET; m68k_compute_frame_layout(); /* If the stack limit is a symbol, we can check it here, before actually allocating the space. */ if (current_function_limit_stack && GET_CODE (stack_limit_rtx) == SYMBOL_REF) asm_fprintf (stream, "\tcmp" ASM_DOT "l %I%s+%wd,%Rsp\n\ttrapcs\n", XSTR (stack_limit_rtx, 0), current_frame.size + 4); /* On ColdFire add register save into initial stack frame setup, if possible. */ fsize_with_regs = current_frame.size; if (TARGET_COLDFIRE && current_frame.reg_no > 2) fsize_with_regs += current_frame.reg_no * 4; if (frame_pointer_needed) { if (current_frame.size == 0 && TARGET_68040) /* on the 68040, pea + move is faster than link.w 0 */ fprintf (stream, MOTOROLA ? "\tpea (%s)\n\tmove.l %s,%s\n" : "\tpea %s@\n\tmovel %s,%s\n", M68K_REGNAME(FRAME_POINTER_REGNUM), M68K_REGNAME(STACK_POINTER_REGNUM), M68K_REGNAME(FRAME_POINTER_REGNUM)); else if (fsize_with_regs < 0x8000) asm_fprintf (stream, "\tlink" ASM_DOTW " %s,%I%wd\n", M68K_REGNAME(FRAME_POINTER_REGNUM), -fsize_with_regs); else if (TARGET_68020) asm_fprintf (stream, "\tlink" ASM_DOTL " %s,%I%wd\n", M68K_REGNAME(FRAME_POINTER_REGNUM), -fsize_with_regs); else /* Adding negative number is faster on the 68040. */ asm_fprintf (stream, "\tlink" ASM_DOTW " %s,%I0\n" "\tadd" ASM_DOT "l %I%wd,%Rsp\n", M68K_REGNAME(FRAME_POINTER_REGNUM), -fsize_with_regs); if (dwarf2out_do_frame ()) { char *l; l = (char *) dwarf2out_cfi_label (); cfa_offset += 4; dwarf2out_reg_save (l, FRAME_POINTER_REGNUM, -cfa_offset); dwarf2out_def_cfa (l, FRAME_POINTER_REGNUM, cfa_offset); cfa_offset += current_frame.size; } } else if (fsize_with_regs) /* !frame_pointer_needed */ { if (fsize_with_regs < 0x8000) { if (fsize_with_regs <= 8) { if (!TARGET_COLDFIRE) asm_fprintf (stream, "\tsubq" ASM_DOT "w %I%wd,%Rsp\n", fsize_with_regs); else asm_fprintf (stream, "\tsubq" ASM_DOT "l %I%wd,%Rsp\n", fsize_with_regs); } else if (fsize_with_regs <= 16 && TARGET_CPU32) /* On the CPU32 it is faster to use two subqw instructions to subtract a small integer (8 < N <= 16) to a register. */ asm_fprintf (stream, "\tsubq" ASM_DOT "w %I8,%Rsp\n" "\tsubq" ASM_DOT "w %I%wd,%Rsp\n", fsize_with_regs - 8); else if (TARGET_68040) /* Adding negative number is faster on the 68040. */ asm_fprintf (stream, "\tadd" ASM_DOT "w %I%wd,%Rsp\n", -fsize_with_regs); else asm_fprintf (stream, MOTOROLA ? "\tlea (%wd,%Rsp),%Rsp\n" : "\tlea %Rsp@(%wd),%Rsp\n", -fsize_with_regs); } else /* fsize_with_regs >= 0x8000 */ asm_fprintf (stream, "\tadd" ASM_DOT "l %I%wd,%Rsp\n", -fsize_with_regs); if (dwarf2out_do_frame ()) { cfa_offset += current_frame.size + 4; dwarf2out_def_cfa ("", STACK_POINTER_REGNUM, cfa_offset); } } /* !frame_pointer_needed */ if (current_frame.fpu_mask) { asm_fprintf (stream, MOTOROLA ? "\tfmovm %I0x%x,-(%Rsp)\n" : "\tfmovem %I0x%x,%Rsp@-\n", current_frame.fpu_mask); if (dwarf2out_do_frame ()) { char *l = (char *) dwarf2out_cfi_label (); int n_regs, regno; cfa_offset += current_frame.fpu_no * 12; if (! frame_pointer_needed) dwarf2out_def_cfa (l, STACK_POINTER_REGNUM, cfa_offset); for (regno = 16, n_regs = 0; regno < 24; regno++) if (current_frame.fpu_mask & (1 << (regno - 16))) dwarf2out_reg_save (l, regno, -cfa_offset + n_regs++ * 12); } } /* If the stack limit is not a symbol, check it here. This has the disadvantage that it may be too late... */ if (current_function_limit_stack) { if (REG_P (stack_limit_rtx)) asm_fprintf (stream, "\tcmp" ASM_DOT "l %s,%Rsp\n\ttrapcs\n", M68K_REGNAME(REGNO (stack_limit_rtx))); else if (GET_CODE (stack_limit_rtx) != SYMBOL_REF) warning (0, "stack limit expression is not supported"); } if (current_frame.reg_no <= 2) { /* Store each separately in the same order moveml uses. Using two movel instructions instead of a single moveml is about 15% faster for the 68020 and 68030 at no expense in code size. */ int i; for (i = 0; i < 16; i++) if (current_frame.reg_rev_mask & (1 << i)) { asm_fprintf (stream, MOTOROLA ? "\t%Omove.l %s,-(%Rsp)\n" : "\tmovel %s,%Rsp@-\n", M68K_REGNAME(15 - i)); if (dwarf2out_do_frame ()) { char *l = (char *) dwarf2out_cfi_label (); cfa_offset += 4; if (! frame_pointer_needed) dwarf2out_def_cfa (l, STACK_POINTER_REGNUM, cfa_offset); dwarf2out_reg_save (l, 15 - i, -cfa_offset); } } } else if (current_frame.reg_rev_mask) { if (TARGET_COLDFIRE) /* The ColdFire does not support the predecrement form of the MOVEM instruction, so we must adjust the stack pointer and then use the plain address register indirect mode. The required register save space was combined earlier with the fsize_with_regs amount. */ asm_fprintf (stream, MOTOROLA ? "\tmovm.l %I0x%x,(%Rsp)\n" : "\tmoveml %I0x%x,%Rsp@\n", current_frame.reg_mask); else asm_fprintf (stream, MOTOROLA ? "\tmovm.l %I0x%x,-(%Rsp)\n" : "\tmoveml %I0x%x,%Rsp@-\n", current_frame.reg_rev_mask); if (dwarf2out_do_frame ()) { char *l = (char *) dwarf2out_cfi_label (); int n_regs, regno; cfa_offset += current_frame.reg_no * 4; if (! frame_pointer_needed) dwarf2out_def_cfa (l, STACK_POINTER_REGNUM, cfa_offset); for (regno = 0, n_regs = 0; regno < 16; regno++) if (current_frame.reg_mask & (1 << regno)) dwarf2out_reg_save (l, regno, -cfa_offset + n_regs++ * 4); } } if (!TARGET_SEP_DATA && flag_pic && (current_function_uses_pic_offset_table || (!current_function_is_leaf && TARGET_ID_SHARED_LIBRARY))) { if (TARGET_ID_SHARED_LIBRARY) { asm_fprintf (stream, "\tmovel %s@(%s), %s\n", M68K_REGNAME(PIC_OFFSET_TABLE_REGNUM), m68k_library_id_string, M68K_REGNAME(PIC_OFFSET_TABLE_REGNUM)); } else { if (MOTOROLA) asm_fprintf (stream, "\t%Olea (%Rpc, %U_GLOBAL_OFFSET_TABLE_@GOTPC), %s\n", M68K_REGNAME(PIC_OFFSET_TABLE_REGNUM)); else { asm_fprintf (stream, "\tmovel %I%U_GLOBAL_OFFSET_TABLE_, %s\n", M68K_REGNAME(PIC_OFFSET_TABLE_REGNUM)); asm_fprintf (stream, "\tlea %Rpc@(0,%s:l),%s\n", M68K_REGNAME(PIC_OFFSET_TABLE_REGNUM), M68K_REGNAME(PIC_OFFSET_TABLE_REGNUM)); } } }}/* Return true if this function's epilogue can be output as RTL. */booluse_return_insn (void){ if (!reload_completed || frame_pointer_needed || get_frame_size () != 0) return false; /* We can output the epilogue as RTL only if no registers need to be restored. */ m68k_compute_frame_layout(); return current_frame.reg_no ? false : true;}/* 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 voidm68k_output_function_epilogue (FILE *stream, HOST_WIDE_INT size ATTRIBUTE_UNUSED){ HOST_WIDE_INT fsize, fsize_with_regs; bool big = false; bool restore_from_sp = false; rtx insn = get_last_insn (); m68k_compute_frame_layout(); /* If the last insn was a BARRIER, we don't have to write any code. */ if (GET_CODE (insn) == NOTE) insn = prev_nonnote_insn (insn); if (insn && GET_CODE (insn) == BARRIER) { /* Output just a no-op so that debuggers don't get confused about which function the pc is in at this address. */ fprintf (stream, "\tnop\n"); return; }#ifdef FUNCTION_EXTRA_EPILOGUE FUNCTION_EXTRA_EPILOGUE (stream, size);#endif fsize = current_frame.size; /* FIXME : leaf_function_p below is too strong. What we really need to know there is if there could be pending stack adjustment needed at that point. */ restore_from_sp = ! frame_pointer_needed || (! current_function_calls_alloca && leaf_function_p ()); /* fsize_with_regs is the size we need to adjust the sp when popping the frame. */ fsize_with_regs = fsize; /* Because the ColdFire doesn't support moveml with complex address modes, we must adjust the stack manually after restoring registers. When the frame pointer isn't used, we can merge movem adjustment into frame unlinking made immediately after it. */ if (TARGET_COLDFIRE && restore_from_sp && (current_frame.reg_no > 2)) fsize_with_regs += current_frame.reg_no * 4; if (current_frame.offset + fsize >= 0x8000 && ! restore_from_sp && (current_frame.reg_mask || current_frame.fpu_mask)) { /* Because the ColdFire doesn't support moveml with complex address modes we make an extra correction here. */ if (TARGET_COLDFIRE) fsize += current_frame.offset; asm_fprintf (stream, "\t%Omove" ASM_DOT "l %I%wd,%Ra1\n", -fsize); fsize = 0, big = true; } if (current_frame.reg_no <= 2) { /* Restore each separately in the same order moveml does. Using two movel instructions instead of a single moveml is about 15% faster for the 68020 and 68030 at no expense in code size. */ int i; HOST_WIDE_INT offset = current_frame.offset + fsize; for (i = 0; i < 16; i++) if (current_frame.reg_mask & (1 << i)) { if (big) { if (MOTOROLA) asm_fprintf (stream, "\t%Omove.l -%wd(%s,%Ra1.l),%s\n", offset, M68K_REGNAME(FRAME_POINTER_REGNUM), M68K_REGNAME(i)); else asm_fprintf (stream, "\tmovel %s@(-%wd,%Ra1:l),%s\n", M68K_REGNAME(FRAME_POINTER_REGNUM), offset, M68K_REGNAME(i)); } else if (restore_from_sp) asm_fprintf (stream, MOTOROLA ? "\t%Omove.l (%Rsp)+,%s\n" : "\tmovel %Rsp@+,%s\n", M68K_REGNAME(i)); else { if (MOTOROLA) asm_fprintf (stream, "\t%Omove.l -%wd(%s),%s\n", offset, M68K_REGNAME(FRAME_POINTER_REGNUM), M68K_REGNAME(i)); else asm_fprintf (stream, "\tmovel %s@(-%wd),%s\n", M68K_REGNAME(FRAME_POINTER_REGNUM), offset, M68K_REGNAME(i)); } offset -= 4; } } else if (current_frame.reg_mask) { /* The ColdFire requires special handling due to its limited moveml insn. */ if (TARGET_COLDFIRE) { if (big) { asm_fprintf (stream, "\tadd" ASM_DOT "l %s,%Ra1\n", M68K_REGNAME(FRAME_POINTER_REGNUM)); asm_fprintf (stream, MOTOROLA ? "\tmovm.l (%Ra1),%I0x%x\n" : "\tmoveml %Ra1@,%I0x%x\n", current_frame.reg_mask); } else if (restore_from_sp) asm_fprintf (stream, MOTOROLA ? "\tmovm.l (%Rsp),%I0x%x\n" : "\tmoveml %Rsp@,%I0x%x\n", current_frame.reg_mask); else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -