diff options
| author | rth <rth@138bc75d-0d04-0410-961f-82ee72b054a4> | 2005-05-11 21:34:19 +0000 | 
|---|---|---|
| committer | rth <rth@138bc75d-0d04-0410-961f-82ee72b054a4> | 2005-05-11 21:34:19 +0000 | 
| commit | 3ec3c84f411b699d86c249cdb9998c5b6e2345a6 (patch) | |
| tree | 57a3390e516ee7f28564f666930c45556bb6ba42 /gcc | |
| parent | 162a101bb5a3c63473aadb8c7d4ffc6c537b6eac (diff) | |
| download | ppe42-gcc-3ec3c84f411b699d86c249cdb9998c5b6e2345a6.tar.gz ppe42-gcc-3ec3c84f411b699d86c249cdb9998c5b6e2345a6.zip  | |
        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.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@99596 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc')
| -rw-r--r-- | gcc/ChangeLog | 38 | ||||
| -rw-r--r-- | gcc/config/ia64/ia64-protos.h | 3 | ||||
| -rw-r--r-- | gcc/config/ia64/ia64.c | 229 | ||||
| -rw-r--r-- | gcc/config/ia64/ia64.h | 11 | ||||
| -rw-r--r-- | gcc/config/ia64/ia64.md | 192 | ||||
| -rw-r--r-- | gcc/config/ia64/predicates.md | 265 | 
6 files changed, 559 insertions, 179 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index afbf5af7c1e..f92014e8077 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,41 @@ +2005-05-11  Richard Henderson  <rth@redhat.com> + +	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  <rsandifo@redhat.com>  	* 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 1eb45883860..94fa176f7e7 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 d75a74f0f1e..a4d12c92cc3 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 4aca02471da..bd32069b171 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 a1353f4e70a..179a6e74004 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 554dc79c95f..7ec32090b5d 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"  | 

