📄 thumb.c
字号:
asm_fprintf (asm_out_file, reg_names[regno]); if (live_regs_mask & ~1) asm_fprintf (asm_out_file, ", "); } if ( TARGET_THUMB_INTERWORK || TARGET_BACKTRACE || is_called_in_ARM_mode (current_function_decl)) { asm_fprintf (asm_out_file, "}\n"); thumb_exit (asm_out_file, -1); } else asm_fprintf (asm_out_file, ", pc}\n"); } return "";}voidthumb_function_prologue (f, frame_size) FILE *f; int frame_size;{ int amount = frame_size + current_function_outgoing_args_size; int live_regs_mask = 0; int high_regs_pushed = 0; int store_arg_regs = 0; int regno; if (is_called_in_ARM_mode (current_function_decl)) { char * name; if (GET_CODE (DECL_RTL (current_function_decl)) != MEM) abort(); if (GET_CODE (XEXP (DECL_RTL (current_function_decl), 0)) != SYMBOL_REF) abort(); name = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0); /* Generate code sequence to switch us into Thumb mode. */ /* The .code 32 directive has already been emitted by ASM_DECLARE_FUNCITON_NAME */ asm_fprintf (f, "\torr\tr12, pc, #1\n"); asm_fprintf (f, "\tbx\tr12\n"); /* Generate a label, so that the debugger will notice the change in instruction sets. This label is also used by the assembler to bypass the ARM code when this function is called from a Thumb encoded function elsewhere in the same file. Hence the definition of STUB_NAME here must agree with the definition in gas/config/tc-arm.c */ #define STUB_NAME ".real_start_of" asm_fprintf (f, "\t.code\t16\n"); asm_fprintf (f, "\t.globl %s%U%s\n", STUB_NAME, name); asm_fprintf (f, "\t.thumb_func\n"); asm_fprintf (f, "%s%U%s:\n", STUB_NAME, name); } if (current_function_anonymous_args && current_function_pretend_args_size) store_arg_regs = 1; if (current_function_pretend_args_size) { if (store_arg_regs) { asm_fprintf (f, "\tpush\t{"); for (regno = 4 - current_function_pretend_args_size / 4 ; regno < 4; regno++) asm_fprintf (f, "%s%s", reg_names[regno], regno == 3 ? "" : ", "); asm_fprintf (f, "}\n"); } else asm_fprintf (f, "\tsub\t%Rsp, %Rsp, #%d\n", current_function_pretend_args_size); } for (regno = 0; regno < 8; regno++) if (regs_ever_live[regno] && ! call_used_regs[regno]) live_regs_mask |= 1 << regno; if (live_regs_mask || ! leaf_function_p () || far_jump_used_p()) live_regs_mask |= 1 << 14; if (TARGET_BACKTRACE) { char * name; int offset; int work_register = 0; /* We have been asked to create a stack backtrace structure. The code looks like this: 0 .align 2 0 func: 0 sub SP, #16 Reserve space for 4 registers. 2 push {R7} Get a work register. 4 add R7, SP, #20 Get the stack pointer before the push. 6 str R7, [SP, #8] Store the stack pointer (before reserving the space). 8 mov R7, PC Get hold of the start of this code plus 12. 10 str R7, [SP, #16] Store it. 12 mov R7, FP Get hold of the current frame pointer. 14 str R7, [SP, #4] Store it. 16 mov R7, LR Get hold of the current return address. 18 str R7, [SP, #12] Store it. 20 add R7, SP, #16 Point at the start of the backtrace structure. 22 mov FP, R7 Put this value into the frame pointer. */ if ((live_regs_mask & 0xFF) == 0) { /* See if the a4 register is free. */ if (regs_ever_live[ 3 ] == 0) work_register = 3; else /* We must push a register of our own */ live_regs_mask |= (1 << 7); } if (work_register == 0) { /* Select a register from the list that will be pushed to use as our work register. */ for (work_register = 8; work_register--;) if ((1 << work_register) & live_regs_mask) break; } name = reg_names[ work_register ]; asm_fprintf (f, "\tsub\tsp, sp, #16\t@ Create stack backtrace structure\n"); if (live_regs_mask) thumb_pushpop (f, live_regs_mask, 1); for (offset = 0, work_register = 1 << 15; work_register; work_register >>= 1) if (work_register & live_regs_mask) offset += 4; asm_fprintf (f, "\tadd\t%s, sp, #%d\n", name, offset + 16 + current_function_pretend_args_size); asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset + 4); /* Make sure that the instruction fetching the PC is in the right place to calculate "start of backtrace creation code + 12". */ if (live_regs_mask) { asm_fprintf (f, "\tmov\t%s, pc\n", name); asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset + 12); asm_fprintf (f, "\tmov\t%s, fp\n", name); asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset); } else { asm_fprintf (f, "\tmov\t%s, fp\n", name); asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset); asm_fprintf (f, "\tmov\t%s, pc\n", name); asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset + 12); } asm_fprintf (f, "\tmov\t%s, lr\n", name); asm_fprintf (f, "\tstr\t%s, [sp, #%d]\n", name, offset + 8); asm_fprintf (f, "\tadd\t%s, sp, #%d\n", name, offset + 12); asm_fprintf (f, "\tmov\tfp, %s\t\t@ Backtrace structure created\n", name); } else if (live_regs_mask) thumb_pushpop (f, live_regs_mask, 1); for (regno = 8; regno < 13; regno++) { if (regs_ever_live[regno] && ! call_used_regs[regno]) high_regs_pushed++; } if (high_regs_pushed) { int pushable_regs = 0; int mask = live_regs_mask & 0xff; int next_hi_reg; for (next_hi_reg = 12; next_hi_reg > 7; next_hi_reg--) { if (regs_ever_live[next_hi_reg] && ! call_used_regs[next_hi_reg]) break; } pushable_regs = mask; if (pushable_regs == 0) { /* desperation time -- this probably will never happen */ if (regs_ever_live[3] || ! call_used_regs[3]) asm_fprintf (f, "\tmov\t%s, %s\n", reg_names[12], reg_names[3]); mask = 1 << 3; } while (high_regs_pushed > 0) { for (regno = 7; regno >= 0; regno--) { if (mask & (1 << regno)) { asm_fprintf (f, "\tmov\t%s, %s\n", reg_names[regno], reg_names[next_hi_reg]); high_regs_pushed--; if (high_regs_pushed) for (next_hi_reg--; next_hi_reg > 7; next_hi_reg--) { if (regs_ever_live[next_hi_reg] && ! call_used_regs[next_hi_reg]) break; } else { mask &= ~ ((1 << regno) - 1); break; } } } thumb_pushpop (f, mask, 1); } if (pushable_regs == 0 && (regs_ever_live[3] || ! call_used_regs[3])) asm_fprintf (f, "\tmov\t%s, %s\n", reg_names[3], reg_names[12]); }}voidthumb_expand_prologue (){ HOST_WIDE_INT amount = (get_frame_size () + current_function_outgoing_args_size); int regno; int live_regs_mask; if (amount) { live_regs_mask = 0; for (regno = 0; regno < 8; regno++) if (regs_ever_live[regno] && ! call_used_regs[regno]) live_regs_mask |= 1 << regno; if (amount < 512) emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, GEN_INT (-amount))); else { rtx reg, spare; if ((live_regs_mask & 0xff) == 0) /* Very unlikely */ emit_insn (gen_movsi (spare = gen_rtx (REG, SImode, 12), reg = gen_rtx (REG, SImode, 4))); else { for (regno = 0; regno < 8; regno++) if (live_regs_mask & (1 << regno)) break; reg = gen_rtx (REG, SImode, regno); } emit_insn (gen_movsi (reg, GEN_INT (-amount))); emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, reg)); if ((live_regs_mask & 0xff) == 0) emit_insn (gen_movsi (reg, spare)); } } if (frame_pointer_needed) { if (current_function_outgoing_args_size) { rtx offset = GEN_INT (current_function_outgoing_args_size); if (current_function_outgoing_args_size < 1024) emit_insn (gen_addsi3 (frame_pointer_rtx, stack_pointer_rtx, offset)); else { emit_insn (gen_movsi (frame_pointer_rtx, offset)); emit_insn (gen_addsi3 (frame_pointer_rtx, frame_pointer_rtx, stack_pointer_rtx)); } } else emit_insn (gen_movsi (frame_pointer_rtx, stack_pointer_rtx)); } /* if (profile_flag || profile_block_flag) */ emit_insn (gen_blockage ());}voidthumb_expand_epilogue (){ HOST_WIDE_INT amount = (get_frame_size () + current_function_outgoing_args_size); int regno; if (amount) { if (amount < 512) emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, GEN_INT (amount))); else { rtx reg = gen_rtx (REG, SImode, 3); /* Always free in the epilogue */ emit_insn (gen_movsi (reg, GEN_INT (amount))); emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, reg)); } /* if (profile_flag || profile_block_flag) */ emit_insn (gen_blockage ()); }}voidthumb_function_epilogue (f, frame_size) FILE *f; int frame_size;{ /* ??? Probably not safe to set this here, since it assumes that a function will be emitted as assembly immediately after we generate RTL for it. This does not happen for inline functions. */ return_used_this_function = 0;#if 0 /* TODO : comment not really needed */ fprintf (f, "%s THUMB Epilogue\n", ASM_COMMENT_START);#endif}/* The bits which aren't usefully expanded as rtl. */char *thumb_unexpanded_epilogue (){ int regno; int live_regs_mask = 0; int high_regs_pushed = 0; int leaf_function = leaf_function_p (); int had_to_push_lr; if (return_used_this_function) return ""; for (regno = 0; regno < 8; regno++) if (regs_ever_live[regno] && ! call_used_regs[regno]) live_regs_mask |= 1 << regno; for (regno = 8; regno < 13; regno++) { if (regs_ever_live[regno] && ! call_used_regs[regno]) high_regs_pushed ++; } /* The prolog may have pushed some high registers to use as work registers. eg the testuite file: gcc/testsuite/gcc/gcc.c-torture/execute/complex-2.c compiles to produce: push {r4, r5, r6, r7, lr} mov r7, r9 mov r6, r8 push {r6, r7} as part of the prolog. We have to undo that pushing here. */ if (high_regs_pushed) { int mask = live_regs_mask; int next_hi_reg; int size; int mode; #ifdef RTX_CODE /* If we can deduce the registers used from the function's return value. This is more reliable that examining regs_ever_live[] because that will be set if the register is ever used in the function, not just if the register is used to hold a return value. */ if (current_function_return_rtx != 0) { mode = GET_MODE (current_function_return_rtx); } else#endif { mode = DECL_MODE (DECL_RESULT (current_function_decl)); } size = GET_MODE_SIZE (mode); /* Unless we are returning a type of size > 12 register r3 is available. */ if (size < 13) mask |= 1 << 3; if (mask == 0) { /* Oh dear! We have no low registers into which we can pop high registers! */ fatal ("No low registers available for popping high registers"); } for (next_hi_reg = 8; next_hi_reg < 13; next_hi_reg++) if (regs_ever_live[next_hi_reg] && ! call_used_regs[next_hi_reg]) break; while (high_regs_pushed) { /* Find low register(s) into which the high register(s) can be popped. */ for (regno = 0; regno < 8; regno++) { if (mask & (1 << regno)) high_regs_pushed--; if (high_regs_pushed == 0) break; } mask &= (2 << regno) - 1; /* A noop if regno == 8 */ /* Pop the values into the low register(s). */ thumb_pushpop (asm_out_file, mask, 0); /* Move the value(s) into the high registers. */ for (regno = 0; regno < 8; regno++) { if (mask & (1 << regno)) { asm_fprintf (asm_out_file, "\tmov\t%s, %s\n", reg_names[next_hi_reg], reg_names[regno]); for (next_hi_reg++; next_hi_reg < 13; next_hi_reg++) if (regs_ever_live[next_hi_reg] && ! call_used_regs[next_hi_reg]) break; } } } } had_to_push_lr = (live_regs_mask || ! leaf_function || far_jump_used_p()); if (TARGET_BACKTRACE && ((live_regs_mask & 0xFF) == 0) && regs_ever_live[ ARG_4_REGISTER ] != 0) { /* The stack backtrace structure creation code had to push R7 in order to get a work register, so we pop it now. */ live_regs_mask |= (1 << WORK_REGISTER); } if (current_function_pretend_args_size == 0 || TARGET_BACKTRACE) { if (had_to_push_lr && ! is_called_in_ARM_mode (current_function_decl)) live_regs_mask |= 1 << PROGRAM_COUNTER; /* Either no argument registers were pushed or a backtrace structure was created which includes an adjusted stack pointer, so just pop everything. */ if (live_regs_mask) thumb_pushpop (asm_out_file, live_regs_mask, FALSE); /* We have either just popped the return address into the PC or it is was kept in LR for the entire function or it is still on the stack because we do not want to return by doing a pop {pc}. */ if ((live_regs_mask & (1 << PROGRAM_COUNTER)) == 0) thumb_exit (asm_out_file, (had_to_push_lr && is_called_in_ARM_mode (current_function_decl)) ? -1 : LINK_REGISTER); } else { /* Pop everything but the return address. */ live_regs_mask &= ~ (1 << PROGRAM_COUNTER); if (live_regs_mask) thumb_pushpop (asm_out_file, live_regs_mask, FALSE); if (had_to_push_lr) { /* Get the return address into a temporary register. */ thumb_pushpop (asm_out_file, 1 << ARG_4_REGISTER, 0); } /* Remove the argument registers that were pushed onto the stack. */ asm_fprintf (asm_out_file, "\tadd\t%s, %s, #%d\n", reg_names [STACK_POINTER], reg_names [STACK_POINTER], current_function_pretend_args_size); thumb_exit (asm_out_file, had_to_push_lr ? ARG_4_REGISTER : LINK_REGISTER); } return "";}/* Handle the case of a double word load into a low register from
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -