📄 pa.c
字号:
if (reload_in_progress || reload_completed) { temp = scratch_reg ? scratch_reg : operand0; /* TEMP will hold an address and maybe the actual data. We want it in WORD_MODE regardless of what mode it was originally given to us. */ temp = force_mode (word_mode, temp); } else temp = gen_reg_rtx (Pmode); /* (const (plus (symbol) (const_int))) must be forced to memory during/after reload if the const_int will not fit in 14 bits. */ if (GET_CODE (operand1) == CONST && GET_CODE (XEXP (operand1, 0)) == PLUS && GET_CODE (XEXP (XEXP (operand1, 0), 1)) == CONST_INT && !INT_14_BITS (XEXP (XEXP (operand1, 0), 1)) && (reload_completed || reload_in_progress) && flag_pic) { rtx const_mem = force_const_mem (mode, operand1); operands[1] = legitimize_pic_address (XEXP (const_mem, 0), mode, temp); operands[1] = replace_equiv_address (const_mem, operands[1]); emit_move_sequence (operands, mode, temp); } else { operands[1] = legitimize_pic_address (operand1, mode, temp); if (REG_P (operand0) && REG_P (operands[1])) copy_reg_pointer (operand0, operands[1]); emit_insn (gen_rtx_SET (VOIDmode, operand0, operands[1])); } } /* On the HPPA, references to data space are supposed to use dp, register 27, but showing it in the RTL inhibits various cse and loop optimizations. */ else { rtx temp, set; if (reload_in_progress || reload_completed) { temp = scratch_reg ? scratch_reg : operand0; /* TEMP will hold an address and maybe the actual data. We want it in WORD_MODE regardless of what mode it was originally given to us. */ temp = force_mode (word_mode, temp); } else temp = gen_reg_rtx (mode); /* Loading a SYMBOL_REF into a register makes that register safe to be used as the base in an indexed address. Don't mark hard registers though. That loses. */ if (GET_CODE (operand0) == REG && REGNO (operand0) >= FIRST_PSEUDO_REGISTER) mark_reg_pointer (operand0, BITS_PER_UNIT); if (REGNO (temp) >= FIRST_PSEUDO_REGISTER) mark_reg_pointer (temp, BITS_PER_UNIT); if (ishighonly) set = gen_rtx_SET (mode, operand0, temp); else set = gen_rtx_SET (VOIDmode, operand0, gen_rtx_LO_SUM (mode, temp, operand1)); emit_insn (gen_rtx_SET (VOIDmode, temp, gen_rtx_HIGH (mode, operand1))); emit_insn (set); } return 1; } else if (pa_tls_referenced_p (operand1)) { rtx tmp = operand1; rtx addend = NULL; if (GET_CODE (tmp) == CONST && GET_CODE (XEXP (tmp, 0)) == PLUS) { addend = XEXP (XEXP (tmp, 0), 1); tmp = XEXP (XEXP (tmp, 0), 0); } gcc_assert (GET_CODE (tmp) == SYMBOL_REF); tmp = legitimize_tls_address (tmp); if (addend) { tmp = gen_rtx_PLUS (mode, tmp, addend); tmp = force_operand (tmp, operands[0]); } operands[1] = tmp; } else if (GET_CODE (operand1) != CONST_INT || !cint_ok_for_move (INTVAL (operand1))) { rtx insn, temp; rtx op1 = operand1; HOST_WIDE_INT value = 0; HOST_WIDE_INT insv = 0; int insert = 0; if (GET_CODE (operand1) == CONST_INT) value = INTVAL (operand1); if (TARGET_64BIT && GET_CODE (operand1) == CONST_INT && HOST_BITS_PER_WIDE_INT > 32 && GET_MODE_BITSIZE (GET_MODE (operand0)) > 32) { HOST_WIDE_INT nval; /* Extract the low order 32 bits of the value and sign extend. If the new value is the same as the original value, we can can use the original value as-is. If the new value is different, we use it and insert the most-significant 32-bits of the original value into the final result. */ nval = ((value & (((HOST_WIDE_INT) 2 << 31) - 1)) ^ ((HOST_WIDE_INT) 1 << 31)) - ((HOST_WIDE_INT) 1 << 31); if (value != nval) {#if HOST_BITS_PER_WIDE_INT > 32 insv = value >= 0 ? value >> 32 : ~(~value >> 32);#endif insert = 1; value = nval; operand1 = GEN_INT (nval); } } if (reload_in_progress || reload_completed) temp = scratch_reg ? scratch_reg : operand0; else temp = gen_reg_rtx (mode); /* We don't directly split DImode constants on 32-bit targets because PLUS uses an 11-bit immediate and the insn sequence generated is not as efficient as the one using HIGH/LO_SUM. */ if (GET_CODE (operand1) == CONST_INT && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT && !insert) { /* Directly break constant into high and low parts. This provides better optimization opportunities because various passes recognize constants split with PLUS but not LO_SUM. We use a 14-bit signed low part except when the addition of 0x4000 to the high part might change the sign of the high part. */ HOST_WIDE_INT low = value & 0x3fff; HOST_WIDE_INT high = value & ~ 0x3fff; if (low >= 0x2000) { if (high == 0x7fffc000 || (mode == HImode && high == 0x4000)) high += 0x2000; else high += 0x4000; } low = value - high; emit_insn (gen_rtx_SET (VOIDmode, temp, GEN_INT (high))); operands[1] = gen_rtx_PLUS (mode, temp, GEN_INT (low)); } else { emit_insn (gen_rtx_SET (VOIDmode, temp, gen_rtx_HIGH (mode, operand1))); operands[1] = gen_rtx_LO_SUM (mode, temp, operand1); } insn = emit_move_insn (operands[0], operands[1]); /* Now insert the most significant 32 bits of the value into the register. When we don't have a second register available, it could take up to nine instructions to load a 64-bit integer constant. Prior to reload, we force constants that would take more than three instructions to load to the constant pool. During and after reload, we have to handle all possible values. */ if (insert) { /* Use a HIGH/LO_SUM/INSV sequence if we have a second register and the value to be inserted is outside the range that can be loaded with three depdi instructions. */ if (temp != operand0 && (insv >= 16384 || insv < -16384)) { operand1 = GEN_INT (insv); emit_insn (gen_rtx_SET (VOIDmode, temp, gen_rtx_HIGH (mode, operand1))); emit_move_insn (temp, gen_rtx_LO_SUM (mode, temp, operand1)); emit_insn (gen_insv (operand0, GEN_INT (32), const0_rtx, temp)); } else { int len = 5, pos = 27; /* Insert the bits using the depdi instruction. */ while (pos >= 0) { HOST_WIDE_INT v5 = ((insv & 31) ^ 16) - 16; HOST_WIDE_INT sign = v5 < 0; /* Left extend the insertion. */ insv = (insv >= 0 ? insv >> len : ~(~insv >> len)); while (pos > 0 && (insv & 1) == sign) { insv = (insv >= 0 ? insv >> 1 : ~(~insv >> 1)); len += 1; pos -= 1; } emit_insn (gen_insv (operand0, GEN_INT (len), GEN_INT (pos), GEN_INT (v5))); len = pos > 0 && pos < 5 ? pos : 5; pos -= len; } } } REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUAL, op1, REG_NOTES (insn)); return 1; } } /* Now have insn-emit do whatever it normally does. */ return 0;}/* Examine EXP and return nonzero if it contains an ADDR_EXPR (meaning it will need a link/runtime reloc). */intreloc_needed (tree exp){ int reloc = 0; switch (TREE_CODE (exp)) { case ADDR_EXPR: return 1; case PLUS_EXPR: case MINUS_EXPR: reloc = reloc_needed (TREE_OPERAND (exp, 0)); reloc |= reloc_needed (TREE_OPERAND (exp, 1)); break; case NOP_EXPR: case CONVERT_EXPR: case NON_LVALUE_EXPR: reloc = reloc_needed (TREE_OPERAND (exp, 0)); break; case CONSTRUCTOR: { tree value; unsigned HOST_WIDE_INT ix; FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (exp), ix, value) if (value) reloc |= reloc_needed (value); } break; case ERROR_MARK: break; default: break; } return reloc;}/* Does operand (which is a symbolic_operand) live in text space? If so, SYMBOL_REF_FLAG, which is set by pa_encode_section_info, will be true. */intread_only_operand (rtx operand, enum machine_mode mode ATTRIBUTE_UNUSED){ if (GET_CODE (operand) == CONST) operand = XEXP (XEXP (operand, 0), 0); if (flag_pic) { if (GET_CODE (operand) == SYMBOL_REF) return SYMBOL_REF_FLAG (operand) && !CONSTANT_POOL_ADDRESS_P (operand); } else { if (GET_CODE (operand) == SYMBOL_REF) return SYMBOL_REF_FLAG (operand) || CONSTANT_POOL_ADDRESS_P (operand); } return 1;}/* Return the best assembler insn template for moving operands[1] into operands[0] as a fullword. */const char *singlemove_string (rtx *operands){ HOST_WIDE_INT intval; if (GET_CODE (operands[0]) == MEM) return "stw %r1,%0"; if (GET_CODE (operands[1]) == MEM) return "ldw %1,%0"; if (GET_CODE (operands[1]) == CONST_DOUBLE) { long i; REAL_VALUE_TYPE d; gcc_assert (GET_MODE (operands[1]) == SFmode); /* Translate the CONST_DOUBLE to a CONST_INT with the same target bit pattern. */ REAL_VALUE_FROM_CONST_DOUBLE (d, operands[1]); REAL_VALUE_TO_TARGET_SINGLE (d, i); operands[1] = GEN_INT (i); /* Fall through to CONST_INT case. */ } if (GET_CODE (operands[1]) == CONST_INT) { intval = INTVAL (operands[1]); if (VAL_14_BITS_P (intval)) return "ldi %1,%0"; else if ((intval & 0x7ff) == 0) return "ldil L'%1,%0"; else if (zdepi_cint_p (intval)) return "{zdepi %Z1,%0|depwi,z %Z1,%0}"; else return "ldil L'%1,%0\n\tldo R'%1(%0),%0"; } return "copy %1,%0";}/* Compute position (in OP[1]) and width (in OP[2]) useful for copying IMM to a register using the zdepi instructions. Store the immediate value to insert in OP[0]. */static voidcompute_zdepwi_operands (unsigned HOST_WIDE_INT imm, unsigned *op){ int lsb, len; /* Find the least significant set bit in IMM. */ for (lsb = 0; lsb < 32; lsb++) { if ((imm & 1) != 0) break; imm >>= 1; } /* Choose variants based on *sign* of the 5-bit field. */ if ((imm & 0x10) == 0) len = (lsb <= 28) ? 4 : 32 - lsb; else { /* Find the width of the bitstring in IMM. */ for (len = 5; len < 32; len++) { if ((imm & (1 << len)) == 0) break; } /* Sign extend IMM as a 5-bit value. */ imm = (imm & 0xf) - 0x10; } op[0] = imm; op[1] = 31 - lsb; op[2] = len;}/* Compute position (in OP[1]) and width (in OP[2]) useful for copying IMM to a register using the depdi,z instructions. Store the immediate value to insert in OP[0]. */voidcompute_zdepdi_operands (unsigned HOST_WIDE_INT imm, unsigned *op){ HOST_WIDE_INT lsb, len; /* Find the least significant set bit in IMM. */ for (lsb = 0; lsb < HOST_BITS_PER_WIDE_INT; lsb++) { if ((imm & 1) != 0) break; imm >>= 1; } /* Choose variants based on *sign* of the 5-bit field. */ if ((imm & 0x10) == 0) len = ((lsb <= HOST_BITS_PER_WIDE_INT - 4) ? 4 : HOST_BITS_PER_WIDE_INT - lsb); else { /* Find the width of the bitstring in IMM. */ for (len = 5; len < HOST_BITS_PER_WIDE_INT; len++) { if ((imm & ((unsigned HOST_WIDE_INT) 1 << len)) == 0) break; } /* Sign extend IMM as a 5-bit value. */ imm = (imm & 0xf) - 0x10; } op[0] = imm; op[1] = 63 - lsb; op[2] = len;}/* Output assembler code to perform a doubleword move insn with operands OPERANDS. */const char *output_move_double (rtx *operands){ enum { REGOP, OFFSOP
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -