📄 rs6000.c
字号:
if (GET_MODE_BITSIZE (mode) > HOST_BITS_PER_WIDE_INT && opl < 0) return 0;#endif } else if (GET_CODE (op) == CONST_DOUBLE) { if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT) abort (); opl = CONST_DOUBLE_LOW (op); oph = CONST_DOUBLE_HIGH (op); if (oph != 0) return 0; } else return 0; return ((opl & ~ (unsigned HOST_WIDE_INT) 0xffff) == 0 || (opl & ~ (unsigned HOST_WIDE_INT) 0xffff0000) == 0);}/* Return 1 if C is a constant that is not a logical operand (as above), but could be split into one. */intnon_logical_cint_operand (op, mode) rtx op; enum machine_mode mode;{ return ((GET_CODE (op) == CONST_INT || GET_CODE (op) == CONST_DOUBLE) && ! logical_operand (op, mode) && reg_or_logical_cint_operand (op, mode));}/* 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) rtx op; enum machine_mode mode ATTRIBUTE_UNUSED;{ HOST_WIDE_INT c, lsb; if (GET_CODE (op) != CONST_INT) return 0; c = INTVAL (op); /* Fail in 64-bit mode if the mask wraps around because the upper 32-bits of the mask will all be 1s, contrary to GCC's internal view. */ if (TARGET_POWERPC64 && (c & 0x80000001) == 0x80000001) return 0; /* We don't change the number of transitions by inverting, so make sure we start with the LS bit zero. */ if (c & 1) c = ~c; /* Reject all zeros or all ones. */ if (c == 0) return 0; /* Find the first transition. */ lsb = c & -c; /* Invert to look for a second transition. */ c = ~c; /* Erase first transition. */ c &= -lsb; /* Find the second transition (if any). */ lsb = c & -c; /* Match if all the bits above are 1's (or c is zero). */ return c == -lsb;}/* 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) rtx op; enum machine_mode mode;{ if (GET_CODE (op) == CONST_INT) { HOST_WIDE_INT c, lsb; /* We don't change the number of transitions by inverting, so make sure we start with the LS bit zero. */ c = INTVAL (op); if (c & 1) c = ~c; /* Reject all zeros or all ones. */ if (c == 0) return 0; /* Find the transition, and check that all bits above are 1's. */ lsb = c & -c; return c == -lsb; } else if (GET_CODE (op) == CONST_DOUBLE && (mode == VOIDmode || mode == DImode)) { HOST_WIDE_INT low, high, lsb; if (HOST_BITS_PER_WIDE_INT < 64) high = CONST_DOUBLE_HIGH (op); low = CONST_DOUBLE_LOW (op); if (low & 1) { if (HOST_BITS_PER_WIDE_INT < 64) high = ~high; low = ~low; } if (low == 0) { if (HOST_BITS_PER_WIDE_INT >= 64 || high == 0) return 0; lsb = high & -high; return high == -lsb; } lsb = low & -low; return low == -lsb && (HOST_BITS_PER_WIDE_INT >= 64 || high == ~0); } 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) rtx op; enum machine_mode mode;{ if (fixed_regs[CR0_REGNO]) /* 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) rtx op; enum machine_mode mode;{ if (fixed_regs[CR0_REGNO]) /* 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) rtx op; 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) rtx op; 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 && (GET_CODE (XEXP (inner, 0)) != PLUS || GET_CODE (XEXP (XEXP (inner, 0), 1)) != CONST_INT || INTVAL (XEXP (XEXP (inner, 0), 1)) % 4 == 0));}/* 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) 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) 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) 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; /* A constant pool expression (relative to the TOC) is valid */ if (TOC_RELATIVE_EXPR_P (op)) return 1; /* V.4 allows SYMBOL_REFs and CONSTs that are in the small data region to be valid. */ if (DEFAULT_ABI == ABI_V4 && (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; if (rs6000_sdata == SDATA_NONE || rs6000_sdata == SDATA_DATA) return 0; if (DEFAULT_ABI != ABI_V4) 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}static int constant_pool_expr_1 (op, have_sym, have_toc) rtx op; int *have_sym; int *have_toc;{ switch (GET_CODE(op)) { case SYMBOL_REF: if (CONSTANT_POOL_ADDRESS_P (op)) { if (ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (get_pool_constant (op), Pmode)) { *have_sym = 1; return 1; } else return 0; } else if (! strcmp (XSTR (op, 0), toc_label_name)) { *have_toc = 1; return 1; } else return 0; case PLUS: case MINUS: return (constant_pool_expr_1 (XEXP (op, 0), have_sym, have_toc) && constant_pool_expr_1 (XEXP (op, 1), have_sym, have_toc)); case CONST: return constant_pool_expr_1 (XEXP (op, 0), have_sym, have_toc); case CONST_INT: return 1; default: return 0; }}intconstant_pool_expr_p (op) rtx op;{ int have_sym = 0; int have_toc = 0; return constant_pool_expr_1 (op, &have_sym, &have_toc) && have_sym;}inttoc_relative_expr_p (op) rtx op;{ int have_sym = 0; int have_toc = 0; return constant_pool_expr_1 (op, &have_sym, &have_toc) && have_toc;}/* Try machine-dependent ways of modifying an illegitimate address to be legitimate. If we find one, return the new, valid address. This is used from only one place: `memory_address' in explow.c. OLDX is the address as it was before break_out_memory_refs was called. In some cases it is useful to look at this to decide what needs to be done. MODE is passed so that this function can use GO_IF_LEGITIMATE_ADDRESS. It is always safe for this function to do nothing. It exists to recognize opportunities to optimize the output. On RS/6000, first check for the sum of a register with a constant integer that is out of range. If so, generate code to add the constant with the low-order 16 bits masked to the register and force this result into another register (this can be done with `cau'). Then generate an address of REG+(CONST&0xffff), allowing for the possibility of bit 16 being a one. Then check for the sum of a register and something not constant, try to load the other things into a register and return the sum. */rtxrs6000_legitimize_address (x, oldx, mode) rtx x; rtx oldx ATTRIBUTE_UNUSED; enum machine_mode mode;{ if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 0)) == REG && GET_CODE (XEXP (x, 1)) == CONST_INT && (unsigned HOST_WIDE_INT) (INTVAL (XEXP (x, 1)) + 0x8000) >= 0x10000) { HOST_WIDE_INT high_int, low_int; rtx sum; high_int = INTVAL (XEXP (x, 1)) & (~ (HOST_WIDE_INT) 0xffff); low_int = INTVAL (XEXP (x, 1)) & 0xffff; if (low_int & 0x8000) high_int += 0x10000, low_int |= ((HOST_WIDE_INT) -1) << 16; sum = force_operand (gen_rtx_PLUS (Pmode, XEXP (x, 0), GEN_INT (high_int)), 0); return gen_rtx_PLUS (Pmode, sum, GEN_INT (low_int)); } else if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 0)) == REG && GET_CODE (XEXP (x, 1)) != CONST_INT && GET_MODE_NUNITS (mode) == 1 && (TARGET_HARD_FLOAT || TARGET_POWERPC64 || mode != DFmode) && (TARGET_POWERPC64 || mode != DImode) && mode != TImode) { return gen_rtx_PLUS (Pmode, XEXP (x, 0), force_reg (Pmode, force_operand (XEXP (x, 1), 0))); } else if (ALTIVEC_VECTOR_MODE (mode)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -