📄 avr.c
字号:
/* Output to FILE the asm instructions to adjust the frame pointer by ADJ (r29:r28 -= ADJ;) which can be positive (prologue) or negative (epilogue). Returns the number of instructions generated. */static intout_adj_frame_ptr (file, adj) FILE *file; int adj;{ int size = 0; if (adj) { if (TARGET_TINY_STACK) { if (adj < -63 || adj > 63) warning ("large frame pointer change (%d) with -mtiny-stack", adj); /* The high byte (r29) doesn't change - prefer "subi" (1 cycle) over "sbiw" (2 cycles, same size). */ fprintf (file, (AS2 (subi, r28, %d) CR_TAB), adj); size++; } else if (adj < -63 || adj > 63) { fprintf (file, (AS2 (subi, r28, lo8(%d)) CR_TAB AS2 (sbci, r29, hi8(%d)) CR_TAB), adj, adj); size += 2; } else if (adj < 0) { fprintf (file, (AS2 (adiw, r28, %d) CR_TAB), -adj); size++; } else { fprintf (file, (AS2 (sbiw, r28, %d) CR_TAB), adj); size++; } } return size;}/* Output to FILE the asm instructions to copy r29:r28 to SPH:SPL, handling various cases of interrupt enable flag state BEFORE and AFTER (0=disabled, 1=enabled, -1=unknown/unchanged) and target_flags. Returns the number of instructions generated. */static intout_set_stack_ptr (file, before, after) FILE *file; int before; int after;{ int do_sph, do_cli, do_save, do_sei, lock_sph, size; /* The logic here is so that -mno-interrupts actually means "it is safe to write SPH in one instruction, then SPL in the next instruction, without disabling interrupts first". The after != -1 case (interrupt/signal) is not affected. */ do_sph = !TARGET_TINY_STACK; lock_sph = do_sph && !TARGET_NO_INTERRUPTS; do_cli = (before != 0 && (after == 0 || lock_sph)); do_save = (do_cli && before == -1 && after == -1); do_sei = ((do_cli || before != 1) && after == 1); size = 1; if (do_save) { fprintf (file, AS2 (in, __tmp_reg__, __SREG__) CR_TAB); size++; } if (do_cli) { fprintf (file, "cli" CR_TAB); size++; } /* Do SPH first - maybe this will disable interrupts for one instruction someday (a suggestion has been sent to avr@atmel.com for consideration in future devices - that would make -mno-interrupts always safe). */ if (do_sph) { fprintf (file, AS2 (out, __SP_H__, r29) CR_TAB); size++; } /* Set/restore the I flag now - interrupts will be really enabled only after the next instruction. This is not clearly documented, but believed to be true for all AVR devices. */ if (do_save) { fprintf (file, AS2 (out, __SREG__, __tmp_reg__) CR_TAB); size++; } else if (do_sei) { fprintf (file, "sei" CR_TAB); size++; } fprintf (file, AS2 (out, __SP_L__, r28) "\n"); return size;}/* Output function prologue */static voidavr_output_function_prologue (file, size) FILE *file; HOST_WIDE_INT size;{ int reg; int interrupt_func_p; int signal_func_p; int main_p; int live_seq; int minimize; last_insn_address = 0; jump_tables_size = 0; prologue_size = 0; fprintf (file, "/* prologue: frame size=%d */\n", size); if (avr_naked_function_p (current_function_decl)) { fputs ("/* prologue: naked */\n", file); goto out; } interrupt_func_p = interrupt_function_p (current_function_decl); signal_func_p = signal_function_p (current_function_decl); main_p = MAIN_NAME_P (DECL_NAME (current_function_decl)); live_seq = sequent_regs_live (); minimize = (TARGET_CALL_PROLOGUES && !interrupt_func_p && !signal_func_p && live_seq); if (interrupt_func_p) { fprintf (file,"\tsei\n"); ++prologue_size; } if (interrupt_func_p || signal_func_p) { fprintf (file, "\t" AS1 (push,__zero_reg__) CR_TAB AS1 (push,__tmp_reg__) CR_TAB AS2 (in,__tmp_reg__,__SREG__) CR_TAB AS1 (push,__tmp_reg__) CR_TAB AS1 (clr,__zero_reg__) "\n"); prologue_size += 5; } if (main_p) { fprintf (file, ("\t" AS2 (ldi,r28,lo8(%s - %d)) CR_TAB AS2 (ldi,r29,hi8(%s - %d)) CR_TAB AS2 (out,__SP_H__,r29) CR_TAB AS2 (out,__SP_L__,r28) "\n"), avr_init_stack, size, avr_init_stack, size); prologue_size += 4; } else if (minimize && (frame_pointer_needed || live_seq > 6)) { fprintf (file, ("\t" AS2 (ldi, r26, lo8(%d)) CR_TAB AS2 (ldi, r27, hi8(%d)) CR_TAB), size, size); fprintf (file, (AS2 (ldi, r30, pm_lo8(.L_%s_body)) CR_TAB AS2 (ldi, r31, pm_hi8(.L_%s_body)) CR_TAB) ,current_function_name, current_function_name); prologue_size += 4; if (AVR_MEGA) { fprintf (file, AS1 (jmp,__prologue_saves__+%d) "\n", (18 - live_seq) * 2); prologue_size += 2; } else { fprintf (file, AS1 (rjmp,__prologue_saves__+%d) "\n", (18 - live_seq) * 2); ++prologue_size; } fprintf (file, ".L_%s_body:\n", current_function_name); } else { HARD_REG_SET set; prologue_size += avr_regs_to_save (&set); for (reg = 0; reg < 32; ++reg) { if (TEST_HARD_REG_BIT (set, reg)) { fprintf (file, "\t" AS1 (push,%s) "\n", avr_regnames[reg]); } } if (frame_pointer_needed) { { fprintf (file, "\t" AS1 (push,r28) CR_TAB AS1 (push,r29) CR_TAB AS2 (in,r28,__SP_L__) CR_TAB AS2 (in,r29,__SP_H__) "\n"); prologue_size += 4; if (size) { fputs ("\t", file); prologue_size += out_adj_frame_ptr (file, size); if (interrupt_func_p) { prologue_size += out_set_stack_ptr (file, 1, 1); } else if (signal_func_p) { prologue_size += out_set_stack_ptr (file, 0, 0); } else { prologue_size += out_set_stack_ptr (file, -1, -1); } } } } } out: fprintf (file, "/* prologue end (size=%d) */\n", prologue_size);}/* Output function epilogue */static voidavr_output_function_epilogue (file, size) FILE *file; HOST_WIDE_INT size;{ int reg; int interrupt_func_p; int signal_func_p; int main_p; int function_size; int live_seq; int minimize; rtx last = get_last_nonnote_insn (); function_size = jump_tables_size; if (last) { rtx first = get_first_nonnote_insn (); function_size += (INSN_ADDRESSES (INSN_UID (last)) - INSN_ADDRESSES (INSN_UID (first))); function_size += get_attr_length (last); } fprintf (file, "/* epilogue: frame size=%d */\n", size); epilogue_size = 0; if (avr_naked_function_p (current_function_decl)) { fputs ("/* epilogue: naked */\n", file); goto out; } if (last && GET_CODE (last) == BARRIER) { fputs ("/* epilogue: noreturn */\n", file); goto out; } interrupt_func_p = interrupt_function_p (current_function_decl); signal_func_p = signal_function_p (current_function_decl); main_p = MAIN_NAME_P (DECL_NAME (current_function_decl)); live_seq = sequent_regs_live (); minimize = (TARGET_CALL_PROLOGUES && !interrupt_func_p && !signal_func_p && live_seq); if (main_p) { /* Return value from main() is already in the correct registers (r25:r24) as the exit() argument. */ if (AVR_MEGA) { fputs ("\t" AS1 (jmp,exit) "\n", file); epilogue_size += 2; } else { fputs ("\t" AS1 (rjmp,exit) "\n", file); ++epilogue_size; } } else if (minimize && (frame_pointer_needed || live_seq > 4)) { fprintf (file, ("\t" AS2 (ldi, r30, %d) CR_TAB), live_seq); ++epilogue_size; if (frame_pointer_needed) { epilogue_size += out_adj_frame_ptr (file, -size); } else { fprintf (file, (AS2 (in , r28, __SP_L__) CR_TAB AS2 (in , r29, __SP_H__) CR_TAB)); epilogue_size += 2; } if (AVR_MEGA) { fprintf (file, AS1 (jmp,__epilogue_restores__+%d) "\n", (18 - live_seq) * 2); epilogue_size += 2; } else { fprintf (file, AS1 (rjmp,__epilogue_restores__+%d) "\n", (18 - live_seq) * 2); ++epilogue_size; } } else { HARD_REG_SET set; if (frame_pointer_needed) { if (size) { fputs ("\t", file); epilogue_size += out_adj_frame_ptr (file, -size); if (interrupt_func_p || signal_func_p) { epilogue_size += out_set_stack_ptr (file, -1, 0); } else { epilogue_size += out_set_stack_ptr (file, -1, -1); } } fprintf (file, "\t" AS1 (pop,r29) CR_TAB AS1 (pop,r28) "\n"); epilogue_size += 2; } epilogue_size += avr_regs_to_save (&set); for (reg = 31; reg >= 0; --reg) { if (TEST_HARD_REG_BIT (set, reg)) { fprintf (file, "\t" AS1 (pop,%s) "\n", avr_regnames[reg]); } } if (interrupt_func_p || signal_func_p) { fprintf (file, "\t" AS1 (pop,__tmp_reg__) CR_TAB AS2 (out,__SREG__,__tmp_reg__) CR_TAB AS1 (pop,__tmp_reg__) CR_TAB AS1 (pop,__zero_reg__) "\n"); epilogue_size += 4; fprintf (file, "\treti\n"); } else fprintf (file, "\tret\n"); ++epilogue_size; } out: fprintf (file, "/* epilogue end (size=%d) */\n", epilogue_size); fprintf (file, "/* function %s size %d (%d) */\n", current_function_name, prologue_size + function_size + epilogue_size, function_size); commands_in_file += prologue_size + function_size + epilogue_size; commands_in_prologues += prologue_size; commands_in_epilogues += epilogue_size;}/* Return nonzero if X (an RTX) is a legitimate memory address on the target machine for a memory operand of mode MODE. */intlegitimate_address_p (mode, x, strict) enum machine_mode mode; rtx x; int strict;{ enum reg_class r = NO_REGS; if (TARGET_ALL_DEBUG) { fprintf (stderr, "mode: (%s) %s %s %s %s:", GET_MODE_NAME(mode), strict ? "(strict)": "", reload_completed ? "(reload_completed)": "", reload_in_progress ? "(reload_in_progress)": "", reg_renumber ? "(reg_renumber)" : ""); if (GET_CODE (x) == PLUS && REG_P (XEXP (x, 0)) && GET_CODE (XEXP (x, 1)) == CONST_INT && INTVAL (XEXP (x, 1)) >= 0 && INTVAL (XEXP (x, 1)) <= MAX_LD_OFFSET (mode) && reg_renumber ) fprintf (stderr, "(r%d ---> r%d)", REGNO (XEXP (x, 0)), true_regnum (XEXP (x, 0))); debug_rtx (x); } if (REG_P (x) && (strict ? REG_OK_FOR_BASE_STRICT_P (x) : REG_OK_FOR_BASE_NOSTRICT_P (x))) r = POINTER_REGS; else if (CONSTANT_ADDRESS_P (x)) r = ALL_REGS; else if (GET_CODE (x) == PLUS && REG_P (XEXP (x, 0)) && GET_CODE (XEXP (x, 1)) == CONST_INT && INTVAL (XEXP (x, 1)) >= 0) { int fit = INTVAL (XEXP (x, 1)) <= MAX_LD_OFFSET (mode); if (fit) { if (! strict || REGNO (XEXP (x,0)) == REG_Y || REGNO (XEXP (x,0)) == REG_Z) r = BASE_POINTER_REGS; if (XEXP (x,0) == frame_pointer_rtx || XEXP (x,0) == arg_pointer_rtx) r = BASE_POINTER_REGS; } else if (frame_pointer_needed && XEXP (x,0) == frame_pointer_rtx) r = POINTER_Y_REGS; } else if ((GET_CODE (x) == PRE_DEC || GET_CODE (x) == POST_INC) && REG_P (XEXP (x, 0)) && (strict ? REG_OK_FOR_BASE_STRICT_P (XEXP (x, 0)) : REG_OK_FOR_BASE_NOSTRICT_P (XEXP (x, 0)))) { r = POINTER_REGS; } if (TARGET_ALL_DEBUG) { fprintf (stderr, " ret = %c\n", r); } return r == NO_REGS ? 0 : (int)r;}/* Attempts to replace X with a valid memory address for an operand of mode MODE */rtxlegitimize_address (x, oldx, mode) rtx x; rtx oldx; enum machine_mode mode;{ x = oldx; if (TARGET_ALL_DEBUG) { fprintf (stderr, "legitimize_address mode: %s", GET_MODE_NAME(mode)); debug_rtx (oldx); } if (GET_CODE (oldx) == PLUS && REG_P (XEXP (oldx,0))) { if (REG_P (XEXP (oldx,1))) x = force_reg (GET_MODE (oldx), oldx); else if (GET_CODE (XEXP (oldx, 1)) == CONST_INT) { int offs = INTVAL (XEXP (oldx,1)); if (frame_pointer_rtx != XEXP (oldx,0)) if (offs > MAX_LD_OFFSET (mode)) { if (TARGET_ALL_DEBUG) fprintf (stderr, "force_reg (big offset)\n"); x = force_reg (GET_MODE (oldx), oldx); } } } return x;}/* Return a pointer register name as a string */static const char *ptrreg_to_str (regno) int regno;{ switch (regno) { case REG_X: return "X"; case REG_Y: return "Y"; case REG_Z: return "Z";
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -