📄 fr30.c
字号:
insn = emit_insn (gen_movsi (tmp, GEN_INT (current_frame_info.frame_size))); RTX_FRAME_RELATED_P (insn) = 1; insn = emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx, tmp)); RTX_FRAME_RELATED_P (insn) = 1; } if (current_function_profile) emit_insn (gen_blockage ());}/* Called after register allocation to add any instructions needed for the epilogue. Using an epilogue insn is favored compared to putting all of the instructions in output_function_epilogue(), since it allows the scheduler to intermix instructions with the restores of the caller saved registers. In some cases, it might be necessary to emit a barrier instruction as the first insn to prevent such scheduling. */voidfr30_expand_epilogue (void){ int regno; /* Perform the inversion operations of the prologue. */ if (! current_frame_info.initialised) abort (); /* Pop local variables and arguments off the stack. If frame_pointer_needed is TRUE then the frame pointer register has actually been used as a frame pointer, and we can recover the stack pointer from it, otherwise we must unwind the stack manually. */ if (current_frame_info.frame_size > 0) { if (current_frame_info.save_fp && frame_pointer_needed) { emit_insn (gen_leave_func ()); current_frame_info.save_fp = 0; } else if (current_frame_info.frame_size <= 508) emit_insn (gen_add_to_stack (GEN_INT (current_frame_info.frame_size))); else { rtx tmp = gen_rtx_REG (Pmode, PROLOGUE_TMP_REGNUM); emit_insn (gen_movsi (tmp, GEN_INT (current_frame_info.frame_size))); emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, tmp)); } } if (current_frame_info.save_fp) emit_insn (gen_movsi_pop (frame_pointer_rtx)); /* Pop all the registers that were pushed. */ if (current_frame_info.save_rp) emit_insn (gen_movsi_pop (gen_rtx_REG (Pmode, RETURN_POINTER_REGNUM))); for (regno = 0; regno < STACK_POINTER_REGNUM; regno ++) if (current_frame_info.gmask & (1 << regno)) emit_insn (gen_movsi_pop (gen_rtx_REG (Pmode, regno))); if (current_frame_info.pretend_size) emit_insn (gen_add_to_stack (GEN_INT (current_frame_info.pretend_size))); /* Reset state info for each function. */ current_frame_info = zero_frame_info; emit_jump_insn (gen_return_from_func ());}/* Do any needed setup for a variadic function. We must create a register parameter block, and then copy any anonymous arguments, plus the last named argument, from registers into memory. * copying actually done in fr30_expand_prologue(). ARG_REGS_USED_SO_FAR has *not* been updated for the last named argument which has type TYPE and mode MODE, and we rely on this fact. */voidfr30_setup_incoming_varargs (CUMULATIVE_ARGS *arg_regs_used_so_far, enum machine_mode mode, tree type ATTRIBUTE_UNUSED, int *pretend_size, int second_time ATTRIBUTE_UNUSED){ int size; /* All BLKmode values are passed by reference. */ if (mode == BLKmode) abort (); /* ??? This run-time test as well as the code inside the if statement is probably unnecessary. */ if (targetm.calls.strict_argument_naming (arg_regs_used_so_far)) /* If TARGET_STRICT_ARGUMENT_NAMING returns true, then the last named arg must not be treated as an anonymous arg. */ arg_regs_used_so_far += fr30_num_arg_regs (mode, type); size = FR30_NUM_ARG_REGS - (* arg_regs_used_so_far); if (size <= 0) return; * pretend_size = (size * UNITS_PER_WORD);}/*}}}*//*{{{ Printing operands */ /* Print a memory address as an operand to reference that memory location. */voidfr30_print_operand_address (FILE *stream, rtx address){ switch (GET_CODE (address)) { case SYMBOL_REF: output_addr_const (stream, address); break; default: fprintf (stderr, "code = %x\n", GET_CODE (address)); debug_rtx (address); output_operand_lossage ("fr30_print_operand_address: unhandled address"); break; }}/* Print an operand. */voidfr30_print_operand (FILE *file, rtx x, int code){ rtx x0; switch (code) { case '#': /* Output a :D if this instruction is delayed. */ if (dbr_sequence_length () != 0) fputs (":D", file); return; case 'p': /* Compute the register name of the second register in a hi/lo register pair. */ if (GET_CODE (x) != REG) output_operand_lossage ("fr30_print_operand: unrecognized %%p code"); else fprintf (file, "r%d", REGNO (x) + 1); return; case 'b': /* Convert GCC's comparison operators into FR30 comparison codes. */ switch (GET_CODE (x)) { case EQ: fprintf (file, "eq"); break; case NE: fprintf (file, "ne"); break; case LT: fprintf (file, "lt"); break; case LE: fprintf (file, "le"); break; case GT: fprintf (file, "gt"); break; case GE: fprintf (file, "ge"); break; case LTU: fprintf (file, "c"); break; case LEU: fprintf (file, "ls"); break; case GTU: fprintf (file, "hi"); break; case GEU: fprintf (file, "nc"); break; default: output_operand_lossage ("fr30_print_operand: unrecognized %%b code"); break; } return; case 'B': /* Convert GCC's comparison operators into the complimentary FR30 comparison codes. */ switch (GET_CODE (x)) { case EQ: fprintf (file, "ne"); break; case NE: fprintf (file, "eq"); break; case LT: fprintf (file, "ge"); break; case LE: fprintf (file, "gt"); break; case GT: fprintf (file, "le"); break; case GE: fprintf (file, "lt"); break; case LTU: fprintf (file, "nc"); break; case LEU: fprintf (file, "hi"); break; case GTU: fprintf (file, "ls"); break; case GEU: fprintf (file, "c"); break; default: output_operand_lossage ("fr30_print_operand: unrecognized %%B code"); break; } return; case 'A': /* Print a signed byte value as an unsigned value. */ if (GET_CODE (x) != CONST_INT) output_operand_lossage ("fr30_print_operand: invalid operand to %%A code"); else { HOST_WIDE_INT val; val = INTVAL (x); val &= 0xff; fprintf (file, HOST_WIDE_INT_PRINT_DEC, val); } return; case 'x': if (GET_CODE (x) != CONST_INT || INTVAL (x) < 16 || INTVAL (x) > 32) output_operand_lossage ("fr30_print_operand: invalid %%x code"); else fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x) - 16); return; case 'F': if (GET_CODE (x) != CONST_DOUBLE) output_operand_lossage ("fr30_print_operand: invalid %%F code"); else { char str[30]; real_to_decimal (str, CONST_DOUBLE_REAL_VALUE (x), sizeof (str), 0, 1); fputs (str, file); } return; case 0: /* Handled below. */ break; default: fprintf (stderr, "unknown code = %x\n", code); output_operand_lossage ("fr30_print_operand: unknown code"); return; } switch (GET_CODE (x)) { case REG: fputs (reg_names [REGNO (x)], file); break; case MEM: x0 = XEXP (x,0); switch (GET_CODE (x0)) { case REG: if ((unsigned) REGNO (x0) >= ARRAY_SIZE (reg_names)) abort (); fprintf (file, "@%s", reg_names [REGNO (x0)]); break; case PLUS: if (GET_CODE (XEXP (x0, 0)) != REG || REGNO (XEXP (x0, 0)) < FRAME_POINTER_REGNUM || REGNO (XEXP (x0, 0)) > STACK_POINTER_REGNUM || GET_CODE (XEXP (x0, 1)) != CONST_INT) { fprintf (stderr, "bad INDEXed address:"); debug_rtx (x); output_operand_lossage ("fr30_print_operand: unhandled MEM"); } else if (REGNO (XEXP (x0, 0)) == FRAME_POINTER_REGNUM) { HOST_WIDE_INT val = INTVAL (XEXP (x0, 1)); if (val < -(1 << 9) || val > ((1 << 9) - 4)) { fprintf (stderr, "frame INDEX out of range:"); debug_rtx (x); output_operand_lossage ("fr30_print_operand: unhandled MEM"); } fprintf (file, "@(r14, #" HOST_WIDE_INT_PRINT_DEC ")", val); } else { HOST_WIDE_INT val = INTVAL (XEXP (x0, 1)); if (val < 0 || val > ((1 << 6) - 4)) { fprintf (stderr, "stack INDEX out of range:"); debug_rtx (x); output_operand_lossage ("fr30_print_operand: unhandled MEM"); } fprintf (file, "@(r15, #" HOST_WIDE_INT_PRINT_DEC ")", val); } break; case SYMBOL_REF: output_address (x0); break; default: fprintf (stderr, "bad MEM code = %x\n", GET_CODE (x0)); debug_rtx (x); output_operand_lossage ("fr30_print_operand: unhandled MEM"); break; } break; case CONST_DOUBLE : /* We handle SFmode constants here as output_addr_const doesn't. */ if (GET_MODE (x) == SFmode) { REAL_VALUE_TYPE d; long l; REAL_VALUE_FROM_CONST_DOUBLE (d, x); REAL_VALUE_TO_TARGET_SINGLE (d, l); fprintf (file, "0x%08lx", l); break; } /* Fall through. Let output_addr_const deal with it. */ default: output_addr_const (file, x); break; } return;}/*}}}*//*{{{ Function arguments */ /* Return true if we should pass an argument on the stack rather than in registers. */static boolfr30_must_pass_in_stack (enum machine_mode mode, tree type){ if (mode == BLKmode) return true; if (type == NULL) return false; return AGGREGATE_TYPE_P (type);}/* Compute the number of word sized registers needed to hold a function argument of mode INT_MODE and tree type TYPE. */intfr30_num_arg_regs (enum machine_mode mode, tree type){ int size; if (targetm.calls.must_pass_in_stack (mode, type))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -