📄 rs6000.c
字号:
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));}/* Like the above, but also match constants that can be implemented with two rldicl or rldicr insns. */intand64_2_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_2_operand (op, mode); return logical_operand (op, mode) || mask64_2_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 SYMBOL_REF. */intsymbol_ref_operand (op, mode) rtx op; enum machine_mode mode;{ if (mode != VOIDmode && GET_MODE (op) != mode) return 0; return (GET_CODE (op) == SYMBOL_REF);}/* Return 1 if the operand, used inside a MEM, is a valid first argument to CALL. This is a SYMBOL_REF, a pseudo-register, LR or CTR. */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) == LINK_REGISTER_REGNUM || REGNO (op) == COUNT_REGISTER_REGNUM || 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; low_int = ((INTVAL (XEXP (x, 1)) & 0xffff) ^ 0x8000) - 0x8000; high_int = INTVAL (XEXP (x, 1)) - low_int; 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_FPRS) || TARGET_POWERPC64 || (mode != DFmode && mode != TFmode)) && (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)) { rtx reg; /* Make sure both operands are registers. */ if (GET_CODE (x) == PLUS) return gen_rtx_PLUS (Pmode, force_reg (Pmode, XEXP (x, 0)), force_reg (Pmode, XEXP (x, 1))); reg = force_reg (Pmode, x); return reg; } else if (SPE_VECTOR_MODE (mode)) { /* We accept [reg + reg] and [reg + OFFSET]. */ if (GET_CODE (x) == PLUS) { rtx op1 = XEXP (x, 0); rtx op2 = XEXP (x, 1); op1 = force_reg (Pmode, op1); if (GET_CODE (op2) != REG && (GET_CODE (op2) != CONST_INT || !SPE_CONST_OFFSET_OK (INTVAL (op2)))) op2 = force_reg (Pmode, op2); return gen_rtx_PLUS (Pmode, op1, op2); } return force_reg (Pmode, x); } else if (TARGET_ELF && TARGET_32BIT && TARGET_NO_TOC && ! flag_pic && GET_CODE (x) != CONST_INT && GET_CODE (x) != CONST_DOUBLE && CONSTANT_P (x) && GET_MODE_NUNITS (mode) == 1 && (GET_MODE_BITSIZE (mode) <= 32 || ((TARGET_HARD_FLOAT && TARGET_FPRS) && mode == DFmode))) { rtx reg = gen_reg_rtx (Pmode); emit_insn (gen_elf_high (reg, (x))); return gen_rtx_LO_SUM (Pmode, reg, (x)); } else if (TARGET_MACHO && TARGET_32BIT && TARGET_NO_TOC && ! flag_pic && GET_CODE (x) != CONST_INT && GET_CODE (x) != CONST_DOUBLE && CONSTANT_P (x) && ((TARGET_HARD_FLOAT && TARGET_FPRS) || mode != DFmode) && mode != DImode && mode != TImode) { rtx reg = gen_reg_rtx (Pmode); emit_insn (gen_macho_high (reg, (x))); return gen_rtx_LO_SUM (Pmode, reg, (x)); } else if (TARGET_TOC && CONSTANT_POOL_EXPR_P (x) && ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (get_pool_constant (x), Pmode)) { return create_TOC_reference (x); } else return NULL_RTX;}/* The convention appears to be to define this wherever it is used. With legitimize_reload_address now defined here, REG_MODE_OK_FOR_BASE_P is now used here. */#ifndef REG_MODE_OK_FOR_BASE_P#define REG_MODE_OK_FOR_BASE_P(REGNO, MODE) REG_OK_FOR_BASE_P (REGNO)#endif/* Our implementation of LEGITIMIZE_RELOAD_ADDRESS. Returns a value to replace the input X, or the original X if no replacement is called for. The output parameter *WIN is 1 if the calling macro should goto WIN, 0 if it should not. For RS/6000, we wish to handle large displacements off a base register by splitting the addend across an addiu/addis and the mem insn. This cuts number of extra insns needed from 3 to 1. On Darwin, we use this to generate code for floating point constants. A movsf_low is generated so we wind up with 2 instructions rather than 3. The Darwin code is inside #if TARGET_MACHO because only then is machopic_function_base_name() defined. */rtxrs6000_legitimize_reload_address (x, mode, opnum, type, ind_levels, win) rtx x; enum machine_mode mode; int opnum; int type; int ind_levels ATTRIBUTE_UNUSED; int *win;{ /* We must recognize output that we have already generated ourselves. */ if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 0)) == PLUS && GET_CODE (XEXP (XEXP (x, 0), 0)) == REG && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT && GET_CODE (XEXP (x, 1)) == CONST_INT) { push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL, BASE_REG_CLASS, GET_MODE (x), VOIDmode, 0, 0, opnum, (enum reload_type)type); *win = 1; return x; }#if TARGET_MACHO if (DEFAULT_ABI == ABI_DARWIN && flag_pic && GET_CODE (x) == LO_SUM && GET_CODE (XEXP (x, 0)) == PLUS && XEXP (XEXP (x, 0), 0) == pic_offset_table_rtx && GET_CODE (XEXP (XEXP (x, 0), 1)) == HIGH && GET_CODE (XEXP (XEXP (XEXP (x, 0), 1), 0)) == CONST && XEXP (XEXP (
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -