📄 i386.c
字号:
cfa_offset = cfa_store_offset; dwarf2out_def_cfa ("", STACK_POINTER_REGNUM, cfa_offset); } }#endif } } else { xops[3] = gen_rtx_REG (SImode, 0); if (do_rtl) emit_move_insn (xops[3], xops[2]); else output_asm_insn (AS2 (mov%L0,%2,%3), xops); xops[3] = gen_rtx_MEM (FUNCTION_MODE, gen_rtx (SYMBOL_REF, Pmode, "_alloca")); if (do_rtl) emit_call_insn (gen_rtx (CALL, VOIDmode, xops[3], const0_rtx)); else output_asm_insn (AS1 (call,%P3), xops); } /* Note If use enter it is NOT reversed args. This one is not reversed from intel!! I think enter is slower. Also sdb doesn't like it. But if you want it the code is: { xops[3] = const0_rtx; output_asm_insn ("enter %2,%3", xops); } */ limit = (frame_pointer_needed ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM); for (regno = limit - 1; regno >= 0; regno--) if ((regs_ever_live[regno] && ! call_used_regs[regno]) || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used)) { xops[0] = gen_rtx_REG (SImode, regno); if (do_rtl) { insn = emit_insn (gen_rtx (SET, VOIDmode, gen_rtx_MEM (SImode, gen_rtx (PRE_DEC, SImode, stack_pointer_rtx)), xops[0])); RTX_FRAME_RELATED_P (insn) = 1; } else { output_asm_insn ("push%L0 %0", xops);#ifdef INCOMING_RETURN_ADDR_RTX if (dwarf2out_do_frame ()) { char *l = dwarf2out_cfi_label (); cfa_store_offset += 4; if (! frame_pointer_needed) { cfa_offset = cfa_store_offset; dwarf2out_def_cfa (l, STACK_POINTER_REGNUM, cfa_offset); } dwarf2out_reg_save (l, regno, - cfa_store_offset); }#endif } }#ifdef SUBTARGET_PROLOGUE SUBTARGET_PROLOGUE;#endif if (pic_reg_used) load_pic_register (do_rtl); /* If we are profiling, make sure no instructions are scheduled before the call to mcount. However, if -fpic, the above call will have done that. */ if ((profile_flag || profile_block_flag) && ! pic_reg_used && do_rtl) emit_insn (gen_blockage ());}/* Return 1 if it is appropriate to emit `ret' instructions in the body of a function. Do this only if the epilogue is simple, needing a couple of insns. Prior to reloading, we can't tell how many registers must be saved, so return 0 then. Return 0 if there is no frame marker to de-allocate. If NON_SAVING_SETJMP is defined and true, then it is not possible for the epilogue to be simple, so return 0. This is a special case since NON_SAVING_SETJMP will not cause regs_ever_live to change until final, but jump_optimize may need to know sooner if a `return' is OK. */intix86_can_use_return_insn_p (){ int regno; int nregs = 0; int reglimit = (frame_pointer_needed ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM); int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table || current_function_uses_const_pool);#ifdef NON_SAVING_SETJMP if (NON_SAVING_SETJMP && current_function_calls_setjmp) return 0;#endif if (! reload_completed) return 0; for (regno = reglimit - 1; regno >= 0; regno--) if ((regs_ever_live[regno] && ! call_used_regs[regno]) || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used)) nregs++; return nregs == 0 || ! frame_pointer_needed;}/* This function generates the assembly code for function exit. FILE is an stdio stream to output the code to. SIZE is an int: how many units of temporary storage to deallocate. */voidfunction_epilogue (file, size) FILE *file ATTRIBUTE_UNUSED; int size ATTRIBUTE_UNUSED;{ return;}/* Restore function stack, frame, and registers. */voidix86_expand_epilogue (){ ix86_epilogue (1);}static voidix86_epilogue (do_rtl) int do_rtl;{ register int regno; register int limit; int nregs; rtx xops[3]; int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table || current_function_uses_const_pool); int sp_valid = !frame_pointer_needed || current_function_sp_is_unchanging; HOST_WIDE_INT offset; HOST_WIDE_INT tsize = ix86_compute_frame_size (get_frame_size (), &nregs); /* sp is often unreliable so we may have to go off the frame pointer. */ offset = -(tsize + nregs * UNITS_PER_WORD); xops[2] = stack_pointer_rtx; /* When -fpic, we must emit a scheduling barrier, so that the instruction that restores %ebx (which is PIC_OFFSET_TABLE_REGNUM), does not get moved before any instruction which implicitly uses the got. This includes any instruction which uses a SYMBOL_REF or a LABEL_REF. Alternatively, this could be fixed by making the dependence on the PIC_OFFSET_TABLE_REGNUM explicit in the RTL. */ if (flag_pic || profile_flag || profile_block_flag) emit_insn (gen_blockage ()); /* If we're only restoring one register and sp is not valid then using a move instruction to restore the register since it's less work than reloading sp and popping the register. Otherwise, restore sp (if necessary) and pop the registers. */ limit = frame_pointer_needed ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM; if (nregs > 1 || sp_valid) { if ( !sp_valid ) { xops[0] = adj_offsettable_operand (AT_BP (QImode), offset); if (do_rtl) emit_insn (gen_movsi_lea (xops[2], XEXP (xops[0], 0))); else output_asm_insn (AS2 (lea%L2,%0,%2), xops); } for (regno = 0; regno < limit; regno++) if ((regs_ever_live[regno] && ! call_used_regs[regno]) || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used)) { xops[0] = gen_rtx_REG (SImode, regno); if (do_rtl) emit_insn (gen_pop (xops[0])); else output_asm_insn ("pop%L0 %0", xops); } } else for (regno = 0; regno < limit; regno++) if ((regs_ever_live[regno] && ! call_used_regs[regno]) || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used)) { xops[0] = gen_rtx_REG (SImode, regno); xops[1] = adj_offsettable_operand (AT_BP (Pmode), offset); if (do_rtl) emit_move_insn (xops[0], xops[1]); else output_asm_insn (AS2 (mov%L0,%1,%0), xops); offset += 4; } if (frame_pointer_needed) { /* If not an i386, mov & pop is faster than "leave". */ if (TARGET_USE_LEAVE) { if (do_rtl) emit_insn (gen_leave()); else output_asm_insn ("leave", xops); } else { xops[0] = frame_pointer_rtx; xops[1] = stack_pointer_rtx; if (do_rtl) { emit_insn (gen_epilogue_set_stack_ptr()); emit_insn (gen_pop (xops[0])); } else { output_asm_insn (AS2 (mov%L2,%0,%2), xops); output_asm_insn ("pop%L0 %0", xops); } } } else if (tsize) { /* Intel's docs say that for 4 or 8 bytes of stack frame one should use `pop' and not `add'. */ int use_pop = tsize == 4; /* Use two pops only for the Pentium processors. */ if (tsize == 8 && !TARGET_386 && !TARGET_486) { rtx retval = current_function_return_rtx; xops[1] = gen_rtx_REG (SImode, 1); /* %edx */ /* This case is a bit more complex. Since we cannot pop into %ecx twice we need a second register. But this is only available if the return value is not of DImode in which case the %edx register is not available. */ use_pop = (retval == NULL || ! reg_overlap_mentioned_p (xops[1], retval)); } if (use_pop) { xops[0] = gen_rtx_REG (SImode, 2); /* %ecx */ if (do_rtl) { /* We have to prevent the two pops here from being scheduled. GCC otherwise would try in some situation to put other instructions in between them which has a bad effect. */ emit_insn (gen_blockage ()); emit_insn (gen_pop (xops[0])); if (tsize == 8) emit_insn (gen_pop (xops[1])); } else { output_asm_insn ("pop%L0 %0", xops); if (tsize == 8) output_asm_insn ("pop%L1 %1", xops); } } else { /* If there is no frame pointer, we must still release the frame. */ xops[0] = GEN_INT (tsize); if (do_rtl) emit_insn (gen_rtx (SET, VOIDmode, xops[2], gen_rtx (PLUS, SImode, xops[2], xops[0]))); else output_asm_insn (AS2 (add%L2,%0,%2), xops); } }#ifdef FUNCTION_BLOCK_PROFILER_EXIT if (profile_block_flag == 2) { FUNCTION_BLOCK_PROFILER_EXIT(file); }#endif if (current_function_pops_args && current_function_args_size) { xops[1] = GEN_INT (current_function_pops_args); /* i386 can only pop 32K bytes (maybe 64K? Is it signed?). If asked to pop more, pop return address, do explicit add, and jump indirectly to the caller. */ if (current_function_pops_args >= 32768) { /* ??? Which register to use here? */ xops[0] = gen_rtx_REG (SImode, 2); if (do_rtl) { emit_insn (gen_pop (xops[0])); emit_insn (gen_rtx (SET, VOIDmode, xops[2], gen_rtx (PLUS, SImode, xops[1], xops[2]))); emit_jump_insn (xops[0]); } else { output_asm_insn ("pop%L0 %0", xops); output_asm_insn (AS2 (add%L2,%1,%2), xops); output_asm_insn ("jmp %*%0", xops); } } else { if (do_rtl) emit_jump_insn (gen_return_pop_internal (xops[1])); else output_asm_insn ("ret %1", xops); } } else { if (do_rtl) emit_jump_insn (gen_return_internal ()); else output_asm_insn ("ret", xops); }}/* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression that is a valid memory address for an instruction. The MODE argument is the machine mode for the MEM expression that wants to use this address. On x86, legitimate addresses are: base movl (base),reg displacement movl disp,reg base + displacement movl disp(base),reg index + base movl (base,index),reg (index + base) + displacement movl disp(base,index),reg index*scale movl (,index,scale),reg index*scale + disp movl disp(,index,scale),reg index*scale + base movl (base,index,scale),reg (index*scale + base) + disp movl disp(base,index,scale),reg In each case, scale can be 1, 2, 4, 8. *//* This is exactly the same as print_operand_addr, except that it recognizes addresses instead of printing them. It only recognizes address in canonical form. LEGITIMIZE_ADDRESS should convert common non-canonical forms to canonical form so that they will be recognized. */#define ADDR_INVALID(msg,insn) \do { \ if (TARGET_DEBUG_ADDR) \ { \ fprintf (stderr, msg); \ debug_rtx (insn); \ } \} while (0)intlegitimate_pic_address_disp_p (disp) register rtx disp;{ if (GET_CODE (disp) != CONST) return 0; disp = XEXP (disp, 0); if (GET_CODE (disp) == PLUS) { if (GET_CODE (XEXP (disp, 1)) != CONST_INT) return 0; disp = XEXP (disp, 0); } if (GET_CODE (disp) != UNSPEC || XVECLEN (disp, 0) != 1) return 0; /* Must be @GOT or @GOTOFF. */ if (XINT (disp, 1) != 6 && XINT (disp, 1) != 7) return 0; if (GET_CODE (XVECEXP (disp, 0, 0)) != SYMBOL_REF && GET_CODE (XVECEXP (disp, 0, 0)) != LABEL_REF) return 0; return 1;}intlegitimate_address_p (mode, addr, strict) enum machine_mode mode; register rtx addr; int strict;{ rtx base = NULL_RTX; rtx indx = NULL_RTX; rtx scale = NULL_RTX; rtx disp = NULL_RTX; if (TARGET_DEBUG_ADDR) { fprintf (stderr, "\n======\nGO_IF_LEGITIMATE_ADDRESS, mode = %s, strict = %d\n", GET_MODE_NAME (mode), strict); debug_rtx (addr); } if (GET_CODE (addr) == REG || GET_CODE (addr) == SUBREG) base = addr; else if (GET_CODE (addr) == PLUS) { rtx op0 = XEXP (addr, 0); rtx op1 = XEXP (addr, 1); enum rtx_code code0 = GET_CODE (op0); enum rtx_code code1 = GET_CODE (op1); if (code0 == REG || code0 == SUBREG) { if (code1 == REG || code1 == SUBREG) { indx = op0; /* index + base */ base = op1; } else { base = op0; /* base + displacement */ disp = op1; } } else if (code0 == MULT) { indx = XEXP (op0, 0); scale = XEXP (op0, 1); i
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -