📄 ia64.c
字号:
end_sequence (); if (GET_MODE (op0) != Pmode) op0 = tga_ret; emit_libcall_block (insns, op0, tga_ret, op1); break; case TLS_MODEL_LOCAL_DYNAMIC: /* ??? This isn't the completely proper way to do local-dynamic If the call to __tls_get_addr is used only by a single symbol, then we should (somehow) move the dtprel to the second arg to avoid the extra add. */ start_sequence (); tga_op1 = gen_reg_rtx (Pmode); emit_insn (gen_load_dtpmod (tga_op1, op1)); tga_op2 = const0_rtx; tga_ret = emit_library_call_value (gen_tls_get_addr (), NULL_RTX, LCT_CONST, Pmode, 2, tga_op1, Pmode, tga_op2, Pmode); insns = get_insns (); end_sequence (); tga_eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx), UNSPEC_LD_BASE); tmp = gen_reg_rtx (Pmode); emit_libcall_block (insns, tmp, tga_ret, tga_eqv); if (!register_operand (op0, Pmode)) op0 = gen_reg_rtx (Pmode); if (TARGET_TLS64) { emit_insn (gen_load_dtprel (op0, op1)); emit_insn (gen_adddi3 (op0, tmp, op0)); } else emit_insn (gen_add_dtprel (op0, op1, tmp)); break; case TLS_MODEL_INITIAL_EXEC: op1 = plus_constant (op1, addend_hi); addend = addend_lo; tmp = gen_reg_rtx (Pmode); emit_insn (gen_load_tprel (tmp, op1)); if (!register_operand (op0, Pmode)) op0 = gen_reg_rtx (Pmode); emit_insn (gen_adddi3 (op0, tmp, gen_thread_pointer ())); break; case TLS_MODEL_LOCAL_EXEC: if (!register_operand (op0, Pmode)) op0 = gen_reg_rtx (Pmode); op1 = orig_op1; addend = 0; if (TARGET_TLS64) { emit_insn (gen_load_tprel (op0, op1)); emit_insn (gen_adddi3 (op0, op0, gen_thread_pointer ())); } else emit_insn (gen_add_tprel (op0, op1, gen_thread_pointer ())); break; default: abort (); } if (addend) op0 = expand_simple_binop (Pmode, PLUS, op0, GEN_INT (addend), orig_op0, 1, OPTAB_DIRECT); if (orig_op0 == op0) return NULL_RTX; if (GET_MODE (orig_op0) == Pmode) return op0; return gen_lowpart (GET_MODE (orig_op0), op0);}rtxia64_expand_move (rtx op0, rtx op1){ enum machine_mode mode = GET_MODE (op0); if (!reload_in_progress && !reload_completed && !ia64_move_ok (op0, op1)) op1 = force_reg (mode, op1); if ((mode == Pmode || mode == ptr_mode) && symbolic_operand (op1, VOIDmode)) { HOST_WIDE_INT addend = 0; enum tls_model tls_kind; rtx sym = op1; if (GET_CODE (op1) == CONST && GET_CODE (XEXP (op1, 0)) == PLUS && GET_CODE (XEXP (XEXP (op1, 0), 1)) == CONST_INT) { addend = INTVAL (XEXP (XEXP (op1, 0), 1)); sym = XEXP (XEXP (op1, 0), 0); } tls_kind = tls_symbolic_operand_type (sym); if (tls_kind) return ia64_expand_tls_address (tls_kind, op0, sym, addend); if (any_offset_symbol_operand (sym, mode)) addend = 0; else if (aligned_offset_symbol_operand (sym, mode)) { HOST_WIDE_INT addend_lo, addend_hi; addend_lo = ((addend & 0x3fff) ^ 0x2000) - 0x2000; addend_hi = addend - addend_lo; if (addend_lo != 0) { op1 = plus_constant (sym, addend_hi); addend = addend_lo; } else addend = 0; } else op1 = sym; if (reload_completed) { /* We really should have taken care of this offset earlier. */ gcc_assert (addend == 0); if (ia64_expand_load_address (op0, op1)) return NULL_RTX; } if (addend) { rtx subtarget = no_new_pseudos ? op0 : gen_reg_rtx (mode); emit_insn (gen_rtx_SET (VOIDmode, subtarget, op1)); op1 = expand_simple_binop (mode, PLUS, subtarget, GEN_INT (addend), op0, 1, OPTAB_DIRECT); if (op0 == op1) return NULL_RTX; } } return op1;}/* Split a move from OP1 to OP0 conditional on COND. */voidia64_emit_cond_move (rtx op0, rtx op1, rtx cond){ rtx insn, first = get_last_insn (); emit_move_insn (op0, op1); for (insn = get_last_insn (); insn != first; insn = PREV_INSN (insn)) if (INSN_P (insn)) PATTERN (insn) = gen_rtx_COND_EXEC (VOIDmode, copy_rtx (cond), PATTERN (insn));}/* Split a post-reload TImode or TFmode reference into two DImode components. This is made extra difficult by the fact that we do not get any scratch registers to work with, because reload cannot be prevented from giving us a scratch that overlaps the register pair involved. So instead, when addressing memory, we tweak the pointer register up and back down with POST_INCs. Or up and not back down when we can get away with it. REVERSED is true when the loads must be done in reversed order (high word first) for correctness. DEAD is true when the pointer dies with the second insn we generate and therefore the second address must not carry a postmodify. May return an insn which is to be emitted after the moves. */static rtxia64_split_tmode (rtx out[2], rtx in, bool reversed, bool dead){ rtx fixup = 0; switch (GET_CODE (in)) { case REG: out[reversed] = gen_rtx_REG (DImode, REGNO (in)); out[!reversed] = gen_rtx_REG (DImode, REGNO (in) + 1); break; case CONST_INT: case CONST_DOUBLE: /* Cannot occur reversed. */ if (reversed) abort (); if (GET_MODE (in) != TFmode) split_double (in, &out[0], &out[1]); else /* split_double does not understand how to split a TFmode quantity into a pair of DImode constants. */ { REAL_VALUE_TYPE r; unsigned HOST_WIDE_INT p[2]; long l[4]; /* TFmode is 128 bits */ REAL_VALUE_FROM_CONST_DOUBLE (r, in); real_to_target (l, &r, TFmode); if (FLOAT_WORDS_BIG_ENDIAN) { p[0] = (((unsigned HOST_WIDE_INT) l[0]) << 32) + l[1]; p[1] = (((unsigned HOST_WIDE_INT) l[2]) << 32) + l[3]; } else { p[0] = (((unsigned HOST_WIDE_INT) l[3]) << 32) + l[2]; p[1] = (((unsigned HOST_WIDE_INT) l[1]) << 32) + l[0]; } out[0] = GEN_INT (p[0]); out[1] = GEN_INT (p[1]); } break; case MEM: { rtx base = XEXP (in, 0); rtx offset; switch (GET_CODE (base)) { case REG: if (!reversed) { out[0] = adjust_automodify_address (in, DImode, gen_rtx_POST_INC (Pmode, base), 0); out[1] = adjust_automodify_address (in, DImode, dead ? 0 : gen_rtx_POST_DEC (Pmode, base), 8); } else { /* Reversal requires a pre-increment, which can only be done as a separate insn. */ emit_insn (gen_adddi3 (base, base, GEN_INT (8))); out[0] = adjust_automodify_address (in, DImode, gen_rtx_POST_DEC (Pmode, base), 8); out[1] = adjust_address (in, DImode, 0); } break; case POST_INC: if (reversed || dead) abort (); /* Just do the increment in two steps. */ out[0] = adjust_automodify_address (in, DImode, 0, 0); out[1] = adjust_automodify_address (in, DImode, 0, 8); break; case POST_DEC: if (reversed || dead) abort (); /* Add 8, subtract 24. */ base = XEXP (base, 0); out[0] = adjust_automodify_address (in, DImode, gen_rtx_POST_INC (Pmode, base), 0); out[1] = adjust_automodify_address (in, DImode, gen_rtx_POST_MODIFY (Pmode, base, plus_constant (base, -24)), 8); break; case POST_MODIFY: if (reversed || dead) abort (); /* Extract and adjust the modification. This case is trickier than the others, because we might have an index register, or we might have a combined offset that doesn't fit a signed 9-bit displacement field. We can assume the incoming expression is already legitimate. */ offset = XEXP (base, 1); base = XEXP (base, 0); out[0] = adjust_automodify_address (in, DImode, gen_rtx_POST_INC (Pmode, base), 0); if (GET_CODE (XEXP (offset, 1)) == REG) { /* Can't adjust the postmodify to match. Emit the original, then a separate addition insn. */ out[1] = adjust_automodify_address (in, DImode, 0, 8); fixup = gen_adddi3 (base, base, GEN_INT (-8)); } else if (GET_CODE (XEXP (offset, 1)) != CONST_INT) abort (); else if (INTVAL (XEXP (offset, 1)) < -256 + 8) { /* Again the postmodify cannot be made to match, but in this case it's more efficient to get rid of the postmodify entirely and fix up with an add insn. */ out[1] = adjust_automodify_address (in, DImode, base, 8); fixup = gen_adddi3 (base, base, GEN_INT (INTVAL (XEXP (offset, 1)) - 8)); } else { /* Combined offset still fits in the displacement field. (We cannot overflow it at the high end.) */ out[1] = adjust_automodify_address (in, DImode, gen_rtx_POST_MODIFY (Pmode, base, gen_rtx_PLUS (Pmode, base, GEN_INT (INTVAL (XEXP (offset, 1)) - 8))), 8); } break; default: abort (); } break; } default: abort (); } return fixup;}/* Split a TImode or TFmode move instruction after reload. This is used by *movtf_internal and *movti_internal. */voidia64_split_tmode_move (rtx operands[]){ rtx in[2], out[2], insn; rtx fixup[2]; bool dead = false; bool reversed = false; /* It is possible for reload to decide to overwrite a pointer with the value it points to. In that case we have to do the loads in the appropriate order so that the pointer is not destroyed too early. Also we must not generate a postmodify for that second load, or rws_access_regno will abort. */ if (GET_CODE (operands[1]) == MEM && reg_overlap_mentioned_p (operands[0], operands[1])) { rtx base = XEXP (operands[1], 0); while (GET_CODE (base) != REG) base = XEXP (base, 0); if (REGNO (base) == REGNO (operands[0])) reversed = true; dead = true; } /* Another reason to do the moves in reversed order is if the first element of the target register pair is also the second element of the source register pair. */ if (GET_CODE (operands[0]) == REG && GET_CODE (operands[1]) == REG && REGNO (operands[0]) == REGNO (operands[1]) + 1) reversed = true; fixup[0] = ia64_split_tmode (in, operands[1], reversed, dead); fixup[1] = ia64_split_tmode (out, operands[0], reversed, dead);#define MAYBE_ADD_REG_INC_NOTE(INSN, EXP) \ if (GET_CODE (EXP) == MEM \ && (GET_CODE (XEXP (EXP, 0)) == POST_MODIFY \ || GET_CODE (XEXP (EXP, 0)) == POST_INC \ || GET_CODE (XEXP (EXP, 0)) == POST_DEC)) \ REG_NOTES (INSN) = gen_rtx_EXPR_LIST (REG_INC, \ XEXP (XEXP (EXP, 0), 0), \ REG_NOTES (INSN)) insn = emit_insn (gen_rtx_SET (VOIDmode, out[0], in[0])); MAYBE_ADD_REG_INC_NOTE (insn, in[0]); MAYBE_ADD_REG_INC_NOTE (insn, out[0]); insn = emit_insn (gen_rtx_SET (VOIDmode, out[1], in[1])); MAYBE_ADD_REG_INC_NOTE (insn, in[1]); MAYBE_ADD_REG_INC_NOTE (insn, out[1]); if (fixup[0]) emit_insn (fixup[0]); if (fixup[1]) emit_insn (fixup[1]);#undef MAYBE_ADD_REG_INC_NOTE}/* ??? Fixing GR->FR XFmode moves during reload is hard. You need to go through memory plus an extra GR scratch register. Except that you can either get the first from SECONDARY_MEMORY_NEEDED or the second from SECONDARY_RELOAD_CLASS, but not both. We got into problems in the first place by allowing a construct like (subreg:XF (reg:TI)), which we got from a union containing a long double. This solution attempts to prevent this situation from occurring. When we see something like the above, we spill the inner register to memory. */rtxspill_xfmode_operand (rtx in, int force){ if (GET_CODE (in) == SUBREG && GET_MODE (SUBREG_REG (in)) == TImode && GET_CODE (SUBREG_REG (in)) == REG) { rtx memt = assign_stack_temp (TImode, 16, 0); emit_move_insn (memt, SUBREG_REG (in)); return adjust_address (memt, XFmode, 0); } else if (force && GET_CODE (in) == REG) { rtx memx = assign_stack_temp (XFmode, 16, 0); emit_move_insn (memx, in); return memx; } else return in;}/* Emit comparison instruction if necessary, returning the expression that holds the compare result in the proper mode. */static GTY(()) rtx cmptf_libfunc;rtxia64_expand_compare (enum rtx_code code, enum machine_mode mode){ rtx op0 = ia64_compare_op0, op1 = ia64_compare_op1; rtx cmp; /* If we have a BImode input, then we already have a compare result, and
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -