📄 i386.c
字号:
"$_GLOBAL_OFFSET_TABLE_"), xops[1])); } else { output_asm_insn (AS1 (call,%P1), xops); output_asm_insn ("addl $_GLOBAL_OFFSET_TABLE_,%0", xops); pic_label_rtx = 0; } } else { xops[0] = pic_offset_table_rtx; xops[1] = gen_label_rtx (); if (do_rtl) { /* We can't put a raw CODE_LABEL into the RTL, and we can't emit a new CODE_LABEL after reload, so we need a single pattern to emit the 3 necessary instructions. */ emit_insn (gen_prologue_get_pc_and_set_got (xops[0])); } else { output_asm_insn (AS1 (call,%P1), xops); ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (xops[1])); output_asm_insn (AS1 (pop%L0,%0), xops); output_asm_insn ("addl $_GLOBAL_OFFSET_TABLE_+[.-%P1],%0", xops); } } /* 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. */ if (do_rtl) emit_insn (gen_blockage ());}static voidix86_prologue (do_rtl) int do_rtl;{ register int regno; int limit; rtx xops[4]; int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table || current_function_uses_const_pool); long tsize = get_frame_size (); rtx insn; int cfa_offset = INCOMING_FRAME_SP_OFFSET, cfa_store_offset = cfa_offset; xops[0] = stack_pointer_rtx; xops[1] = frame_pointer_rtx; xops[2] = GEN_INT (tsize); if (frame_pointer_needed) { if (do_rtl) { insn = emit_insn (gen_rtx (SET, VOIDmode, gen_rtx (MEM, SImode, gen_rtx (PRE_DEC, SImode, stack_pointer_rtx)), frame_pointer_rtx)); RTX_FRAME_RELATED_P (insn) = 1; insn = emit_move_insn (xops[1], xops[0]); RTX_FRAME_RELATED_P (insn) = 1; } else { output_asm_insn ("push%L1 %1", xops); #ifdef INCOMING_RETURN_ADDR_RTX if (dwarf2out_do_frame ()) { char *l = dwarf2out_cfi_label (); cfa_store_offset += 4; cfa_offset = cfa_store_offset; dwarf2out_def_cfa (l, STACK_POINTER_REGNUM, cfa_offset); dwarf2out_reg_save (l, FRAME_POINTER_REGNUM, - cfa_store_offset); }#endif output_asm_insn (AS2 (mov%L0,%0,%1), xops); #ifdef INCOMING_RETURN_ADDR_RTX if (dwarf2out_do_frame ()) dwarf2out_def_cfa ("", FRAME_POINTER_REGNUM, cfa_offset);#endif } } if (tsize == 0) ; else if (! TARGET_STACK_PROBE || tsize < CHECK_STACK_LIMIT) { if (do_rtl) { insn = emit_insn (gen_prologue_set_stack_ptr (xops[2])); RTX_FRAME_RELATED_P (insn) = 1; } else { output_asm_insn (AS2 (sub%L0,%2,%0), xops);#ifdef INCOMING_RETURN_ADDR_RTX if (dwarf2out_do_frame ()) { cfa_store_offset += tsize; if (! frame_pointer_needed) { 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 } } 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; int size;{ 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 nregs, limit; int offset; rtx xops[3]; int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table || current_function_uses_const_pool); long tsize = get_frame_size (); /* Compute the number of registers to pop */ limit = (frame_pointer_needed ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM); nregs = 0; for (regno = limit - 1; regno >= 0; regno--) if ((regs_ever_live[regno] && ! call_used_regs[regno]) || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used)) nregs++; /* sp is often unreliable so we must go off the frame pointer. In reality, we may not care if sp is unreliable, because we can restore the register relative to the frame pointer. In theory, since each move is the same speed as a pop, and we don't need the leal, this is faster. For now restore multiple registers the old way. */ 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 (nregs > 1 || ! frame_pointer_needed) { if (frame_pointer_needed) { 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) { /* 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_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); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -