📄 m68k.c
字号:
/* 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 ("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 { if (MOTOROLA) asm_fprintf (stream, "\tmovm.l -%wd(%s),%I0x%x\n", current_frame.offset + fsize, M68K_REGNAME(FRAME_POINTER_REGNUM), current_frame.reg_mask); else asm_fprintf (stream, "\tmoveml %s@(-%wd),%I0x%x\n", M68K_REGNAME(FRAME_POINTER_REGNUM), current_frame.offset + fsize, current_frame.reg_mask); } } else /* !TARGET_COLDFIRE */ { if (big) { if (MOTOROLA) asm_fprintf (stream, "\tmovm.l -%wd(%s,%Ra1.l),%I0x%x\n", current_frame.offset + fsize, M68K_REGNAME(FRAME_POINTER_REGNUM), current_frame.reg_mask); else asm_fprintf (stream, "\tmoveml %s@(-%wd,%Ra1:l),%I0x%x\n", M68K_REGNAME(FRAME_POINTER_REGNUM), current_frame.offset + fsize, 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 { if (MOTOROLA) asm_fprintf (stream, "\tmovm.l -%wd(%s),%I0x%x\n", current_frame.offset + fsize, M68K_REGNAME(FRAME_POINTER_REGNUM), current_frame.reg_mask); else asm_fprintf (stream, "\tmoveml %s@(-%wd),%I0x%x\n", M68K_REGNAME(FRAME_POINTER_REGNUM), current_frame.offset + fsize, current_frame.reg_mask); } } } if (current_frame.fpu_rev_mask) { if (big) { if (MOTOROLA) asm_fprintf (stream, "\tfmovm -%wd(%s,%Ra1.l),%I0x%x\n", current_frame.foffset + fsize, M68K_REGNAME(FRAME_POINTER_REGNUM), current_frame.fpu_rev_mask); else asm_fprintf (stream, "\tfmovem %s@(-%wd,%Ra1:l),%I0x%x\n", M68K_REGNAME(FRAME_POINTER_REGNUM), current_frame.foffset + fsize, current_frame.fpu_rev_mask); } else if (restore_from_sp) { if (MOTOROLA) asm_fprintf (stream, "\tfmovm (%Rsp)+,%I0x%x\n", current_frame.fpu_rev_mask); else asm_fprintf (stream, "\tfmovem %Rsp@+,%I0x%x\n", current_frame.fpu_rev_mask); } else { if (MOTOROLA) asm_fprintf (stream, "\tfmovm -%wd(%s),%I0x%x\n", current_frame.foffset + fsize, M68K_REGNAME(FRAME_POINTER_REGNUM), current_frame.fpu_rev_mask); else asm_fprintf (stream, "\tfmovem %s@(-%wd),%I0x%x\n", M68K_REGNAME(FRAME_POINTER_REGNUM), current_frame.foffset + fsize, current_frame.fpu_rev_mask); } } if (frame_pointer_needed) fprintf (stream, "\tunlk %s\n", M68K_REGNAME(FRAME_POINTER_REGNUM)); else if (fsize_with_regs) { if (fsize_with_regs <= 8) { if (!TARGET_COLDFIRE) asm_fprintf (stream, "\taddq" ASM_DOT "w %I%wd,%Rsp\n", fsize_with_regs); else asm_fprintf (stream, "\taddq" ASM_DOT "l %I%wd,%Rsp\n",
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -