📄 bfin.c
字号:
do_unlink (spreg, get_frame_size (), false); expand_epilogue_reg_restore (spreg, false, false); /* Omit the return insn if this is for a sibcall. */ if (! need_return) return; if (eh_return) emit_insn (gen_addsi3 (spreg, spreg, gen_rtx_REG (Pmode, REG_P2))); emit_jump_insn (gen_return_internal (GEN_INT (SUBROUTINE)));}/* Return nonzero if register OLD_REG can be renamed to register NEW_REG. */intbfin_hard_regno_rename_ok (unsigned int old_reg ATTRIBUTE_UNUSED, unsigned int new_reg){ /* Interrupt functions can only use registers that have already been saved by the prologue, even if they would normally be call-clobbered. */ if (funkind (TREE_TYPE (current_function_decl)) != SUBROUTINE && !regs_ever_live[new_reg]) return 0; return 1;}/* Return the value of the return address for the frame COUNT steps up from the current frame, after the prologue. We punt for everything but the current frame by returning const0_rtx. */rtxbfin_return_addr_rtx (int count){ if (count != 0) return const0_rtx; return get_hard_reg_initial_val (Pmode, REG_RETS);}/* Try machine-dependent ways of modifying an illegitimate address X to be legitimate. If we find one, return the new, valid address, otherwise return NULL_RTX. OLDX is the address as it was before break_out_memory_refs was called. In some cases it is useful to look at this to decide what needs to be done. MODE is the mode of the memory reference. */rtxlegitimize_address (rtx x ATTRIBUTE_UNUSED, rtx oldx ATTRIBUTE_UNUSED, enum machine_mode mode ATTRIBUTE_UNUSED){ return NULL_RTX;}/* This predicate is used to compute the length of a load/store insn. OP is a MEM rtx, we return nonzero if its addressing mode requires a 32 bit instruction. */inteffective_address_32bit_p (rtx op, enum machine_mode mode) { HOST_WIDE_INT offset; mode = GET_MODE (op); op = XEXP (op, 0); if (GET_CODE (op) != PLUS) { gcc_assert (REG_P (op) || GET_CODE (op) == POST_INC || GET_CODE (op) == PRE_DEC || GET_CODE (op) == POST_DEC); return 0; } offset = INTVAL (XEXP (op, 1)); /* All byte loads use a 16 bit offset. */ if (GET_MODE_SIZE (mode) == 1) return 1; if (GET_MODE_SIZE (mode) == 4) { /* Frame pointer relative loads can use a negative offset, all others are restricted to a small positive one. */ if (XEXP (op, 0) == frame_pointer_rtx) return offset < -128 || offset > 60; return offset < 0 || offset > 60; } /* Must be HImode now. */ return offset < 0 || offset > 30;}/* Return cost of the memory address ADDR. All addressing modes are equally cheap on the Blackfin. */static intbfin_address_cost (rtx addr ATTRIBUTE_UNUSED){ return 1;}/* Subroutine of print_operand; used to print a memory reference X to FILE. */voidprint_address_operand (FILE *file, rtx x){ switch (GET_CODE (x)) { case PLUS: output_address (XEXP (x, 0)); fprintf (file, "+"); output_address (XEXP (x, 1)); break; case PRE_DEC: fprintf (file, "--"); output_address (XEXP (x, 0)); break; case POST_INC: output_address (XEXP (x, 0)); fprintf (file, "++"); break; case POST_DEC: output_address (XEXP (x, 0)); fprintf (file, "--"); break; default: gcc_assert (GET_CODE (x) != MEM); print_operand (file, x, 0); break; }}/* Adding intp DImode support by Tony * -- Q: (low word) * -- R: (high word) */voidprint_operand (FILE *file, rtx x, char code){ enum machine_mode mode = GET_MODE (x); switch (code) { case 'j': switch (GET_CODE (x)) { case EQ: fprintf (file, "e"); break; case NE: fprintf (file, "ne"); break; case GT: fprintf (file, "g"); break; case LT: fprintf (file, "l"); break; case GE: fprintf (file, "ge"); break; case LE: fprintf (file, "le"); break; case GTU: fprintf (file, "g"); break; case LTU: fprintf (file, "l"); break; case GEU: fprintf (file, "ge"); break; case LEU: fprintf (file, "le"); break; default: output_operand_lossage ("invalid %%j value"); } break; case 'J': /* reverse logic */ switch (GET_CODE(x)) { case EQ: fprintf (file, "ne"); break; case NE: fprintf (file, "e"); break; case GT: fprintf (file, "le"); break; case LT: fprintf (file, "ge"); break; case GE: fprintf (file, "l"); break; case LE: fprintf (file, "g"); break; case GTU: fprintf (file, "le"); break; case LTU: fprintf (file, "ge"); break; case GEU: fprintf (file, "l"); break; case LEU: fprintf (file, "g"); break; default: output_operand_lossage ("invalid %%J value"); } break; default: switch (GET_CODE (x)) { case REG: if (code == 'h') { gcc_assert (REGNO (x) < 32); fprintf (file, "%s", short_reg_names[REGNO (x)]); /*fprintf (file, "\n%d\n ", REGNO (x));*/ break; } else if (code == 'd') { gcc_assert (REGNO (x) < 32); fprintf (file, "%s", high_reg_names[REGNO (x)]); break; } else if (code == 'w') { gcc_assert (REGNO (x) == REG_A0 || REGNO (x) == REG_A1); fprintf (file, "%s.w", reg_names[REGNO (x)]); } else if (code == 'x') { gcc_assert (REGNO (x) == REG_A0 || REGNO (x) == REG_A1); fprintf (file, "%s.x", reg_names[REGNO (x)]); } else if (code == 'D') { fprintf (file, "%s", dregs_pair_names[REGNO (x)]); } else if (code == 'H') { gcc_assert (mode == DImode || mode == DFmode); gcc_assert (REG_P (x)); fprintf (file, "%s", reg_names[REGNO (x) + 1]); } else if (code == 'T') { gcc_assert (D_REGNO_P (REGNO (x))); fprintf (file, "%s", byte_reg_names[REGNO (x)]); } else fprintf (file, "%s", reg_names[REGNO (x)]); break; case MEM: fputc ('[', file); x = XEXP (x,0); print_address_operand (file, x); fputc (']', file); break; case CONST_INT: /* Moves to half registers with d or h modifiers always use unsigned constants. */ if (code == 'd') x = GEN_INT ((INTVAL (x) >> 16) & 0xffff); else if (code == 'h') x = GEN_INT (INTVAL (x) & 0xffff); else if (code == 'X') x = GEN_INT (exact_log2 (0xffffffff & INTVAL (x))); else if (code == 'Y') x = GEN_INT (exact_log2 (0xffffffff & ~INTVAL (x))); else if (code == 'Z') /* Used for LINK insns. */ x = GEN_INT (-8 - INTVAL (x)); /* fall through */ case SYMBOL_REF: output_addr_const (file, x); if (code == 'G' && flag_pic) fprintf (file, "@GOT"); break; case CONST_DOUBLE: output_operand_lossage ("invalid const_double operand"); break; case UNSPEC: switch (XINT (x, 1)) { case UNSPEC_MOVE_PIC: output_addr_const (file, XVECEXP (x, 0, 0)); fprintf (file, "@GOT"); break; case UNSPEC_LIBRARY_OFFSET: fprintf (file, "_current_shared_library_p5_offset_"); break; default: gcc_unreachable (); } break; default: output_addr_const (file, x); } }}/* Argument support functions. *//* Initialize a variable CUM of type CUMULATIVE_ARGS for a call to a function whose data type is FNTYPE. For a library call, FNTYPE is 0. VDSP C Compiler manual, our ABI says that first 3 words of arguments will use R0, R1 and R2.*/voidinit_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype, rtx libname ATTRIBUTE_UNUSED){ static CUMULATIVE_ARGS zero_cum; *cum = zero_cum; /* Set up the number of registers to use for passing arguments. */ cum->nregs = max_arg_registers; cum->arg_regs = arg_regs; cum->call_cookie = CALL_NORMAL; /* Check for a longcall attribute. */ if (fntype && lookup_attribute ("shortcall", TYPE_ATTRIBUTES (fntype))) cum->call_cookie |= CALL_SHORT; else if (fntype && lookup_attribute ("longcall", TYPE_ATTRIBUTES (fntype))) cum->call_cookie |= CALL_LONG; return;}/* Update the data in CUM to advance over an argument of mode MODE and data type TYPE. (TYPE is null for libcalls where that information may not be available.) */voidfunction_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type, int named ATTRIBUTE_UNUSED){ int count, bytes, words; bytes = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode); words = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD; cum->words += words; cum->nregs -= words; if (cum->nregs <= 0) { cum->nregs = 0; cum->arg_regs = NULL; } else { for (count = 1; count <= words; count++) cum->arg_regs++; } return;}/* Define where to put the arguments to a function. Value is zero to push the argument on the stack, or a hard register in which to store the argument. MODE is the argument's machine mode. TYPE is the data type of the argument (as a tree). This is null for libcalls where that information may not be available. CUM is a variable of type CUMULATIVE_ARGS which gives info about the preceding args and about the function being called. NAMED is nonzero if this argument is a named parameter (otherwise it is an extra parameter matching an ellipsis). */struct rtx_def *function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type, int named ATTRIBUTE_UNUSED){ int bytes = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode); if (mode == VOIDmode) /* Compute operand 2 of the call insn. */ return GEN_INT (cum->call_cookie); if (bytes == -1) return NULL_RTX; if (cum->nregs) return gen_rtx_REG (mode, *(cum->arg_regs)); return NULL_RTX;}/* For an arg passed partly in registers and partly in memory, this is the number of bytes passed in registers. For args passed entirely in registers or entirely in memory, zero. Refer VDSP C Compiler manual, our ABI. First 3 words are in registers. So, if a an argument is larger than the registers available, it will span the register and stack. */static intbfin_arg_partial_bytes (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type ATTRIBUTE_UNUSED, bool named ATTRIBUTE_UNUSED){ int bytes = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode); int bytes_left = cum->nregs * UNITS_PER_WORD; if (bytes == -1) return 0; if (bytes_left == 0) return 0; if (bytes > bytes_left) return bytes_left; return 0;}/* Variable sized types are passed by reference. */static boolbfin_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED, enum machine_mode mode ATTRIBUTE_UNUSED, tree type, bool named ATTRIBUTE_UNUSED){ return type && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST;}/* Decide whether a type should be returned in memory (true) or in a register (false). This is called by the macro RETURN_IN_MEMORY. */intbfin_return_in_memory (tree type){ int size = int_size_in_bytes (type); return size > 2 * UNITS_PER_WORD || size == -1;}/* Register in which address to store a structure value is passed to a function. */static rtxbfin_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED, int incoming ATTRIBUTE_UNUSED){ return gen_rtx_REG (Pmode, REG_P0);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -