📄 rs6000.c
字号:
low = operand_subword (op, 1, 0, mode); if (high == 0 || ! input_operand (high, word_mode)) return 0; return (mode == SFmode || (low != 0 && input_operand (low, word_mode)));}/* Return 1 if the operand is an offsettable memory address. */intoffsettable_addr_operand (op, mode) register rtx op; enum machine_mode mode;{ return offsettable_address_p (reload_completed | reload_in_progress, mode, op);}/* Return 1 if the operand is either a floating-point register, a pseudo register, or memory. */intfp_reg_or_mem_operand (op, mode) register rtx op; enum machine_mode mode;{ return (memory_operand (op, mode) || (register_operand (op, mode) && (GET_CODE (op) != REG || REGNO (op) >= FIRST_PSEUDO_REGISTER || FP_REGNO_P (REGNO (op)))));}/* Return 1 if the operand is either an easy FP constant (see above) or memory. */intmem_or_easy_const_operand (op, mode) register rtx op; enum machine_mode mode;{ return memory_operand (op, mode) || easy_fp_constant (op, mode);}/* Return 1 if the operand is either a non-special register or an item that can be used as the operand of an SI add insn. */intadd_operand (op, mode) register rtx op; enum machine_mode mode;{ return (reg_or_short_operand (op, mode) || (GET_CODE (op) == CONST_INT && (INTVAL (op) & 0xffff) == 0));}/* Return 1 if OP is a constant but not a valid add_operand. */intnon_add_cint_operand (op, mode) register rtx op; enum machine_mode mode;{ return (GET_CODE (op) == CONST_INT && (unsigned) (INTVAL (op) + 0x8000) >= 0x10000 && (INTVAL (op) & 0xffff) != 0);}/* Return 1 if the operand is a non-special register or a constant that can be used as the operand of an OR or XOR insn on the RS/6000. */intlogical_operand (op, mode) register rtx op; enum machine_mode mode;{ return (gpc_reg_operand (op, mode) || (GET_CODE (op) == CONST_INT && ((INTVAL (op) & 0xffff0000) == 0 || (INTVAL (op) & 0xffff) == 0)));}/* Return 1 if C is a constant that is not a logical operand (as above). */intnon_logical_cint_operand (op, mode) register rtx op; enum machine_mode mode;{ return (GET_CODE (op) == CONST_INT && (INTVAL (op) & 0xffff0000) != 0 && (INTVAL (op) & 0xffff) != 0);}/* Return 1 if C is a constant that can be encoded in a mask on the RS/6000. It is if there are no more than two 1->0 or 0->1 transitions. Reject all ones and all zeros, since these should have been optimized away and confuse the making of MB and ME. */intmask_constant (c) register int c;{ int i; int last_bit_value; int transitions = 0; if (c == 0 || c == ~0) return 0; last_bit_value = c & 1; for (i = 1; i < 32; i++) if (((c >>= 1) & 1) != last_bit_value) last_bit_value ^= 1, transitions++; return transitions <= 2;}/* Return 1 if the operand is a constant that is a mask on the RS/6000. */intmask_operand (op, mode) register rtx op; enum machine_mode mode;{ return GET_CODE (op) == CONST_INT && mask_constant (INTVAL (op));}/* Return 1 if the operand is either a non-special register or a constant that can be used as the operand of an RS/6000 logical AND insn. */intand_operand (op, mode) register rtx op; enum machine_mode mode;{ return (reg_or_short_operand (op, mode) || logical_operand (op, mode) || mask_operand (op, mode));}/* Return 1 if the operand is a constant but not a valid operand for an AND insn. */intnon_and_cint_operand (op, mode) register rtx op; enum machine_mode mode;{ return GET_CODE (op) == CONST_INT && ! and_operand (op, mode);}/* Return 1 if the operand is a general register or memory operand. */intreg_or_mem_operand (op, mode) register rtx op; register enum machine_mode mode;{ return gpc_reg_operand (op, mode) || memory_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; /* 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; /* For HImode and QImode, any constant is valid. */ if ((mode == HImode || mode == QImode) && GET_CODE (op) == CONST_INT) return 1; /* A SYMBOL_REF referring to the TOC is valid. */ if (LEGITIMATE_CONSTANT_POOL_ADDRESS_P (op)) return 1; /* Otherwise, we will be doing this SET with an add, so anything valid for an add will be valid. */ return add_operand (op, mode);}/* 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 an EXPR_LIST. */voidinit_cumulative_args (cum, fntype, libname, incoming) CUMULATIVE_ARGS *cum; tree fntype; rtx libname; int incoming;{ static CUMULATIVE_ARGS zero_cumulative; *cum = zero_cumulative; cum->words = 0; cum->fregno = FP_ARG_MIN_REG; cum->prototype = (fntype && TYPE_ARG_TYPES (fntype)); if (incoming) { cum->nargs_prototype = 1000; /* don't return an EXPR_LIST */#ifdef TARGET_V4_CALLS if (TARGET_V4_CALLS) cum->varargs_offset = RS6000_VARARGS_OFFSET;#endif } 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; 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) ]); }#ifdef TARGET_V4_CALLS if (TARGET_V4_CALLS && incoming) fprintf (stderr, " varargs = %d, ", cum->varargs_offset);#endif fprintf (stderr, " proto = %d, nargs = %d\n", cum->prototype, cum->nargs_prototype); }}/* 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--;#ifdef TARGET_V4_CALLS if (TARGET_V4_CALLS) { /* 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#endif 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\n", cum->words, cum->fregno, cum->nargs_prototype, cum->prototype, GET_MODE_NAME (mode), named);}/* 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 EXPR_LIST anyway. */struct rtx_def *function_arg (cum, mode, type, named) CUMULATIVE_ARGS *cum; enum machine_mode mode; tree type; int named;{ if (TARGET_DEBUG_ARG) fprintf (stderr, "function_arg: words = %2d, fregno = %2d, nargs = %4d, proto = %d, mode = %4s, named = %d\n", cum->words, cum->fregno, cum->nargs_prototype, cum->prototype, GET_MODE_NAME (mode), named); /* 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) {#ifdef TARGET_V4_CALLS if (TARGET_V4_CALLS && TARGET_HARD_FLOAT && cum->nargs_prototype < 0 && type && (cum->prototype || TARGET_NO_PROTOTYPE)) return GEN_INT ((cum->fregno == FP_ARG_MIN_REG) ? -1 : 1);#endif return GEN_INT (0); } if (!named) {#ifdef TARGET_V4_CALLS if (!TARGET_V4_CALLS)#endif 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 ((cum->nargs_prototype > 0)#ifdef TARGET_V4_CALLS || TARGET_V4_CALLS /* V.4 never passes FP values in GP registers */#endif || !type) return gen_rtx (REG, mode, cum->fregno); return gen_rtx (EXPR_LIST, VOIDmode, ((cum->words < GP_ARG_NUM_REG) ? gen_rtx (REG, mode, GP_ARG_MIN_REG + cum->words) : NULL_RTX), gen_rtx (REG, mode, cum->fregno)); }#ifdef TARGET_V4_CALLS /* Long longs won't be split between register and stack */ else if (TARGET_V4_CALLS && cum->words + RS6000_ARG_SIZE (mode, type, named) > GP_ARG_NUM_REG) { return NULL_RTX; }#endif else if (cum->words < GP_ARG_NUM_REG) return gen_rtx (REG, mode, GP_ARG_MIN_REG + cum->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;#ifdef TARGET_V4_CALLS
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -