📄 d30v.c
字号:
break; } x0 = XEXP (op, 0); if (GET_CODE (x0) != REG && GET_CODE (x0) != SUBREG) return FALSE; if (GET_MODE (x0) != SImode) return FALSE; x1 = XEXP (op, 1); switch (GET_CODE (x1)) { default: return FALSE; case REG: case SUBREG: case CONST_INT: case LABEL_REF: case SYMBOL_REF: case CONST: break; } return TRUE;}/* Return true if operand is a SI mode unsigned relational test. */inturelational_si_operator (op, mode) register rtx op; enum machine_mode mode;{ rtx x0, x1; if (GET_MODE (op) != mode && mode != VOIDmode) return FALSE; switch (GET_CODE (op)) { default: return FALSE; case LTU: case LEU: case GTU: case GEU: break; } x0 = XEXP (op, 0); if (GET_CODE (x0) != REG && GET_CODE (x0) != SUBREG) return FALSE; if (GET_MODE (x0) != SImode) return FALSE; x1 = XEXP (op, 1); switch (GET_CODE (x1)) { default: return FALSE; case REG: case SUBREG: case CONST_INT: case LABEL_REF: case SYMBOL_REF: case CONST: break; } return TRUE;}/* Return true if operand is a DI mode relational test. */intrelational_di_operator (op, mode) register rtx op; enum machine_mode mode;{ rtx x0, x1; if (GET_MODE (op) != mode && mode != VOIDmode) return FALSE; if (GET_RTX_CLASS (GET_CODE (op)) != '<') return FALSE; x0 = XEXP (op, 0); if (GET_CODE (x0) != REG && GET_CODE (x0) != SUBREG) return FALSE; if (GET_MODE (x0) != DImode) return FALSE; x1 = XEXP (op, 1); if (GET_CODE (x1) != REG && GET_CODE (x1) != SUBREG && GET_CODE (x1) != CONST_INT && GET_CODE (x1) != CONST_DOUBLE) return FALSE; return TRUE;}/* Calculate the stack information for the current function. D30V stack frames look like: high | .... | +-------------------------------+ | Argument word #19 | +-------------------------------+ | Argument word #18 | +-------------------------------+ | Argument word #17 | +-------------------------------+ | Argument word #16 | Prev sp +-------------------------------+ | | | Save for arguments 1..16 if | | the func. uses stdarg/varargs | | | +-------------------------------+ | | | Save area for GPR registers | | | +-------------------------------+ | | | Save area for accumulators | | | +-------------------------------+ | | | Local variables | | | +-------------------------------+ | | | alloca space if used | | | +-------------------------------+ | | | Space for outgoing arguments | | | low SP----> +-------------------------------+*/d30v_stack_t *d30v_stack_info (){ static d30v_stack_t info, zero_info; d30v_stack_t *info_ptr = &info; tree fndecl = current_function_decl; tree fntype = TREE_TYPE (fndecl); int varargs_p = 0; tree cur_arg; tree next_arg; int saved_gprs; int saved_accs; int memrefs_2words; int memrefs_1word; unsigned char save_gpr_p[GPR_LAST]; int i; /* If we've already calculated the values and reload is complete, just return now */ if (d30v_stack_cache) return d30v_stack_cache; /* Zero all fields */ info = zero_info; if (current_function_profile) regs_ever_live[GPR_LINK] = 1; /* Determine if this is a stdarg function */ if (TYPE_ARG_TYPES (fntype) != 0 && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype))) != void_type_node)) varargs_p = 1; else { /* Find the last argument, and see if it is __builtin_va_alist. */ for (cur_arg = DECL_ARGUMENTS (fndecl); cur_arg != (tree)0; cur_arg = next_arg) { next_arg = TREE_CHAIN (cur_arg); if (next_arg == (tree)0) { if (DECL_NAME (cur_arg) && !strcmp (IDENTIFIER_POINTER (DECL_NAME (cur_arg)), "__builtin_va_alist")) varargs_p = 1; break; } } } /* Calculate which registers need to be saved & save area size */ saved_accs = 0; memrefs_2words = 0; memrefs_1word = 0; for (i = ACCUM_FIRST; i <= ACCUM_LAST; i++) { if (regs_ever_live[i] && !call_used_regs[i]) { info_ptr->save_p[i] = 2; saved_accs++; memrefs_2words++; } } saved_gprs = 0; for (i = GPR_FIRST; i <= GPR_LAST; i++) { if (regs_ever_live[i] && (!call_used_regs[i] || i == GPR_LINK)) { save_gpr_p[i] = 1; saved_gprs++; } else save_gpr_p[i] = 0; } /* Determine which register pairs can be saved together with ld2w/st2w */ for (i = GPR_FIRST; i <= GPR_LAST; i++) { if (((i - GPR_FIRST) & 1) == 0 && save_gpr_p[i] && save_gpr_p[i+1]) { memrefs_2words++; info_ptr->save_p[i++] = 2; } else if (save_gpr_p[i]) { memrefs_1word++; info_ptr->save_p[i] = 1; } } /* Determine various sizes */ info_ptr->varargs_p = varargs_p; info_ptr->varargs_size = ((varargs_p) ? (GPR_ARG_LAST + 1 - GPR_ARG_FIRST) * UNITS_PER_WORD : 0); info_ptr->accum_size = 2 * UNITS_PER_WORD * saved_accs; info_ptr->gpr_size = D30V_ALIGN (UNITS_PER_WORD * saved_gprs, 2 * UNITS_PER_WORD); info_ptr->vars_size = D30V_ALIGN (get_frame_size (), 2 * UNITS_PER_WORD); info_ptr->parm_size = D30V_ALIGN (current_function_outgoing_args_size, 2 * UNITS_PER_WORD); info_ptr->total_size = D30V_ALIGN ((info_ptr->gpr_size + info_ptr->accum_size + info_ptr->vars_size + info_ptr->parm_size + info_ptr->varargs_size + current_function_pretend_args_size), (STACK_BOUNDARY / BITS_PER_UNIT)); info_ptr->save_offset = (info_ptr->total_size - (current_function_pretend_args_size + info_ptr->varargs_size + info_ptr->gpr_size + info_ptr->accum_size)); /* The link register is the last GPR saved, but there might be some padding bytes after it, so account for that. */ info_ptr->link_offset = (info_ptr->total_size - (current_function_pretend_args_size + info_ptr->varargs_size + (info_ptr->gpr_size - UNITS_PER_WORD * saved_gprs) + UNITS_PER_WORD)); info_ptr->memrefs_varargs = info_ptr->varargs_size / (2 * UNITS_PER_WORD); info_ptr->memrefs_2words = memrefs_2words; info_ptr->memrefs_1word = memrefs_1word; if (reload_completed) d30v_stack_cache = info_ptr; return info_ptr;}/* Internal function to print all of the information about the stack */voiddebug_stack_info (info) d30v_stack_t *info;{ int i; if (!info) info = d30v_stack_info (); fprintf (stderr, "\nStack information for function %s:\n", ((current_function_decl && DECL_NAME (current_function_decl)) ? IDENTIFIER_POINTER (DECL_NAME (current_function_decl)) : "<unknown>")); fprintf (stderr, "\tsave_offset = %d\n", info->save_offset); fprintf (stderr, "\tmemrefs_varargs = %d\n", info->memrefs_varargs); fprintf (stderr, "\tmemrefs_2words = %d\n", info->memrefs_2words); fprintf (stderr, "\tmemrefs_1word = %d\n", info->memrefs_1word); fprintf (stderr, "\tvarargs_p = %d\n", info->varargs_p); fprintf (stderr, "\tvarargs_size = %d\n", info->varargs_size); fprintf (stderr, "\tvars_size = %d\n", info->vars_size); fprintf (stderr, "\tparm_size = %d\n", info->parm_size); fprintf (stderr, "\tgpr_size = %d\n", info->gpr_size); fprintf (stderr, "\taccum_size = %d\n", info->accum_size); fprintf (stderr, "\ttotal_size = %d\n", info->total_size); fprintf (stderr, "\tsaved registers ="); for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) { if (info->save_p[i] == 2) { fprintf (stderr, " %s-%s", reg_names[i], reg_names[i+1]); i++; } else if (info->save_p[i]) fprintf (stderr, " %s", reg_names[i]); } putc ('\n', stderr); fflush (stderr);}/* Return nonzero if this function is known to have a null or 1 instruction epilogue. */intdirect_return (){ if (reload_completed) { d30v_stack_t *info = d30v_stack_info (); /* If no epilogue code is needed, can use just a simple jump */ if (info->total_size == 0) return 1;#if 0 /* If just a small amount of local stack was allocated and no registers saved, skip forward branch */ if (info->total_size == info->vars_size && IN_RANGE_P (info->total_size, 1, 31)) return 1;#endif } return 0;}/* A C statement (sans semicolon) for initializing the variable CUM for the state at the beginning of the argument list. The variable has type `CUMULATIVE_ARGS'. The value of FNTYPE is the tree node for the data type of the function which will receive the args, or 0 if the args are to a compiler support library function. The value of INDIRECT is nonzero when processing an indirect call, for example a call through a function pointer. The value of INDIRECT is zero for a call to an explicitly named function, a library function call, or when `INIT_CUMULATIVE_ARGS' is used to find arguments for the function being compiled. When processing a call to a compiler support library function, LIBNAME identifies which one. It is a `symbol_ref' rtx which contains the name of the function, as a string. LIBNAME is 0 when an ordinary C function call is being processed. Thus, each time this macro is called, either LIBNAME or FNTYPE is nonzero, but never both of them at once. */voidd30v_init_cumulative_args (cum, fntype, libname, indirect, incoming) CUMULATIVE_ARGS *cum; tree fntype; rtx libname; int indirect; int incoming;{ *cum = GPR_ARG_FIRST; if (TARGET_DEBUG_ARG) { fprintf (stderr, "\ninit_cumulative_args:"); if (indirect) fputs (" indirect", stderr); if (incoming) fputs (" incoming", stderr); if (fntype) { tree ret_type = TREE_TYPE (fntype); fprintf (stderr, " return=%s,", tree_code_name[ (int)TREE_CODE (ret_type) ]); } if (libname && GET_CODE (libname) == SYMBOL_REF) fprintf (stderr, " libname=%s", XSTR (libname, 0)); putc ('\n', stderr); }}/* If defined, a C expression that gives the alignment boundary, in bits, of an argument with the specified mode and type. If it is not defined, `PARM_BOUNDARY' is used for all arguments. */intd30v_function_arg_boundary (mode, type) enum machine_mode mode; tree type;{ int size = ((mode == BLKmode && type) ? int_size_in_bytes (type) : (int) GET_MODE_SIZE (mode)); return (size > UNITS_PER_WORD) ? 2*UNITS_PER_WORD : UNITS_PER_WORD;}/* A C expression that controls whether a function argument is passed in a register, and which register. The arguments are CUM, which summarizes all the previous arguments; MODE, the machine mode of the argument; TYPE, the data type of the argument as a tree node or 0 if that is not known (which happens for C support library functions); and NAMED, which is 1 for an ordinary argument and 0 for nameless arguments that correspond to `...' in the called function's prototype. The value of the expression should either be a `reg' RTX for the hard register in which to pass the argument, or zero to pass the argument on the stack. For machines like the VAX and 68000, where normally all arguments are pushed, zero suffices as a definition. The usual way to make the ANSI library `stdarg.h' work on a machine where some arguments are usually passed in registers, is to cause nameless arguments to be passed on the stack instead. This is done by making `FUNCTION_ARG' return 0 whenever NAMED is 0. You may use the macro `MUST_PASS_IN_STACK (MODE, TYPE)' in the definition of this macro to determine if this argument is of a type that must be passed in the stack. If `REG_PARM_STACK_SPACE' is not defined and `FUNCTION_ARG' returns nonzero for such an argument, the compiler will abort. If `REG_PARM_STACK_SPACE' is defined, the argument will be computed in the stack and then loaded into a register. */rtxd30v_function_arg (cum, mode, type, named, incoming) CUMULATIVE_ARGS *cum; enum machine_mode mode; tree type; int named; int incoming ATTRIBUTE_UNUSED;{ int size = ((mode == BLKmode && type) ? int_size_in_bytes (type) : (int) GET_MODE_SIZE (mode)); int adjust = (size > UNITS_PER_WORD && (*cum & 1) != 0); rtx ret; /* Return a marker for use in the call instruction. */ if (mode == VOIDmode) ret = const0_rtx; else if (*cum + adjust <= GPR_ARG_LAST) ret = gen_rtx (REG, mode, *cum + adjust); else ret = NULL_RTX; if (TARGET_DEBUG_ARG) fprintf (stderr, "function_arg: words = %2d, mode = %4s, named = %d, size = %3d, adjust = %1d, arg = %s\n", *cum, GET_MODE_NAME (mode), named, size, adjust, (ret) ? ((ret == const0_rtx) ? "<0>" : reg_names[ REGNO (ret) ]) : "memory"); return ret;}/* A C expression for the number of words, at the beginning of an argument, must be put in registers. The value must be zero for arguments that are passed entirely in registers or that are entirely pushed on the stack. On some machines, certain arguments must be passed partially in registers and partially in memory. On these machines, typically the first N words of arguments are passed in registers, and the rest on the stack. If a multi-word argument (a `double' or a structure) crosses that boundary, its first few words must be passed in registers and the rest must be pushed. This macro tells the compiler when this occurs, and how many of the words should go in registers. `FUNCTION_ARG' for these arguments should return the first register to be used by the caller for this argument; likewise `FUNCTION_INCOMING_ARG', for the called function. */intd30v_function_arg_partial_nregs (cum, mode, type, named) CUMULATIVE_ARGS *cum; enum machine_mode mode; tree type; int named ATTRIBUTE_UNUSED;{ int bytes = ((mode == BLKmode) ? int_size_in_bytes (type) : (int) GET_MODE_SIZE (mode)); int words = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -