📄 rs6000.c
字号:
/* Return 1 if the operand is a non-special register or a 32-bit constant that can be used as the operand of an OR or XOR insn on the RS/6000. */intlogical_u_operand (op, mode) register rtx op; enum machine_mode mode;{ return (gpc_reg_operand (op, mode) || (GET_CODE (op) == CONST_INT && INTVAL (op) > 0#if HOST_BITS_PER_WIDE_INT != 32 && INTVAL (op) < ((HOST_WIDE_INT) 1 << 32)#endif && ((INTVAL (op) & GET_MODE_MASK (mode) & (~ (HOST_WIDE_INT) 0xffff)) == 0 || (INTVAL (op) & GET_MODE_MASK (mode) & (~ (unsigned HOST_WIDE_INT) 0xffff0000u)) == 0))#if HOST_BITS_PER_WIDE_INT == 32 || (GET_CODE (op) == CONST_DOUBLE && CONST_DOUBLE_HIGH (op) == 0 && ((CONST_DOUBLE_LOW (op) & (~ (unsigned HOST_WIDE_INT) 0xffff0000u)) == 0))#endif );}/* 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 ATTRIBUTE_UNUSED;{ return (GET_CODE (op) == CONST_INT#if HOST_BITS_PER_WIDE_INT != 32 && INTVAL (op) < ((HOST_WIDE_INT) 1 << 32)#endif && (INTVAL (op) & GET_MODE_MASK (mode) & (~ (HOST_WIDE_INT) 0xffff)) != 0 && (INTVAL (op) & GET_MODE_MASK (mode) & (~ (unsigned HOST_WIDE_INT) 0xffff0000u)) != 0);}/* Return 1 if C is an unsigned 32-bit constant that is not a logical operand (as above). */intnon_logical_u_cint_operand (op, mode) register rtx op; enum machine_mode mode ATTRIBUTE_UNUSED;{ return ((GET_CODE (op) == CONST_INT && INTVAL (op) > 0#if HOST_BITS_PER_WIDE_INT != 32 && INTVAL (op) < ((HOST_WIDE_INT) 1 << 32)#endif && (INTVAL (op) & GET_MODE_MASK (mode) & (~ (HOST_WIDE_INT) 0xffff)) != 0 && (INTVAL (op) & GET_MODE_MASK (mode) & (~ (unsigned HOST_WIDE_INT) 0xffff0000u)) != 0)#if HOST_BITS_PER_WIDE_INT == 32 || (GET_CODE (op) == CONST_DOUBLE && CONST_DOUBLE_HIGH (op) == 0 && (CONST_DOUBLE_LOW (op) & (~ (HOST_WIDE_INT) 0xffff)) != 0 && (CONST_DOUBLE_LOW (op) & (~ (unsigned HOST_WIDE_INT) 0xffff0000u)) != 0));#endif}/* Return 1 if C is a constant that can be encoded in a 32-bit 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_operand (op, mode) register rtx op; enum machine_mode mode ATTRIBUTE_UNUSED;{ HOST_WIDE_INT c; int i; int last_bit_value; int transitions = 0; if (GET_CODE (op) != CONST_INT) return 0; c = INTVAL (op); 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 PowerPC64 mask. It is if there are no more than one 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. */intmask64_operand (op, mode) register rtx op; enum machine_mode mode;{ if (GET_CODE (op) == CONST_INT) { HOST_WIDE_INT c = INTVAL (op); 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 < HOST_BITS_PER_WIDE_INT; i++) if (((c >>= 1) & 1) != last_bit_value) last_bit_value ^= 1, transitions++;#if HOST_BITS_PER_WIDE_INT == 32 /* Consider CONST_INT sign-extended. */ transitions += (last_bit_value != 1);#endif return transitions <= 1; } else if (GET_CODE (op) == CONST_DOUBLE && (mode == VOIDmode || mode == DImode)) { HOST_WIDE_INT low = CONST_DOUBLE_LOW (op);#if HOST_BITS_PER_WIDE_INT == 32 HOST_WIDE_INT high = CONST_DOUBLE_HIGH (op);#endif int i; int last_bit_value; int transitions = 0; if ((low == 0#if HOST_BITS_PER_WIDE_INT == 32 && high == 0#endif ) || (low == ~0#if HOST_BITS_PER_WIDE_INT == 32 && high == ~0#endif )) return 0; last_bit_value = low & 1; for (i = 1; i < HOST_BITS_PER_WIDE_INT; i++) if (((low >>= 1) & 1) != last_bit_value) last_bit_value ^= 1, transitions++;#if HOST_BITS_PER_WIDE_INT == 32 if ((high & 1) != last_bit_value) last_bit_value ^= 1, transitions++; for (i = 1; i < HOST_BITS_PER_WIDE_INT; i++) if (((high >>= 1) & 1) != last_bit_value) last_bit_value ^= 1, transitions++;#endif return transitions <= 1; } else return 0;}/* Return 1 if the operand is either a non-special register or a constant that can be used as the operand of a PowerPC64 logical AND insn. */intand64_operand (op, mode) register rtx op; enum machine_mode mode;{ if (fixed_regs[68]) /* CR0 not available, don't do andi./andis. */ return (gpc_reg_operand (op, mode) || mask64_operand (op, mode)); return (logical_operand (op, mode) || mask64_operand (op, mode));}/* 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;{ if (fixed_regs[68]) /* CR0 not available, don't do andi./andis. */ return (gpc_reg_operand (op, mode) || mask_operand (op, mode)); return (logical_operand (op, mode) || mask_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) || 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 and the function is not weakly defined. */intcurrent_file_function_operand (op, mode) register rtx op; enum machine_mode mode ATTRIBUTE_UNUSED;{ return (GET_CODE (op) == SYMBOL_REF && (SYMBOL_REF_FLAG (op) || (op == XEXP (DECL_RTL (current_function_decl), 0) && !DECL_WEAK (current_function_decl))));}/* 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; /* Only a tiny bit of handling for CONSTANT_P_RTX is necessary. */ if (GET_CODE (op) == CONSTANT_P_RTX) 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 ATTRIBUTE_UNUSED; enum machine_mode mode ATTRIBUTE_UNUSED;{#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 { rtx sum = XEXP (op, 0); HOST_WIDE_INT summand; /* We have to be careful here, because it is the referenced address that must be 32k from _SDA_BASE_, not just the symbol. */ summand = INTVAL (XEXP (sum, 1)); if (summand < 0 || summand > g_switch_value) return 0; sym_ref = XEXP (sum, 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 ATTRIBUTE_UNUSED; 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; cum->sysv_gregno = GP_ARG_MIN_REG; if (incoming) cum->nargs_prototype = 1000; /* don't return a PARALLEL */ 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 (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. */intfunction_arg_padding (mode, type) enum machine_mode mode; tree type;{ if (type != 0 && AGGREGATE_TYPE_P (type)) return (int)upward; /* This is the default definition. */ return (! BYTES_BIG_ENDIAN
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -