From 5e6c8b642870fa915835308210a6bd3679d3c9c5 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 11 May 2005 14:34:19 -0700 Subject: [PATCH] re PR target/21412 (ICE loading TLS address) PR target/21412 * config/ia64/ia64.c (TARGET_CANNOT_FORCE_CONST_MEM): New. (ia64_cannot_force_const_mem): New. (tls_symbolic_operand_type): New. (ia64_legitimate_constant_p): New. (ia64_expand_load_address): Return true on success. Improve checks for when we should not split. (ia64_expand_tls_address): New addend operand. Distribute it as appropriate to the tls_kind. Delay referencing gp. (ia64_expand_move): Split symbolic addend as necessary. Handle tls symbols with addends. * config/ia64/ia64-protos.h: Update. * config/ia64/ia64.h (CALL_REALLY_USED_REGISTERS): False for r0, p0, f0, f1, and r13. (LEGITIMATE_CONSTANT_P): Move to ia64_legitimate_constant_p. * config/ia64/ia64.md (UNSPEC_DTPMOD): New. (symbolic_operand splitter): Pass everything through ia64_expand_load_address and FAIL or DONE as appropriate. (load_fptr): Only accept after reload. (load_fptr_internal1, gprel64_offset, load_gprel64, load_symptr_high, load_symptr_low, load_ltoff_dtpmod, (load_dtpmod): New. (load_dtprel): Only accept tls symbols. (load_dtprel64, load_dtprel22): Likewise. (load_tprel, load_tprel64, load_tprel22): Likewise. (load_dtprel_gd, load_ltoff_dtprel, load_tprel_ie): New. (add_dtprel): Only accept tls symbols. Canonicalize PLUS. (add_dtprel14, add_dtprel22): Likewise. (add_tprel, add_tprel14, add_tprel22): Likewise. * config/ia64/predicates.md (small_addr_symbolic_operand): New. (any_offset_symbol_operand, aligned_offset_symbol_operand): New. (got_symbolic_operand): Check CONST offsets. (tls_symbolic_operand, ld_tls_symbolic_operand): New. (ie_tls_symbolic_operand, le_tls_symbolic_operand): New. (move_operand): Don't handle tls here. Check CONST offsets. From-SVN: r99596 --- gcc/ChangeLog | 38 ++++++ gcc/config/ia64/ia64-protos.h | 3 +- gcc/config/ia64/ia64.c | 229 ++++++++++++++++++++++++++---------- gcc/config/ia64/ia64.h | 11 +- gcc/config/ia64/ia64.md | 192 +++++++++++++++++++----------- gcc/config/ia64/predicates.md | 265 +++++++++++++++++++++++++++++++++++------- 6 files changed, 559 insertions(+), 179 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index afbf5af7..f92014e 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,41 @@ +2005-05-11 Richard Henderson + + PR target/21412 + * config/ia64/ia64.c (TARGET_CANNOT_FORCE_CONST_MEM): New. + (ia64_cannot_force_const_mem): New. + (tls_symbolic_operand_type): New. + (ia64_legitimate_constant_p): New. + (ia64_expand_load_address): Return true on success. Improve + checks for when we should not split. + (ia64_expand_tls_address): New addend operand. Distribute it + as appropriate to the tls_kind. Delay referencing gp. + (ia64_expand_move): Split symbolic addend as necessary. Handle + tls symbols with addends. + * config/ia64/ia64-protos.h: Update. + * config/ia64/ia64.h (CALL_REALLY_USED_REGISTERS): False for r0, + p0, f0, f1, and r13. + (LEGITIMATE_CONSTANT_P): Move to ia64_legitimate_constant_p. + * config/ia64/ia64.md (UNSPEC_DTPMOD): New. + (symbolic_operand splitter): Pass everything through + ia64_expand_load_address and FAIL or DONE as appropriate. + (load_fptr): Only accept after reload. + (load_fptr_internal1, gprel64_offset, load_gprel64, load_symptr_high, + load_symptr_low, load_ltoff_dtpmod, + (load_dtpmod): New. + (load_dtprel): Only accept tls symbols. + (load_dtprel64, load_dtprel22): Likewise. + (load_tprel, load_tprel64, load_tprel22): Likewise. + (load_dtprel_gd, load_ltoff_dtprel, load_tprel_ie): New. + (add_dtprel): Only accept tls symbols. Canonicalize PLUS. + (add_dtprel14, add_dtprel22): Likewise. + (add_tprel, add_tprel14, add_tprel22): Likewise. + * config/ia64/predicates.md (small_addr_symbolic_operand): New. + (any_offset_symbol_operand, aligned_offset_symbol_operand): New. + (got_symbolic_operand): Check CONST offsets. + (tls_symbolic_operand, ld_tls_symbolic_operand): New. + (ie_tls_symbolic_operand, le_tls_symbolic_operand): New. + (move_operand): Don't handle tls here. Check CONST offsets. + 2005-05-11 Richard Sandiford * config/mips/7000.md (rm7_impy_si_mult): Just match imul and imadd. diff --git a/gcc/config/ia64/ia64-protos.h b/gcc/config/ia64/ia64-protos.h index 1eb4588..94fa176 100644 --- a/gcc/config/ia64/ia64-protos.h +++ b/gcc/config/ia64/ia64-protos.h @@ -37,6 +37,7 @@ extern int ia64_produce_address_p (rtx); extern bool ia64_const_ok_for_letter_p (HOST_WIDE_INT, char); extern bool ia64_const_double_ok_for_letter_p (rtx, char); extern bool ia64_extra_constraint (rtx, char); +extern bool ia64_legitimate_constant_p (rtx); extern rtx ia64_expand_move (rtx, rtx); extern int ia64_move_ok (rtx, rtx); @@ -58,7 +59,7 @@ extern void ia64_expand_prologue (void); extern void ia64_expand_epilogue (int); extern int ia64_direct_return (void); -extern void ia64_expand_load_address (rtx, rtx); +extern bool ia64_expand_load_address (rtx, rtx); extern int ia64_hard_regno_rename_ok (int, int); extern void ia64_initialize_trampoline (rtx, rtx, rtx); diff --git a/gcc/config/ia64/ia64.c b/gcc/config/ia64/ia64.c index d75a74f..a4d12c9 100644 --- a/gcc/config/ia64/ia64.c +++ b/gcc/config/ia64/ia64.c @@ -163,7 +163,6 @@ static int ia64_first_cycle_multipass_dfa_lookahead_guard (rtx); static int ia64_dfa_new_cycle (FILE *, int, rtx, int, int, int *); static rtx gen_tls_get_addr (void); static rtx gen_thread_pointer (void); -static rtx ia64_expand_tls_address (enum tls_model, rtx, rtx); static int find_gr_spill (int); static int next_scratch_gr_reg (void); static void mark_reg_gr_used_mask (rtx, void *); @@ -264,7 +263,7 @@ static rtx ia64_struct_value_rtx (tree, int); static tree ia64_gimplify_va_arg (tree, tree, tree *, tree *); static bool ia64_scalar_mode_supported_p (enum machine_mode mode); static bool ia64_vector_mode_supported_p (enum machine_mode mode); - +static bool ia64_cannot_force_const_mem (rtx); /* Table of valid machine attributes. */ static const struct attribute_spec ia64_attribute_table[] = @@ -424,6 +423,9 @@ static const struct attribute_spec ia64_attribute_table[] = #undef TARGET_HANDLE_OPTION #define TARGET_HANDLE_OPTION ia64_handle_option +#undef TARGET_CANNOT_FORCE_CONST_MEM +#define TARGET_CANNOT_FORCE_CONST_MEM ia64_cannot_force_const_mem + struct gcc_target targetm = TARGET_INITIALIZER; typedef enum @@ -693,12 +695,64 @@ ia64_depz_field_mask (rtx rop, rtx rshift) return exact_log2 (op + 1); } +/* Return the TLS model to use for ADDR. */ + +static enum tls_model +tls_symbolic_operand_type (rtx addr) +{ + enum tls_model tls_kind = 0; + + if (GET_CODE (addr) == CONST) + { + if (GET_CODE (XEXP (addr, 0)) == PLUS + && GET_CODE (XEXP (XEXP (addr, 0), 0)) == SYMBOL_REF) + tls_kind = SYMBOL_REF_TLS_MODEL (XEXP (XEXP (addr, 0), 0)); + } + else if (GET_CODE (addr) == SYMBOL_REF) + tls_kind = SYMBOL_REF_TLS_MODEL (addr); + + return tls_kind; +} + +/* Return true if X is a constant that is valid for some immediate + field in an instruction. */ + +bool +ia64_legitimate_constant_p (rtx x) +{ + switch (GET_CODE (x)) + { + case CONST_INT: + case LABEL_REF: + return true; + + case CONST_DOUBLE: + if (GET_MODE (x) == VOIDmode) + return true; + return CONST_DOUBLE_OK_FOR_G (x); + + case CONST: + case SYMBOL_REF: + return tls_symbolic_operand_type (x) == 0; + + default: + return false; + } +} + +/* Don't allow TLS addresses to get spilled to memory. */ + +static bool +ia64_cannot_force_const_mem (rtx x) +{ + return tls_symbolic_operand_type (x) != 0; +} + /* Expand a symbolic constant load. */ -void +bool ia64_expand_load_address (rtx dest, rtx src) { - gcc_assert (GET_CODE (src) != SYMBOL_REF || !SYMBOL_REF_TLS_MODEL (src)); gcc_assert (GET_CODE (dest) == REG); /* ILP32 mode still loads 64-bits of data from the GOT. This avoids @@ -706,57 +760,59 @@ ia64_expand_load_address (rtx dest, rtx src) computation below are also more natural to compute as 64-bit quantities. If we've been given an SImode destination register, change it. */ if (GET_MODE (dest) != Pmode) - dest = gen_rtx_REG (Pmode, REGNO (dest)); + dest = gen_rtx_REG_offset (dest, Pmode, REGNO (dest), 0); - if (GET_CODE (src) == SYMBOL_REF && SYMBOL_REF_SMALL_ADDR_P (src)) - { - emit_insn (gen_rtx_SET (VOIDmode, dest, src)); - return; - } - else if (TARGET_AUTO_PIC) - { - emit_insn (gen_load_gprel64 (dest, src)); - return; - } + if (TARGET_NO_PIC) + return false; + if (small_addr_symbolic_operand (src, VOIDmode)) + return false; + + if (TARGET_AUTO_PIC) + emit_insn (gen_load_gprel64 (dest, src)); else if (GET_CODE (src) == SYMBOL_REF && SYMBOL_REF_FUNCTION_P (src)) - { - emit_insn (gen_load_fptr (dest, src)); - return; - } + emit_insn (gen_load_fptr (dest, src)); else if (sdata_symbolic_operand (src, VOIDmode)) + emit_insn (gen_load_gprel (dest, src)); + else { - emit_insn (gen_load_gprel (dest, src)); - return; - } + HOST_WIDE_INT addend = 0; + rtx tmp; - if (GET_CODE (src) == CONST - && GET_CODE (XEXP (src, 0)) == PLUS - && GET_CODE (XEXP (XEXP (src, 0), 1)) == CONST_INT - && (INTVAL (XEXP (XEXP (src, 0), 1)) & 0x3fff) != 0) - { - rtx sym = XEXP (XEXP (src, 0), 0); - HOST_WIDE_INT ofs, hi, lo; + /* We did split constant offsets in ia64_expand_move, and we did try + to keep them split in move_operand, but we also allowed reload to + rematerialize arbitrary constants rather than spill the value to + the stack and reload it. So we have to be prepared here to split + them apart again. */ + if (GET_CODE (src) == CONST) + { + HOST_WIDE_INT hi, lo; - /* Split the offset into a sign extended 14-bit low part - and a complementary high part. */ - ofs = INTVAL (XEXP (XEXP (src, 0), 1)); - lo = ((ofs & 0x3fff) ^ 0x2000) - 0x2000; - hi = ofs - lo; + hi = INTVAL (XEXP (XEXP (src, 0), 1)); + lo = ((hi & 0x3fff) ^ 0x2000) - 0x2000; + hi = hi - lo; - ia64_expand_load_address (dest, plus_constant (sym, hi)); - emit_insn (gen_adddi3 (dest, dest, GEN_INT (lo))); - } - else - { - rtx tmp; + if (lo != 0) + { + addend = lo; + src = plus_constant (XEXP (XEXP (src, 0), 0), hi); + } + } tmp = gen_rtx_HIGH (Pmode, src); tmp = gen_rtx_PLUS (Pmode, tmp, pic_offset_table_rtx); emit_insn (gen_rtx_SET (VOIDmode, dest, tmp)); - tmp = gen_rtx_LO_SUM (GET_MODE (dest), dest, src); + tmp = gen_rtx_LO_SUM (Pmode, dest, src); emit_insn (gen_rtx_SET (VOIDmode, dest, tmp)); + + if (addend) + { + tmp = gen_rtx_PLUS (Pmode, dest, GEN_INT (addend)); + emit_insn (gen_rtx_SET (VOIDmode, dest, tmp)); + } } + + return true; } static GTY(()) rtx gen_tls_tga; @@ -778,10 +834,15 @@ gen_thread_pointer (void) } static rtx -ia64_expand_tls_address (enum tls_model tls_kind, rtx op0, rtx op1) +ia64_expand_tls_address (enum tls_model tls_kind, rtx op0, rtx op1, + HOST_WIDE_INT addend) { rtx tga_op1, tga_op2, tga_ret, tga_eqv, tmp, insns; - rtx orig_op0 = op0; + rtx orig_op0 = op0, orig_op1 = op1; + HOST_WIDE_INT addend_lo, addend_hi; + + addend_lo = ((addend & 0x3fff) ^ 0x2000) - 0x2000; + addend_hi = addend - addend_lo; switch (tls_kind) { @@ -789,12 +850,10 @@ ia64_expand_tls_address (enum tls_model tls_kind, rtx op0, rtx op1) start_sequence (); tga_op1 = gen_reg_rtx (Pmode); - emit_insn (gen_load_ltoff_dtpmod (tga_op1, op1)); - tga_op1 = gen_const_mem (Pmode, tga_op1); + emit_insn (gen_load_dtpmod (tga_op1, op1)); tga_op2 = gen_reg_rtx (Pmode); - emit_insn (gen_load_ltoff_dtprel (tga_op2, op1)); - tga_op2 = gen_const_mem (Pmode, tga_op2); + emit_insn (gen_load_dtprel (tga_op2, op1)); tga_ret = emit_library_call_value (gen_tls_get_addr (), NULL_RTX, LCT_CONST, Pmode, 2, tga_op1, @@ -816,7 +875,7 @@ ia64_expand_tls_address (enum tls_model tls_kind, rtx op0, rtx op1) start_sequence (); tga_op1 = gen_reg_rtx (Pmode); - emit_insn (gen_load_ltoff_dtpmod (tga_op1, op1)); + emit_insn (gen_load_dtpmod (tga_op1, op1)); tga_op1 = gen_const_mem (Pmode, tga_op1); tga_op2 = const0_rtx; @@ -841,14 +900,15 @@ ia64_expand_tls_address (enum tls_model tls_kind, rtx op0, rtx op1) emit_insn (gen_adddi3 (op0, tmp, op0)); } else - emit_insn (gen_add_dtprel (op0, tmp, op1)); + 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_ltoff_tprel (tmp, op1)); - tmp = gen_const_mem (Pmode, tmp); - tmp = force_reg (Pmode, tmp); + emit_insn (gen_load_tprel (tmp, op1)); if (!register_operand (op0, Pmode)) op0 = gen_reg_rtx (Pmode); @@ -858,19 +918,25 @@ ia64_expand_tls_address (enum tls_model tls_kind, rtx op0, rtx op1) 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, gen_thread_pointer (), op0)); + emit_insn (gen_adddi3 (op0, op0, gen_thread_pointer ())); } else - emit_insn (gen_add_tprel (op0, gen_thread_pointer (), op1)); + emit_insn (gen_add_tprel (op0, op1, gen_thread_pointer ())); break; default: gcc_unreachable (); } + 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) @@ -888,15 +954,58 @@ ia64_expand_move (rtx op0, rtx op1) if ((mode == Pmode || mode == ptr_mode) && symbolic_operand (op1, VOIDmode)) { + HOST_WIDE_INT addend = 0; enum tls_model tls_kind; - if (GET_CODE (op1) == SYMBOL_REF - && (tls_kind = SYMBOL_REF_TLS_MODEL (op1))) - return ia64_expand_tls_address (tls_kind, op0, op1); + 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 + op1 = sym; - if (!TARGET_NO_PIC && reload_completed) + if (reload_completed) { - ia64_expand_load_address (op0, op1); - return NULL_RTX; + /* 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; } } diff --git a/gcc/config/ia64/ia64.h b/gcc/config/ia64/ia64.h index 4aca024..bd32069 100644 --- a/gcc/config/ia64/ia64.h +++ b/gcc/config/ia64/ia64.h @@ -454,7 +454,7 @@ while (0) #define CALL_REALLY_USED_REGISTERS \ { /* General registers. */ \ - 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, \ + 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, \ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ @@ -463,7 +463,7 @@ while (0) 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, \ /* Floating-point registers. */ \ - 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ + 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ @@ -472,7 +472,7 @@ while (0) 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ /* Predicate registers. */ \ - 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ + 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ @@ -1410,10 +1410,7 @@ do { \ /* A C expression that is nonzero if X is a legitimate constant for an immediate operand on the target machine. */ -#define LEGITIMATE_CONSTANT_P(X) \ - (GET_CODE (X) != CONST_DOUBLE || GET_MODE (X) == VOIDmode \ - || GET_MODE (X) == DImode || CONST_DOUBLE_OK_FOR_G (X)) \ - +#define LEGITIMATE_CONSTANT_P(X) ia64_legitimate_constant_p (X) /* Condition Code Status */ diff --git a/gcc/config/ia64/ia64.md b/gcc/config/ia64/ia64.md index a1353f4..179a6e7 100644 --- a/gcc/config/ia64/ia64.md +++ b/gcc/config/ia64/ia64.md @@ -56,6 +56,7 @@ (UNSPEC_DTPREL 2) (UNSPEC_LTOFF_TPREL 3) (UNSPEC_TPREL 4) + (UNSPEC_DTPMOD 5) (UNSPEC_LD_BASE 9) (UNSPEC_GR_SPILL 10) @@ -373,53 +374,54 @@ (define_split [(set (match_operand 0 "register_operand" "") (match_operand 1 "symbolic_operand" ""))] - "reload_completed && ! TARGET_NO_PIC" + "reload_completed" [(const_int 0)] { - ia64_expand_load_address (operands[0], operands[1]); - DONE; + if (ia64_expand_load_address (operands[0], operands[1])) + DONE; + else + FAIL; }) (define_expand "load_fptr" - [(set (match_dup 2) - (plus:DI (reg:DI 1) (match_operand 1 "function_operand" ""))) - (set (match_operand:DI 0 "register_operand" "") (match_dup 3))] - "" + [(set (match_operand:DI 0 "register_operand" "") + (plus:DI (match_dup 2) (match_operand 1 "function_operand" ""))) + (set (match_dup 0) (match_dup 3))] + "reload_completed" { - operands[2] = no_new_pseudos ? operands[0] : gen_reg_rtx (DImode); - operands[3] = gen_const_mem (DImode, operands[2]); + operands[2] = pic_offset_table_rtx; + operands[3] = gen_const_mem (DImode, operands[0]); }) (define_insn "*load_fptr_internal1" [(set (match_operand:DI 0 "register_operand" "=r") (plus:DI (reg:DI 1) (match_operand 1 "function_operand" "s")))] - "" + "reload_completed" "addl %0 = @ltoff(@fptr(%1)), gp" [(set_attr "itanium_class" "ialu")]) (define_insn "load_gprel" [(set (match_operand:DI 0 "register_operand" "=r") (plus:DI (reg:DI 1) (match_operand 1 "sdata_symbolic_operand" "s")))] - "" + "reload_completed" "addl %0 = @gprel(%1), gp" [(set_attr "itanium_class" "ialu")]) -(define_insn "gprel64_offset" +(define_insn "*gprel64_offset" [(set (match_operand:DI 0 "register_operand" "=r") (minus:DI (match_operand:DI 1 "symbolic_operand" "") (reg:DI 1)))] - "" + "reload_completed" "movl %0 = @gprel(%1)" [(set_attr "itanium_class" "long_i")]) (define_expand "load_gprel64" - [(set (match_dup 2) - (minus:DI (match_operand:DI 1 "symbolic_operand" "") (match_dup 3))) - (set (match_operand:DI 0 "register_operand" "") - (plus:DI (match_dup 3) (match_dup 2)))] - "" + [(set (match_operand:DI 0 "register_operand" "") + (minus:DI (match_operand:DI 1 "symbolic_operand" "") (match_dup 2))) + (set (match_dup 0) + (plus:DI (match_dup 2) (match_dup 0)))] + "reload_completed" { - operands[2] = no_new_pseudos ? operands[0] : gen_reg_rtx (DImode); - operands[3] = pic_offset_table_rtx; + operands[2] = pic_offset_table_rtx; }) ;; This is used as a placeholder for the return address during early @@ -445,7 +447,7 @@ [(set (match_operand:DI 0 "register_operand" "=r") (plus:DI (high:DI (match_operand 1 "got_symbolic_operand" "s")) (match_operand:DI 2 "register_operand" "a")))] - "" + "reload_completed" { if (HAVE_AS_LTOFFX_LDXMOV_RELOCS) return "%,addl %0 = @ltoffx(%1), %2"; @@ -458,7 +460,7 @@ [(set (match_operand:DI 0 "register_operand" "=r") (lo_sum:DI (match_operand:DI 1 "register_operand" "r") (match_operand 2 "got_symbolic_operand" "s")))] - "" + "reload_completed" { if (HAVE_AS_LTOFFX_LDXMOV_RELOCS) return "%,ld8.mov %0 = [%1], %2"; @@ -467,34 +469,41 @@ } [(set_attr "itanium_class" "ld")]) -(define_insn "load_ltoff_dtpmod" +(define_insn_and_split "load_dtpmod" [(set (match_operand:DI 0 "register_operand" "=r") - (plus:DI (reg:DI 1) - (unspec:DI [(match_operand:DI 1 "symbolic_operand" "")] - UNSPEC_LTOFF_DTPMOD)))] + (unspec:DI [(match_operand:DI 1 "tls_symbolic_operand" "")] + UNSPEC_DTPMOD))] "" - "addl %0 = @ltoff(@dtpmod(%1)), gp" - [(set_attr "itanium_class" "ialu")]) + "#" + "reload_completed" + [(set (match_dup 0) + (plus:DI (unspec:DI [(match_dup 1)] UNSPEC_LTOFF_DTPMOD) + (match_dup 2))) + (set (match_dup 0) (match_dup 3))] +{ + operands[2] = pic_offset_table_rtx; + operands[3] = gen_const_mem (DImode, operands[0]); +}) -(define_insn "load_ltoff_dtprel" +(define_insn "*load_ltoff_dtpmod" [(set (match_operand:DI 0 "register_operand" "=r") - (plus:DI (reg:DI 1) - (unspec:DI [(match_operand:DI 1 "symbolic_operand" "")] - UNSPEC_LTOFF_DTPREL)))] - "" - "addl %0 = @ltoff(@dtprel(%1)), gp" + (plus:DI (unspec:DI [(match_operand:DI 1 "tls_symbolic_operand" "")] + UNSPEC_LTOFF_DTPMOD) + (match_operand:DI 2 "register_operand" "a")))] + "reload_completed" + "addl %0 = @ltoff(@dtpmod(%1)), %2" [(set_attr "itanium_class" "ialu")]) (define_expand "load_dtprel" [(set (match_operand:DI 0 "register_operand" "") - (unspec:DI [(match_operand:DI 1 "symbolic_operand" "")] + (unspec:DI [(match_operand:DI 1 "tls_symbolic_operand" "")] UNSPEC_DTPREL))] "" "") (define_insn "*load_dtprel64" [(set (match_operand:DI 0 "register_operand" "=r") - (unspec:DI [(match_operand:DI 1 "symbolic_operand" "")] + (unspec:DI [(match_operand:DI 1 "ld_tls_symbolic_operand" "")] UNSPEC_DTPREL))] "TARGET_TLS64" "movl %0 = @dtprel(%1)" @@ -502,57 +511,73 @@ (define_insn "*load_dtprel22" [(set (match_operand:DI 0 "register_operand" "=r") - (unspec:DI [(match_operand:DI 1 "symbolic_operand" "")] + (unspec:DI [(match_operand:DI 1 "ld_tls_symbolic_operand" "")] UNSPEC_DTPREL))] "" "addl %0 = @dtprel(%1), r0" [(set_attr "itanium_class" "ialu")]) +(define_insn_and_split "*load_dtprel_gd" + [(set (match_operand:DI 0 "register_operand" "=r") + (unspec:DI [(match_operand:DI 1 "tls_symbolic_operand" "")] + UNSPEC_DTPREL))] + "" + "#" + "reload_completed" + [(set (match_dup 0) + (plus:DI (unspec:DI [(match_dup 1)] UNSPEC_LTOFF_DTPREL) + (match_dup 2))) + (set (match_dup 0) (match_dup 3))] +{ + operands[2] = pic_offset_table_rtx; + operands[3] = gen_const_mem (DImode, operands[0]); +}) + +(define_insn "*load_ltoff_dtprel" + [(set (match_operand:DI 0 "register_operand" "=r") + (plus:DI (unspec:DI [(match_operand:DI 1 "tls_symbolic_operand" "")] + UNSPEC_LTOFF_DTPREL) + (match_operand:DI 2 "register_operand" "a")))] + "" + "addl %0 = @ltoff(@dtprel(%1)), %2" + [(set_attr "itanium_class" "ialu")]) + (define_expand "add_dtprel" [(set (match_operand:DI 0 "register_operand" "") - (plus:DI (match_operand:DI 1 "register_operand" "") - (unspec:DI [(match_operand:DI 2 "symbolic_operand" "")] - UNSPEC_DTPREL)))] + (plus:DI (unspec:DI [(match_operand:DI 1 "ld_tls_symbolic_operand" "")] + UNSPEC_DTPREL) + (match_operand:DI 2 "register_operand" "")))] "!TARGET_TLS64" "") (define_insn "*add_dtprel14" [(set (match_operand:DI 0 "register_operand" "=r") - (plus:DI (match_operand:DI 1 "register_operand" "r") - (unspec:DI [(match_operand:DI 2 "symbolic_operand" "")] - UNSPEC_DTPREL)))] + (plus:DI (unspec:DI [(match_operand:DI 1 "ld_tls_symbolic_operand" "")] + UNSPEC_DTPREL) + (match_operand:DI 2 "register_operand" "r")))] "TARGET_TLS14" - "adds %0 = @dtprel(%2), %1" + "adds %0 = @dtprel(%1), %2" [(set_attr "itanium_class" "ialu")]) (define_insn "*add_dtprel22" [(set (match_operand:DI 0 "register_operand" "=r") - (plus:DI (match_operand:DI 1 "register_operand" "a") - (unspec:DI [(match_operand:DI 2 "symbolic_operand" "")] - UNSPEC_DTPREL)))] + (plus:DI (unspec:DI [(match_operand:DI 1 "ld_tls_symbolic_operand" "")] + UNSPEC_DTPREL) + (match_operand:DI 2 "register_operand" "a")))] "TARGET_TLS22" - "addl %0 = @dtprel(%2), %1" - [(set_attr "itanium_class" "ialu")]) - -(define_insn "load_ltoff_tprel" - [(set (match_operand:DI 0 "register_operand" "=r") - (plus:DI (reg:DI 1) - (unspec:DI [(match_operand:DI 1 "symbolic_operand" "")] - UNSPEC_LTOFF_TPREL)))] - "" - "addl %0 = @ltoff(@tprel(%1)), gp" + "addl %0 = @dtprel(%1), %2" [(set_attr "itanium_class" "ialu")]) (define_expand "load_tprel" [(set (match_operand:DI 0 "register_operand" "") - (unspec:DI [(match_operand:DI 1 "symbolic_operand" "")] + (unspec:DI [(match_operand:DI 1 "tls_symbolic_operand" "")] UNSPEC_TPREL))] "" "") (define_insn "*load_tprel64" [(set (match_operand:DI 0 "register_operand" "=r") - (unspec:DI [(match_operand:DI 1 "symbolic_operand" "")] + (unspec:DI [(match_operand:DI 1 "le_tls_symbolic_operand" "")] UNSPEC_TPREL))] "TARGET_TLS64" "movl %0 = @tprel(%1)" @@ -560,36 +585,61 @@ (define_insn "*load_tprel22" [(set (match_operand:DI 0 "register_operand" "=r") - (unspec:DI [(match_operand:DI 1 "symbolic_operand" "")] + (unspec:DI [(match_operand:DI 1 "le_tls_symbolic_operand" "")] UNSPEC_TPREL))] "" "addl %0 = @tprel(%1), r0" [(set_attr "itanium_class" "ialu")]) +(define_insn_and_split "*load_tprel_ie" + [(set (match_operand:DI 0 "register_operand" "=r") + (unspec:DI [(match_operand:DI 1 "ie_tls_symbolic_operand" "")] + UNSPEC_TPREL))] + "" + "#" + "reload_completed" + [(set (match_dup 0) + (plus:DI (unspec:DI [(match_dup 1)] UNSPEC_LTOFF_TPREL) + (match_dup 2))) + (set (match_dup 0) (match_dup 3))] +{ + operands[2] = pic_offset_table_rtx; + operands[3] = gen_const_mem (DImode, operands[0]); +}) + +(define_insn "*load_ltoff_tprel" + [(set (match_operand:DI 0 "register_operand" "=r") + (plus:DI (unspec:DI [(match_operand:DI 1 "ie_tls_symbolic_operand" "")] + UNSPEC_LTOFF_TPREL) + (match_operand:DI 2 "register_operand" "a")))] + "" + "addl %0 = @ltoff(@tprel(%1)), %2" + [(set_attr "itanium_class" "ialu")]) + (define_expand "add_tprel" [(set (match_operand:DI 0 "register_operand" "") - (plus:DI (match_operand:DI 1 "register_operand" "") - (unspec:DI [(match_operand:DI 2 "symbolic_operand" "")] - UNSPEC_TPREL)))] + (plus:DI (unspec:DI [(match_operand:DI 1 "le_tls_symbolic_operand" "")] + UNSPEC_TPREL) + (match_operand:DI 2 "register_operand" "")))] "!TARGET_TLS64" "") (define_insn "*add_tprel14" [(set (match_operand:DI 0 "register_operand" "=r") - (plus:DI (match_operand:DI 1 "register_operand" "r") - (unspec:DI [(match_operand:DI 2 "symbolic_operand" "")] - UNSPEC_TPREL)))] + (plus:DI (unspec:DI [(match_operand:DI 1 "le_tls_symbolic_operand" "")] + UNSPEC_TPREL) + (match_operand:DI 2 "register_operand" "r")))] "TARGET_TLS14" - "adds %0 = @tprel(%2), %1" + "adds %0 = @tprel(%1), %2" [(set_attr "itanium_class" "ialu")]) (define_insn "*add_tprel22" [(set (match_operand:DI 0 "register_operand" "=r") - (plus:DI (match_operand:DI 1 "register_operand" "a") - (unspec:DI [(match_operand:DI 2 "symbolic_operand" "")] - UNSPEC_TPREL)))] + (plus:DI (unspec:DI [(match_operand:DI 1 "le_tls_symbolic_operand" "")] + UNSPEC_TPREL) + (match_operand:DI 2 "register_operand" "a")))] "TARGET_TLS22" - "addl %0 = @tprel(%2), %1" + "addl %0 = @tprel(%1), %2" [(set_attr "itanium_class" "ialu")]) ;; With no offsettable memory references, we've got to have a scratch diff --git a/gcc/config/ia64/predicates.md b/gcc/config/ia64/predicates.md index 554dc79..7ec3209 100644 --- a/gcc/config/ia64/predicates.md +++ b/gcc/config/ia64/predicates.md @@ -34,42 +34,6 @@ (and (match_code "symbol_ref") (match_test "SYMBOL_REF_FUNCTION_P (op)"))) -;; True if OP refers to a symbol, and is appropriate for a GOT load. -(define_predicate "got_symbolic_operand" - (match_operand 0 "symbolic_operand" "") -{ - switch (GET_CODE (op)) - { - case LABEL_REF: - return true; - - case SYMBOL_REF: - /* This sort of load should not be used for things in sdata. */ - return !SYMBOL_REF_SMALL_ADDR_P (op); - - case CONST: - /* Accept only (plus (symbol_ref) (const_int)). */ - op = XEXP (op, 0); - if (GET_CODE (op) != PLUS - || GET_CODE (XEXP (op, 0)) != SYMBOL_REF - || GET_CODE (XEXP (op, 1)) != CONST_INT) - return false; - - /* Ok if we're not using GOT entries at all. */ - if (TARGET_NO_PIC || TARGET_AUTO_PIC) - return true; - - /* The low 14 bits of the constant have been forced to zero - by ia64_expand_load_address, so that we do not use up so - many GOT entries. Prevent cse from undoing this. */ - op = XEXP (op, 1); - return (INTVAL (op) & 0x3fff) == 0; - - default: - gcc_unreachable (); - } -}) - ;; True if OP refers to a symbol in the sdata section. (define_predicate "sdata_symbolic_operand" (match_code "symbol_ref,const") @@ -129,6 +93,187 @@ } }) +;; True if OP refers to a symbol in the small address area. +(define_predicate "small_addr_symbolic_operand" + (match_code "symbol_ref,const") +{ + switch (GET_CODE (op)) + { + case CONST: + op = XEXP (op, 0); + if (GET_CODE (op) != PLUS + || GET_CODE (XEXP (op, 0)) != SYMBOL_REF + || GET_CODE (XEXP (op, 1)) != CONST_INT) + return false; + op = XEXP (op, 0); + /* FALLTHRU */ + + case SYMBOL_REF: + return SYMBOL_REF_SMALL_ADDR_P (op); + + default: + gcc_unreachable (); + } +}) + +;; True if OP refers to a symbol with which we may use any offset. +(define_predicate "any_offset_symbol_operand" + (match_code "symbol_ref") +{ + if (TARGET_NO_PIC || TARGET_AUTO_PIC) + return true; + if (SYMBOL_REF_SMALL_ADDR_P (op)) + return true; + if (SYMBOL_REF_FUNCTION_P (op)) + return false; + if (sdata_symbolic_operand (op, mode)) + return true; + return false; +}) + +;; True if OP refers to a symbol with which we may use 14-bit aligned offsets. +;; False if OP refers to a symbol with which we may not use any offset at any +;; time. +(define_predicate "aligned_offset_symbol_operand" + (and (match_code "symbol_ref") + (match_test "! SYMBOL_REF_FUNCTION_P (op)"))) + +;; True if OP refers to a symbol, and is appropriate for a GOT load. +(define_predicate "got_symbolic_operand" + (match_operand 0 "symbolic_operand" "") +{ + HOST_WIDE_INT addend = 0; + + switch (GET_CODE (op)) + { + case LABEL_REF: + return true; + + case CONST: + /* Accept only (plus (symbol_ref) (const_int)). */ + op = XEXP (op, 0); + if (GET_CODE (op) != PLUS + || GET_CODE (XEXP (op, 0)) != SYMBOL_REF + || GET_CODE (XEXP (op, 1)) != CONST_INT) + return false; + + addend = INTVAL (XEXP (op, 1)); + op = XEXP (op, 0); + /* FALLTHRU */ + + case SYMBOL_REF: + /* These symbols shouldn't be used with got loads. */ + if (SYMBOL_REF_SMALL_ADDR_P (op)) + return false; + if (SYMBOL_REF_TLS_MODEL (op) != 0) + return false; + + if (any_offset_symbol_operand (op, mode)) + return true; + + /* The low 14 bits of the constant have been forced to zero + so that we do not use up so many GOT entries. Prevent cse + from undoing this. */ + if (aligned_offset_symbol_operand (op, mode)) + return (addend & 0x3fff) == 0; + + return addend == 0; + + default: + gcc_unreachable (); + } +}) + +;; Return true if OP is a valid thread local storage symbolic operand. +(define_predicate "tls_symbolic_operand" + (match_code "symbol_ref,const") +{ + switch (GET_CODE (op)) + { + case SYMBOL_REF: + return SYMBOL_REF_TLS_MODEL (op) != 0; + + case CONST: + op = XEXP (op, 0); + if (GET_CODE (op) != PLUS + || GET_CODE (XEXP (op, 0)) != SYMBOL_REF + || GET_CODE (XEXP (op, 1)) != CONST_INT) + return false; + + /* We only allow certain offsets for certain tls models. */ + switch (SYMBOL_REF_TLS_MODEL (XEXP (op, 0))) + { + case TLS_MODEL_GLOBAL_DYNAMIC: + case TLS_MODEL_LOCAL_DYNAMIC: + return false; + + case TLS_MODEL_INITIAL_EXEC: + return (INTVAL (XEXP (op, 1)) & 0x3fff) == 0; + + case TLS_MODEL_LOCAL_EXEC: + return true; + + default: + return false; + } + + default: + gcc_unreachable (); + } +}) + +;; Return true if OP is a local-dynamic thread local storage symbolic operand. +(define_predicate "ld_tls_symbolic_operand" + (and (match_code "symbol_ref") + (match_test "SYMBOL_REF_TLS_MODEL (op) == TLS_MODEL_LOCAL_DYNAMIC"))) + +;; Return true if OP is an initial-exec thread local storage symbolic operand. +(define_predicate "ie_tls_symbolic_operand" + (match_code "symbol_ref,const") +{ + switch (GET_CODE (op)) + { + case CONST: + op = XEXP (op, 0); + if (GET_CODE (op) != PLUS + || GET_CODE (XEXP (op, 0)) != SYMBOL_REF + || GET_CODE (XEXP (op, 1)) != CONST_INT + || (INTVAL (XEXP (op, 1)) & 0x3fff) != 0) + return false; + op = XEXP (op, 0); + /* FALLTHRU */ + + case SYMBOL_REF: + return SYMBOL_REF_TLS_MODEL (op) == TLS_MODEL_INITIAL_EXEC; + + default: + gcc_unreachable (); + } +}) + +;; Return true if OP is a local-exec thread local storage symbolic operand. +(define_predicate "le_tls_symbolic_operand" + (match_code "symbol_ref,const") +{ + switch (GET_CODE (op)) + { + case CONST: + op = XEXP (op, 0); + if (GET_CODE (op) != PLUS + || GET_CODE (XEXP (op, 0)) != SYMBOL_REF + || GET_CODE (XEXP (op, 1)) != CONST_INT) + return false; + op = XEXP (op, 0); + /* FALLTHRU */ + + case SYMBOL_REF: + return SYMBOL_REF_TLS_MODEL (op) == TLS_MODEL_LOCAL_EXEC; + + default: + gcc_unreachable (); + } +}) + ;; Like nonimmediate_operand, but don't allow MEMs that try to use a ;; POST_MODIFY with a REG as displacement. (define_predicate "destination_operand" @@ -142,11 +287,51 @@ (and (match_operand 0 "memory_operand") (match_test "GET_RTX_CLASS (GET_CODE (XEXP (op, 0))) != RTX_AUTOINC"))) -;; True if OP is a general operand, excluding tls symbolic operands. +;; True if OP is a general operand, with some restrictions on symbols. (define_predicate "move_operand" - (and (match_operand 0 "general_operand") - (not (match_test - "GET_CODE (op) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (op)")))) + (match_operand 0 "general_operand") +{ + switch (GET_CODE (op)) + { + case CONST: + { + HOST_WIDE_INT addend; + + /* Accept only (plus (symbol_ref) (const_int)). */ + op = XEXP (op, 0); + if (GET_CODE (op) != PLUS + || GET_CODE (XEXP (op, 0)) != SYMBOL_REF + || GET_CODE (XEXP (op, 1)) != CONST_INT) + return false; + + addend = INTVAL (XEXP (op, 1)); + op = XEXP (op, 0); + + /* After reload, we want to allow any offset whatsoever. This + allows reload the opportunity to avoid spilling addresses to + the stack, and instead simply substitute in the value from a + REG_EQUIV. We'll split this up again when splitting the insn. */ + if (reload_in_progress || reload_completed) + return true; + + /* Some symbol types we allow to use with any offset. */ + if (any_offset_symbol_operand (op, mode)) + return true; + + /* Some symbol types we allow offsets with the low 14 bits of the + constant forced to zero so that we do not use up so many GOT + entries. We want to prevent cse from undoing this. */ + if (aligned_offset_symbol_operand (op, mode)) + return (addend & 0x3fff) == 0; + + /* The remaining symbol types may never be used with an offset. */ + return false; + } + + default: + return true; + } +}) ;; True if OP is a register operand that is (or could be) a GR reg. (define_predicate "gr_register_operand" -- 2.7.4