📄 rs6000.c
字号:
register enum machine_mode mode;{ return (gpc_reg_operand (op, mode) || memory_operand (op, mode) || volatile_mem_operand (op, mode));}/* Return 1 if the operand is a general register or memory operand without pre-inc or pre_dec which produces invalid form of PowerPC lwa instruction. */intlwa_operand (op, mode) register rtx op; register enum machine_mode mode;{ rtx inner = op; if (reload_completed && GET_CODE (inner) == SUBREG) inner = SUBREG_REG (inner); return gpc_reg_operand (inner, mode) || (memory_operand (inner, mode) && GET_CODE (XEXP (inner, 0)) != PRE_INC && GET_CODE (XEXP (inner, 0)) != PRE_DEC);}/* Return 1 if the operand, used inside a MEM, is a valid first argument to CALL. This is a SYMBOL_REF or a pseudo-register, which will be forced to lr. */intcall_operand (op, mode) register rtx op; enum machine_mode mode;{ if (mode != VOIDmode && GET_MODE (op) != mode) return 0; return (GET_CODE (op) == SYMBOL_REF || (GET_CODE (op) == REG && REGNO (op) >= FIRST_PSEUDO_REGISTER));}/* Return 1 if the operand is a SYMBOL_REF for a function known to be in this file. */intcurrent_file_function_operand (op, mode) register rtx op; enum machine_mode mode;{ return (GET_CODE (op) == SYMBOL_REF && (SYMBOL_REF_FLAG (op) || op == XEXP (DECL_RTL (current_function_decl), 0)));}/* Return 1 if this operand is a valid input for a move insn. */intinput_operand (op, mode) register rtx op; enum machine_mode mode;{ /* Memory is always valid. */ if (memory_operand (op, mode)) return 1; /* For floating-point, easy constants are valid. */ if (GET_MODE_CLASS (mode) == MODE_FLOAT && CONSTANT_P (op) && easy_fp_constant (op, mode)) return 1; /* Allow any integer constant. */ if (GET_MODE_CLASS (mode) == MODE_INT && (GET_CODE (op) == CONST_INT || GET_CODE (op) == CONST_DOUBLE)) return 1; /* For floating-point or multi-word mode, the only remaining valid type is a register. */ if (GET_MODE_CLASS (mode) == MODE_FLOAT || GET_MODE_SIZE (mode) > UNITS_PER_WORD) return register_operand (op, mode); /* The only cases left are integral modes one word or smaller (we do not get called for MODE_CC values). These can be in any register. */ if (register_operand (op, mode)) return 1; /* A SYMBOL_REF referring to the TOC is valid. */ if (LEGITIMATE_CONSTANT_POOL_ADDRESS_P (op)) return 1; /* Windows NT allows SYMBOL_REFs and LABEL_REFs against the TOC directly in the instruction stream */ if (DEFAULT_ABI == ABI_NT && (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF)) return 1; /* V.4 allows SYMBOL_REFs and CONSTs that are in the small data region to be valid. */ if ((DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS) && (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == CONST) && small_data_operand (op, Pmode)) return 1; return 0;}/* Return 1 for an operand in small memory on V.4/eabi */intsmall_data_operand (op, mode) rtx op; enum machine_mode mode;{#if TARGET_ELF rtx sym_ref, const_part; if (rs6000_sdata == SDATA_NONE || rs6000_sdata == SDATA_DATA) return 0; if (DEFAULT_ABI != ABI_V4 && DEFAULT_ABI != ABI_SOLARIS) return 0; if (GET_CODE (op) == SYMBOL_REF) sym_ref = op; else if (GET_CODE (op) != CONST || GET_CODE (XEXP (op, 0)) != PLUS || GET_CODE (XEXP (XEXP (op, 0), 0)) != SYMBOL_REF || GET_CODE (XEXP (XEXP (op, 0), 1)) != CONST_INT) return 0; else sym_ref = XEXP (XEXP (op, 0), 0); if (*XSTR (sym_ref, 0) != '@') return 0; return 1;#else return 0;#endif}/* 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. For incoming args we set the number of arguments in the prototype large so we never return a PARALLEL. */voidinit_cumulative_args (cum, fntype, libname, incoming) CUMULATIVE_ARGS *cum; tree fntype; rtx libname; int incoming;{ static CUMULATIVE_ARGS zero_cumulative; enum rs6000_abi abi = DEFAULT_ABI; *cum = zero_cumulative; cum->words = 0; cum->fregno = FP_ARG_MIN_REG; cum->prototype = (fntype && TYPE_ARG_TYPES (fntype)); cum->call_cookie = CALL_NORMAL; if (incoming) { cum->nargs_prototype = 1000; /* don't return a PARALLEL */ if (abi == ABI_V4 || abi == ABI_SOLARIS) cum->varargs_offset = RS6000_VARARGS_OFFSET; } else if (cum->prototype) cum->nargs_prototype = (list_length (TYPE_ARG_TYPES (fntype)) - 1 + (TYPE_MODE (TREE_TYPE (fntype)) == BLKmode || RETURN_IN_MEMORY (TREE_TYPE (fntype)))); else cum->nargs_prototype = 0; cum->orig_nargs = cum->nargs_prototype; /* Check for DLL import functions */ if (abi == ABI_NT && fntype && lookup_attribute ("dllimport", TYPE_ATTRIBUTES (fntype))) cum->call_cookie = CALL_NT_DLLIMPORT; /* Also check for longcall's */ else if (fntype && lookup_attribute ("longcall", TYPE_ATTRIBUTES (fntype))) cum->call_cookie = CALL_LONG; if (TARGET_DEBUG_ARG) { fprintf (stderr, "\ninit_cumulative_args:"); if (fntype) { tree ret_type = TREE_TYPE (fntype); fprintf (stderr, " ret code = %s,", tree_code_name[ (int)TREE_CODE (ret_type) ]); } if ((abi == ABI_V4 || abi == ABI_SOLARIS) && incoming) fprintf (stderr, " varargs = %d, ", cum->varargs_offset); if (cum->call_cookie & CALL_NT_DLLIMPORT) fprintf (stderr, " dllimport,"); if (cum->call_cookie & CALL_LONG) fprintf (stderr, " longcall,"); fprintf (stderr, " proto = %d, nargs = %d\n", cum->prototype, cum->nargs_prototype); }}/* If defined, a C expression which determines whether, and in which direction, to pad out an argument with extra space. The value should be of type `enum direction': either `upward' to pad above the argument, `downward' to pad below, or `none' to inhibit padding. For the AIX ABI structs are always stored left shifted in their argument slot. */enum directionfunction_arg_padding (mode, type) enum machine_mode mode; tree type;{ if (type != 0 && AGGREGATE_TYPE_P (type)) return upward; /* This is the default definition. */ return (! BYTES_BIG_ENDIAN ? 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) ? downward : 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) 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;{ int align = ((cum->words & 1) != 0 && function_arg_boundary (mode, type) == 64) ? 1 : 0; cum->words += align; cum->nargs_prototype--; if (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS) { /* Long longs must not be split between registers and stack */ if ((GET_MODE_CLASS (mode) != MODE_FLOAT || TARGET_SOFT_FLOAT) && type && !AGGREGATE_TYPE_P (type) && cum->words < GP_ARG_NUM_REG && cum->words + RS6000_ARG_SIZE (mode, type, named) > GP_ARG_NUM_REG) { cum->words = GP_ARG_NUM_REG; } /* Aggregates get passed as pointers */ if (type && AGGREGATE_TYPE_P (type)) cum->words++; /* Floats go in registers, & don't occupy space in the GP registers like they do for AIX unless software floating point. */ else if (GET_MODE_CLASS (mode) == MODE_FLOAT && TARGET_HARD_FLOAT && cum->fregno <= FP_ARG_V4_MAX_REG) cum->fregno++; else cum->words += RS6000_ARG_SIZE (mode, type, 1); } else 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, nargs = %4d, proto = %d, mode = %4s, named = %d, align = %d\n", cum->words, cum->fregno, cum->nargs_prototype, cum->prototype, GET_MODE_NAME (mode), 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;{ int align = ((cum->words & 1) != 0 && function_arg_boundary (mode, type) == 64) ? 1 : 0; int align_words = cum->words + align; if (TARGET_DEBUG_ARG) fprintf (stderr, "function_arg: words = %2d, fregno = %2d, nargs = %4d, proto = %d, mode = %4s, named = %d, align = %d\n", cum->words, cum->fregno, cum->nargs_prototype, cum->prototype, GET_MODE_NAME (mode), named, align); /* 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) { enum rs6000_abi abi = DEFAULT_ABI; 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 (!named) { if (DEFAULT_ABI != ABI_V4 && DEFAULT_ABI != ABI_SOLARIS) 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 (DEFAULT_ABI == ABI_V4 /* V.4 never passes FP values in GP registers */ || DEFAULT_ABI == ABI_SOLARIS || ! 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))); } /* Long longs won't be split between register and stack; FP arguments get passed on the stack if they didn't get a register. */ else if ((DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS) && (align_words + RS6000_ARG_SIZE (mode, type, named) > GP_ARG_NUM_REG || (GET_MODE_CLASS (mode) == MODE_FLOAT && TARGET_HARD_FLOAT))) { return NULL_RTX; } else if (align_words < GP_ARG_NUM_REG) return gen_rtx (REG, mode, GP_ARG_MIN_REG + align_words); 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; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -