📄 rs6000.c
字号:
? (int)upward : ((mode == BLKmode ? (type && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST && int_size_in_bytes (type) < (PARM_BOUNDARY / BITS_PER_UNIT)) : GET_MODE_BITSIZE (mode) < PARM_BOUNDARY) ? (int)downward : (int)upward));}/* 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. Windows NT wants anything >= 8 bytes to be double word aligned. V.4 wants long longs to be double word aligned. */intfunction_arg_boundary (mode, type) enum machine_mode mode; tree type;{ if ((DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS) && (mode == DImode || mode == DFmode)) return 64; if (DEFAULT_ABI != ABI_NT || TARGET_64BIT) return PARM_BOUNDARY; if (mode != BLKmode) return (GET_MODE_SIZE (mode)) >= 8 ? 64 : 32; return (int_size_in_bytes (type) >= 8) ? 64 : 32;}/* 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 (cum, mode, type, named) CUMULATIVE_ARGS *cum; enum machine_mode mode; tree type; int named;{ cum->nargs_prototype--; if (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS) { if (TARGET_HARD_FLOAT && (mode == SFmode || mode == DFmode)) { if (cum->fregno <= FP_ARG_V4_MAX_REG) cum->fregno++; else { if (mode == DFmode) cum->words += cum->words & 1; cum->words += RS6000_ARG_SIZE (mode, type, 1); } } else { int n_words; int gregno = cum->sysv_gregno; /* Aggregates and IEEE quad get passed by reference. */ if ((type && AGGREGATE_TYPE_P (type)) || mode == TFmode) n_words = 1; else n_words = RS6000_ARG_SIZE (mode, type, 1); /* Long long is put in odd registers. */ if (n_words == 2 && (gregno & 1) == 0) gregno += 1; /* Long long is not split between registers and stack. */ if (gregno + n_words - 1 > GP_ARG_MAX_REG) { /* Long long is aligned on the stack. */ if (n_words == 2) cum->words += cum->words & 1; cum->words += n_words; } /* Note: continuing to accumulate gregno past when we've started spilling to the stack indicates the fact that we've started spilling to the stack to expand_builtin_saveregs. */ cum->sysv_gregno = gregno + n_words; } if (TARGET_DEBUG_ARG) { fprintf (stderr, "function_adv: words = %2d, fregno = %2d, ", cum->words, cum->fregno); fprintf (stderr, "gregno = %2d, nargs = %4d, proto = %d, ", cum->sysv_gregno, cum->nargs_prototype, cum->prototype); fprintf (stderr, "mode = %4s, named = %d\n", GET_MODE_NAME (mode), named); } } else { int align = (TARGET_32BIT && (cum->words & 1) != 0 && function_arg_boundary (mode, type) == 64) ? 1 : 0; cum->words += align; if (named) { cum->words += RS6000_ARG_SIZE (mode, type, named); if (GET_MODE_CLASS (mode) == MODE_FLOAT && TARGET_HARD_FLOAT) cum->fregno++; } if (TARGET_DEBUG_ARG) { fprintf (stderr, "function_adv: words = %2d, fregno = %2d, ", cum->words, cum->fregno); fprintf (stderr, "nargs = %4d, proto = %d, mode = %4s, ", cum->nargs_prototype, cum->prototype, GET_MODE_NAME (mode)); fprintf (stderr, "named = %d, align = %d\n", named, align); } }}/* Determine where to put an argument 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). On RS/6000 the first eight words of non-FP are normally in registers and the rest are pushed. Under AIX, the first 13 FP args are in registers. Under V.4, the first 8 FP args are in registers. If this is floating-point and no prototype is specified, we use both an FP and integer register (or possibly FP reg and stack). Library functions (when TYPE is zero) always have the proper types for args, so we can pass the FP value just in one register. emit_library_function doesn't support PARALLEL anyway. */struct rtx_def *function_arg (cum, mode, type, named) CUMULATIVE_ARGS *cum; enum machine_mode mode; tree type; int named;{ enum rs6000_abi abi = DEFAULT_ABI; /* Return a marker to indicate whether CR1 needs to set or clear the bit that V.4 uses to say fp args were passed in registers. Assume that we don't need the marker for software floating point, or compiler generated library calls. */ if (mode == VOIDmode) { if ((abi == ABI_V4 || abi == ABI_SOLARIS) && TARGET_HARD_FLOAT && cum->nargs_prototype < 0 && type && (cum->prototype || TARGET_NO_PROTOTYPE)) { return GEN_INT (cum->call_cookie | ((cum->fregno == FP_ARG_MIN_REG) ? CALL_V4_SET_FP_ARGS : CALL_V4_CLEAR_FP_ARGS)); } return GEN_INT (cum->call_cookie); } if (abi == ABI_V4 || abi == ABI_SOLARIS) { if (TARGET_HARD_FLOAT && (mode == SFmode || mode == DFmode)) { if (cum->fregno <= FP_ARG_V4_MAX_REG) return gen_rtx_REG (mode, cum->fregno); else return NULL; } else { int n_words; int gregno = cum->sysv_gregno; /* Aggregates and IEEE quad get passed by reference. */ if ((type && AGGREGATE_TYPE_P (type)) || mode == TFmode) n_words = 1; else n_words = RS6000_ARG_SIZE (mode, type, 1); /* Long long is put in odd registers. */ if (n_words == 2 && (gregno & 1) == 0) gregno += 1; /* Long long is not split between registers and stack. */ if (gregno + n_words - 1 <= GP_ARG_MAX_REG) return gen_rtx_REG (mode, gregno); else return NULL; } } else { int align = (TARGET_32BIT && (cum->words & 1) != 0 && function_arg_boundary (mode, type) == 64) ? 1 : 0; int align_words = cum->words + align; if (!named) return NULL_RTX; if (type && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST) return NULL_RTX; if (USE_FP_FOR_ARG_P (*cum, mode, type)) { if (! type || ((cum->nargs_prototype > 0) /* IBM AIX extended its linkage convention definition always to require FP args after register save area hole on the stack. */ && (DEFAULT_ABI != ABI_AIX || ! TARGET_XL_CALL || (align_words < GP_ARG_NUM_REG)))) return gen_rtx_REG (mode, cum->fregno); return gen_rtx_PARALLEL (mode, gen_rtvec (2, gen_rtx_EXPR_LIST (VOIDmode, ((align_words >= GP_ARG_NUM_REG) ? NULL_RTX : (align_words + RS6000_ARG_SIZE (mode, type, named) > GP_ARG_NUM_REG /* If this is partially on the stack, then we only include the portion actually in registers here. */ ? gen_rtx_REG (SImode, GP_ARG_MIN_REG + align_words) : gen_rtx_REG (mode, GP_ARG_MIN_REG + align_words))), const0_rtx), gen_rtx_EXPR_LIST (VOIDmode, gen_rtx_REG (mode, cum->fregno), const0_rtx))); } else if (align_words < GP_ARG_NUM_REG) return gen_rtx_REG (mode, GP_ARG_MIN_REG + align_words); else return NULL_RTX; }}/* For an arg passed partly in registers and partly in memory, this is the number of registers used. For args passed entirely in registers or entirely in memory, zero. */intfunction_arg_partial_nregs (cum, mode, type, named) CUMULATIVE_ARGS *cum; enum machine_mode mode; tree type; int named;{ if (! named) return 0; if (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS) return 0; if (USE_FP_FOR_ARG_P (*cum, mode, type)) { if (cum->nargs_prototype >= 0) return 0; } if (cum->words < GP_ARG_NUM_REG && GP_ARG_NUM_REG < (cum->words + RS6000_ARG_SIZE (mode, type, named))) { int ret = GP_ARG_NUM_REG - cum->words; if (ret && TARGET_DEBUG_ARG) fprintf (stderr, "function_arg_partial_nregs: %d\n", ret); return ret; } return 0;}/* A C expression that indicates when an argument must be passed by reference. If nonzero for an argument, a copy of that argument is made in memory and a pointer to the argument is passed instead of the argument itself. The pointer is passed in whatever way is appropriate for passing a pointer to that type. Under V.4, structures and unions are passed by reference. */intfunction_arg_pass_by_reference (cum, mode, type, named) CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED; enum machine_mode mode ATTRIBUTE_UNUSED; tree type; int named ATTRIBUTE_UNUSED;{ if ((DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS) && ((type && AGGREGATE_TYPE_P (type)) || mode == TFmode)) { if (TARGET_DEBUG_ARG) fprintf (stderr, "function_arg_pass_by_reference: aggregate\n"); return 1; } return 0;}/* Perform any needed actions needed for a function that is receiving a variable number of arguments. CUM is as above. MODE and TYPE are the mode and type of the current parameter. PRETEND_SIZE is a variable that should be set to the amount of stack that must be pushed by the prolog to pretend that our caller pushed it. Normally, this macro will push all remaining incoming registers on the stack and set PRETEND_SIZE to the length of the registers pushed. */voidsetup_incoming_varargs (cum, mode, type, pretend_size, no_rtl) CUMULATIVE_ARGS *cum; enum machine_mode mode; tree type; int *pretend_size; int no_rtl;{ CUMULATIVE_ARGS next_cum; int reg_size = TARGET_32BIT ? 4 : 8; rtx save_area; int first_reg_offset; if (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS) { tree fntype; int stdarg_p; fntype = TREE_TYPE (current_function_decl); stdarg_p = (TYPE_ARG_TYPES (fntype) != 0 && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype))) != void_type_node)); /* For varargs, we do not want to skip the dummy va_dcl argument. For stdargs, we do want to skip the last named argument. */ next_cum = *cum; if (stdarg_p) function_arg_advance (&next_cum, mode, type, 1); /* Indicate to allocate space on the stack for varargs save area. */ /* ??? Does this really have to be located at a magic spot on the stack, or can we allocate this with assign_stack_local instead. */ rs6000_sysv_varargs_p = 1; if (! no_rtl) save_area = plus_constant (virtual_stack_vars_rtx, - RS6000_VARARGS_SIZE); first_reg_offset = next_cum.sysv_gregno - GP_ARG_MIN_REG; } else { save_area = virtual_incoming_args_rtx; rs6000_sysv_varargs_p = 0; first_reg_offset = cum->words; if (MUST_PASS_IN_STACK (mode, type)) first_reg_offset += RS6000_ARG_SIZE (TYPE_MODE (type), type, 1); } if (!no_rtl && first_reg_offset < GP_ARG_NUM_REG) { move_block_from_reg (GP_ARG_MIN_REG + first_reg_offset, gen_rtx_MEM (BLKmode, plus_constant (save_area, first_reg_offset * reg_size)), GP_ARG_NUM_REG - first_reg_offset, (GP_ARG_NUM_REG - first_reg_offset) * UNITS_PER_WORD); /* ??? Does ABI_V4 need this at all? */ *pretend_size = (GP_ARG_NUM_REG - first_reg_offset) * UNITS_PER_WORD; } /* Save FP registers if needed. */ if ((DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS) && TARGET_HARD_FLOAT && !no_rtl && next_cum.fregno <= FP_ARG_V4_MAX_REG) { int fregno = next_cum.fregno; rtx cr1 = gen_rtx_REG (CCmode, 69); rtx lab = gen_label_rtx (); int off = (GP_ARG_NUM_REG * reg_size) + ((fregno - FP_ARG_MIN_REG) * 8); emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, gen_rtx_IF_THEN_ELSE (VOIDmode, gen_rtx_NE (VOIDmode, cr1, const0_rtx), gen_rtx_LABEL_REF (VOIDmode, lab), pc_rtx))); while (fregno <= FP_ARG_V4_MAX_REG) { emit_move_insn (gen_rtx_MEM (DFmode, plus_constant (save_area, off)), gen_rtx_REG (DFmode, fregno)); fregno++; off += 8; } emit_label (lab); }}/* If defined, is a C expression that produces the machine-specific code for a call to `__builtin_saveregs'. This code will be moved to the very beginning of the function, before any parameter access are made. The return value of this function should be an RTX that contains the value to use as the return of `__builtin_saveregs'. The argument ARGS is a `tree_list' containing the arguments that were passed to `__builtin_saveregs'. If this macro is not defined, the compiler will output an ordinary call to the library function `__builtin_saveregs'. On the Power/PowerPC return the address of the area on the stack used to hold arguments. Under AIX, this includes the 8 word register save area. Under V.4, things are more complicated. We do not have access to all of the virtual registers required for va_start to do its job, so we construct the va_list in its entirity here, and reduce va_start to a block copy. This is similar to the way we do things on Alpha. */struct rtx_def *expand_builtin_saveregs (args) tree args ATTRIBUTE_UNUSED;{ rtx block, mem_gpr_fpr, mem_reg_save_area, mem_overflow, tmp; tree fntype; int stdarg_p; HOST_WIDE_INT words, gpr, fpr; if (DEFAULT_ABI != ABI_V4 && DEFAULT_ABI != ABI_SOLARIS) return virtual_incoming_args_rtx; fntype = TREE_TYPE (current_function_decl); stdarg_p = (TYPE_ARG_TYPES (fntype) != 0
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -