This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
ia64 tls support
- From: Richard Henderson <rth at redhat dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Sat, 25 May 2002 12:51:58 -0700
- Subject: ia64 tls support
* configure.in (HAVE_AS_TLS): Add ia64 test.
* configure: Rebuild.
* config/ia64/ia64.c (ia64_tls_size_string, ia64_tls_size): New.
(override_options): Set it.
(TARGET_HAVE_TLS): New.
(sdata_symbolic_operand): Look for 's'.
(tls_symbolic_operand): New.
(ia64_expand_load_address): Abort for tls symbols.
(gen_tls_get_addr): New.
(gen_thread_pointer): New.
(ia64_expand_move): Split out from movdi. Handle tls symbols.
(rtx_needs_barrier): Add new unspecs.
(ia64_encode_section_info): Handle tls symbols.
(ia64_strip_name_encoding): Strip two encoding chars.
* config/ia64/ia64.h (ia64_tls_size, ia64_tls_size_string): New.
(TARGET_TLS14, TARGET_TLS22, TARGET_TLS64): New.
(TARGET_OPTIONS): Add tls-size.
(ENCODE_SECTION_INFO_CHAR): Rename from SDATA_NAME_FLAG_CHAR.
* config/ia64/ia64.md (UNSPEC_LTOFF_DTPMOD, UNSPEC_LTOFF_DTPREL,
UNSPEC_DTPREL, UNSPEC_LTOFF_TPREL, UNSPEC_TPREL, UNSPEC_LD_BASE): New.
(movqi, movhi, movsi, movdi, movti): Use ia64_expand_move.
(movsf, movdf): Likewise.
(movdi_symbolic): Use match_scratch. Don't split if we won't
have a scratch availiable.
(load_ltoff_dtpmod, load_dtprel, load_dtprel64, load_dtprel22,
add_dtprel, add_dtprel14, add_dtprel22, load_ltoff_tprel, load_tprel,
load_tprel64, load_tprel22, add_tprel, add_tprel14, add_tprel22): New.
* config/ia64/ia64-protos.h: Update.
* config/ia64/sysv4.h (ASM_OUTPUT_ALIGNED_DECL_LOCAL): Use
sdata_symbolic_operand.
(ASM_OUTPUT_LABELREF): Strip two characters.
Index: gcc/configure.in
===================================================================
RCS file: /cvs/gcc/gcc/gcc/configure.in,v
retrieving revision 1.592
diff -c -p -d -u -r1.592 configure.in
--- gcc/configure.in 23 May 2002 21:55:23 -0000 1.592
+++ gcc/configure.in 25 May 2002 02:06:36 -0000
@@ -1743,6 +1743,23 @@ foo: .long 25
tls_first_major=2
tls_first_minor=13
;;
+ ia64-*-*)
+ conftest_s='
+ .section ".tdata","awT",@progbits
+foo: data8 25
+ .text
+ addl r16 = @ltoff(@dtpmod(foo#)), gp
+ addl r17 = @ltoff(@dtprel(foo#)), gp
+ addl r18 = @ltoff(@tprel(foo#)), gp
+ addl r19 = @dtprel(foo#), gp
+ adds r21 = @dtprel(foo#), r13
+ movl r23 = @dtprel(foo#)
+ addl r20 = @tprel(foo#), gp
+ adds r22 = @tprel(foo#), r13
+ movl r24 = @tprel(foo#)'
+ tls_first_major=2
+ tls_first_minor=13
+ ;;
esac
if test -z "$tls_first_major"; then
:
Index: gcc/config/ia64/ia64-protos.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/ia64/ia64-protos.h,v
retrieving revision 1.41
diff -c -p -d -u -r1.41 ia64-protos.h
--- gcc/config/ia64/ia64-protos.h 19 May 2002 05:23:11 -0000 1.41
+++ gcc/config/ia64/ia64-protos.h 25 May 2002 02:06:36 -0000
@@ -31,6 +31,7 @@ extern int call_operand PARAMS((rtx, enu
extern int sdata_symbolic_operand PARAMS((rtx, enum machine_mode));
extern int got_symbolic_operand PARAMS((rtx, enum machine_mode));
extern int symbolic_operand PARAMS((rtx, enum machine_mode));
+extern int tls_symbolic_operand PARAMS((rtx, enum machine_mode));
extern int function_operand PARAMS((rtx, enum machine_mode));
extern int setjmp_operand PARAMS((rtx, enum machine_mode));
extern int move_operand PARAMS((rtx, enum machine_mode));
@@ -68,6 +69,7 @@ extern int destination_tfmode_operand PA
extern int tfreg_or_fp01_operand PARAMS((rtx, enum machine_mode));
extern int basereg_operand PARAMS((rtx, enum machine_mode));
+extern rtx ia64_expand_move PARAMS ((rtx, rtx));
extern int ia64_move_ok PARAMS((rtx, rtx));
extern int ia64_depz_field_mask PARAMS((rtx, rtx));
extern rtx ia64_gp_save_reg PARAMS((int));
Index: gcc/config/ia64/ia64.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/ia64/ia64.c,v
retrieving revision 1.171
diff -c -p -d -u -r1.171 ia64.c
--- gcc/config/ia64/ia64.c 24 May 2002 22:54:28 -0000 1.171
+++ gcc/config/ia64/ia64.c 25 May 2002 02:06:36 -0000
@@ -94,6 +94,13 @@ static const char * const ia64_output_re
/* String used with the -mfixed-range= option. */
const char *ia64_fixed_range_string;
+/* Determines whether we use adds, addl, or movl to generate our
+ TLS immediate offsets. */
+int ia64_tls_size = 22;
+
+/* String used with the -mtls-size= option. */
+const char *ia64_tls_size_string;
+
/* Determines whether we run our final scheduling pass or not. We always
avoid the normal second scheduling pass. */
static int ia64_flag_schedule_insns2;
@@ -103,6 +110,8 @@ static int ia64_flag_schedule_insns2;
unsigned int ia64_section_threshold;
+static rtx gen_tls_get_addr PARAMS ((void));
+static rtx gen_thread_pointer PARAMS ((void));
static int find_gr_spill PARAMS ((int));
static int next_scratch_gr_reg PARAMS ((void));
static void mark_reg_gr_used_mask PARAMS ((rtx, void *));
@@ -230,6 +239,11 @@ static const struct attribute_spec ia64_
#undef TARGET_SCHED_REORDER2
#define TARGET_SCHED_REORDER2 ia64_sched_reorder2
+#ifdef HAVE_AS_TLS
+#undef TARGET_HAVE_TLS
+#define TARGET_HAVE_TLS true
+#endif
+
struct gcc_target targetm = TARGET_INITIALIZER;
/* Return 1 if OP is a valid operand for the MEM of a CALL insn. */
@@ -266,7 +280,10 @@ sdata_symbolic_operand (op, mode)
if (CONSTANT_POOL_ADDRESS_P (op))
return GET_MODE_SIZE (get_pool_mode (op)) <= ia64_section_threshold;
else
- return XSTR (op, 0)[0] == SDATA_NAME_FLAG_CHAR;
+ {
+ const char *str = XSTR (op, 0);
+ return (str[0] == ENCODE_SECTION_INFO_CHAR && str[1] == 's');
+ }
default:
break;
@@ -340,6 +357,35 @@ symbolic_operand (op, mode)
return 0;
}
+/* Return tls_model if OP refers to a TLS symbol. */
+
+int
+tls_symbolic_operand (op, mode)
+ rtx op;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+ const char *str;
+
+ if (GET_CODE (op) != SYMBOL_REF)
+ return 0;
+ str = XSTR (op, 0);
+ if (str[0] != ENCODE_SECTION_INFO_CHAR)
+ return 0;
+ switch (str[1])
+ {
+ case 'G':
+ return TLS_MODEL_GLOBAL_DYNAMIC;
+ case 'L':
+ return TLS_MODEL_LOCAL_DYNAMIC;
+ case 'i':
+ return TLS_MODEL_INITIAL_EXEC;
+ case 'l':
+ return TLS_MODEL_LOCAL_EXEC;
+ }
+ return 0;
+}
+
+
/* Return 1 if OP refers to a function. */
int
@@ -953,6 +999,9 @@ ia64_expand_load_address (dest, src, scr
else
temp = dest;
+ if (tls_symbolic_operand (src, Pmode))
+ abort ();
+
if (TARGET_AUTO_PIC)
emit_insn (gen_load_gprel64 (temp, src));
else if (GET_CODE (src) == SYMBOL_REF && SYMBOL_REF_FLAG (src))
@@ -995,6 +1044,185 @@ ia64_expand_load_address (dest, src, scr
emit_move_insn (dest, temp);
}
+static rtx
+gen_tls_get_addr ()
+{
+ static rtx tga;
+ if (!tga)
+ {
+ tga = init_one_libfunc ("__tls_get_addr");
+ ggc_add_rtx_root (&tga, 1);
+ }
+ return tga;
+}
+
+static rtx
+gen_thread_pointer ()
+{
+ static rtx tp;
+ if (!tp)
+ {
+ tp = gen_rtx_REG (Pmode, 13);
+ RTX_UNCHANGING_P (tp);
+ ggc_add_rtx_root (&tp, 1);
+ }
+ return tp;
+}
+
+rtx
+ia64_expand_move (op0, op1)
+ rtx op0, 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)
+ {
+ enum tls_model tls_kind;
+ if ((tls_kind = tls_symbolic_operand (op1, Pmode)))
+ {
+ rtx tga_op1, tga_op2, tga_ret, tga_eqv, tmp, insns;
+
+ switch (tls_kind)
+ {
+ case TLS_MODEL_GLOBAL_DYNAMIC:
+ start_sequence ();
+
+ tga_op1 = gen_reg_rtx (Pmode);
+ emit_insn (gen_load_ltoff_dtpmod (tga_op1, op1));
+ tga_op1 = gen_rtx_MEM (Pmode, tga_op1);
+ RTX_UNCHANGING_P (tga_op1) = 1;
+
+ tga_op2 = gen_reg_rtx (Pmode);
+ emit_insn (gen_load_ltoff_dtprel (tga_op2, op1));
+ tga_op2 = gen_rtx_MEM (Pmode, tga_op2);
+ RTX_UNCHANGING_P (tga_op2) = 1;
+
+ 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 ();
+
+ emit_libcall_block (insns, op0, tga_ret, op1);
+ return NULL_RTX;
+
+ 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_ltoff_dtpmod (tga_op1, op1));
+ tga_op1 = gen_rtx_MEM (Pmode, tga_op1);
+ RTX_UNCHANGING_P (tga_op1) = 1;
+
+ 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))
+ tga_ret = op0;
+ else
+ tga_ret = gen_reg_rtx (Pmode);
+ if (TARGET_TLS64)
+ {
+ emit_insn (gen_load_dtprel (tga_ret, op1));
+ emit_insn (gen_adddi3 (tga_ret, tmp, tga_ret));
+ }
+ else
+ emit_insn (gen_add_dtprel (tga_ret, tmp, op1));
+ if (tga_ret == op0)
+ return NULL_RTX;
+ op1 = tga_ret;
+ break;
+
+ case TLS_MODEL_INITIAL_EXEC:
+ tmp = gen_reg_rtx (Pmode);
+ emit_insn (gen_load_ltoff_tprel (tmp, op1));
+ tmp = gen_rtx_MEM (Pmode, tmp);
+ RTX_UNCHANGING_P (tmp) = 1;
+ tmp = force_reg (Pmode, tmp);
+
+ if (register_operand (op0, Pmode))
+ op1 = op0;
+ else
+ op1 = gen_reg_rtx (Pmode);
+ emit_insn (gen_adddi3 (op1, tmp, gen_thread_pointer ()));
+ if (op1 == op0)
+ return NULL_RTX;
+ break;
+
+ case TLS_MODEL_LOCAL_EXEC:
+ if (register_operand (op0, Pmode))
+ tmp = op0;
+ else
+ tmp = gen_reg_rtx (Pmode);
+ if (TARGET_TLS64)
+ {
+ emit_insn (gen_load_tprel (tmp, op1));
+ emit_insn (gen_adddi3 (tmp, gen_thread_pointer (), tmp));
+ }
+ else
+ emit_insn (gen_add_tprel (tmp, gen_thread_pointer (), op1));
+ if (tmp == op0)
+ return NULL_RTX;
+ op1 = tmp;
+ break;
+
+ default:
+ abort ();
+ }
+ }
+ else if (!TARGET_NO_PIC && symbolic_operand (op1, DImode))
+ {
+ /* Before optimization starts, delay committing to any particular
+ type of PIC address load. If this function gets deferred, we
+ may acquire information that changes the value of the
+ sdata_symbolic_operand predicate.
+
+ But don't delay for function pointers. Loading a function address
+ actually loads the address of the descriptor not the function.
+ If we represent these as SYMBOL_REFs, then they get cse'd with
+ calls, and we end up with calls to the descriptor address instead
+ of calls to the function address. Functions are not candidates
+ for sdata anyways.
+
+ Don't delay for LABEL_REF because the splitter loses REG_LABEL
+ notes. Don't delay for pool addresses on general principals;
+ they'll never become non-local behind our back. */
+
+ if (rtx_equal_function_value_matters
+ && GET_CODE (op1) != LABEL_REF
+ && ! (GET_CODE (op1) == SYMBOL_REF
+ && (SYMBOL_REF_FLAG (op1)
+ || CONSTANT_POOL_ADDRESS_P (op1)
+ || STRING_POOL_ADDRESS_P (op1))))
+ emit_insn (gen_movdi_symbolic (op0, op1));
+ else
+ ia64_expand_load_address (op0, op1, NULL_RTX);
+ return NULL_RTX;
+ }
+ }
+
+ return op1;
+}
+
rtx
ia64_gp_save_reg (setjmp_p)
int setjmp_p;
@@ -3975,6 +4203,16 @@ ia64_override_options ()
if (ia64_fixed_range_string)
fix_range (ia64_fixed_range_string);
+ if (ia64_tls_size_string)
+ {
+ char *end;
+ unsigned long tmp = strtoul (ia64_tls_size_string, &end, 10);
+ if (*end || (tmp != 14 && tmp != 22 && tmp != 64))
+ error ("bad value (%s) for -mtls-size= switch", ia64_tls_size_string);
+ else
+ ia64_tls_size = tmp;
+ }
+
ia64_flag_schedule_insns2 = flag_schedule_insns_after_reload;
flag_schedule_insns_after_reload = 0;
@@ -4595,6 +4833,20 @@ rtx_needs_barrier (x, flags, pred)
case UNSPEC:
switch (XINT (x, 1))
{
+ case UNSPEC_LTOFF_DTPMOD:
+ case UNSPEC_LTOFF_DTPREL:
+ case UNSPEC_DTPREL:
+ case UNSPEC_LTOFF_TPREL:
+ case UNSPEC_TPREL:
+ case UNSPEC_PRED_REL_MUTEX:
+ case UNSPEC_PIC_CALL:
+ case UNSPEC_MF:
+ case UNSPEC_FETCHADD_ACQ:
+ case UNSPEC_BSP_VALUE:
+ case UNSPEC_FLUSHRS:
+ case UNSPEC_BUNDLE_SELECTOR:
+ break;
+
case UNSPEC_GR_SPILL:
case UNSPEC_GR_RESTORE:
{
@@ -4614,15 +4866,6 @@ rtx_needs_barrier (x, flags, pred)
need_barrier = rtx_needs_barrier (XVECEXP (x, 0, 0), flags, pred);
break;
- case UNSPEC_PRED_REL_MUTEX:
- case UNSPEC_PIC_CALL:
- case UNSPEC_MF:
- case UNSPEC_FETCHADD_ACQ:
- case UNSPEC_BSP_VALUE:
- case UNSPEC_FLUSHRS:
- case UNSPEC_BUNDLE_SELECTOR:
- break;
-
case UNSPEC_ADDP4:
need_barrier = rtx_needs_barrier (XVECEXP (x, 0, 0), flags, pred);
break;
@@ -6910,8 +7153,9 @@ ia64_encode_section_info (decl, first)
int first ATTRIBUTE_UNUSED;
{
const char *symbol_str;
- bool is_local, is_small;
+ bool is_local;
rtx symbol;
+ char encoding = 0;
if (TREE_CODE (decl) == FUNCTION_DECL)
{
@@ -6930,40 +7174,66 @@ ia64_encode_section_info (decl, first)
is_local = (*targetm.binds_local_p) (decl);
+ if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL (decl))
+ {
+ enum tls_model kind;
+ if (!flag_pic)
+ {
+ if (is_local)
+ kind = TLS_MODEL_LOCAL_EXEC;
+ else
+ kind = TLS_MODEL_INITIAL_EXEC;
+ }
+ else if (is_local)
+ kind = TLS_MODEL_LOCAL_DYNAMIC;
+ else
+ kind = TLS_MODEL_GLOBAL_DYNAMIC;
+ if (kind < flag_tls_default)
+ kind = flag_tls_default;
+
+ encoding = " GLil"[kind];
+ }
/* Determine if DECL will wind up in .sdata/.sbss. */
- is_small = ia64_in_small_data_p (decl);
+ else if (is_local && ia64_in_small_data_p (decl))
+ encoding = 's';
/* Finally, encode this into the symbol string. */
- if (is_local && is_small)
+ if (encoding)
{
char *newstr;
size_t len;
- if (symbol_str[0] == SDATA_NAME_FLAG_CHAR)
- return;
+ if (symbol_str[0] == ENCODE_SECTION_INFO_CHAR)
+ {
+ if (encoding == symbol_str[1])
+ return;
+ /* ??? Sdata became thread or thread becaome not thread. Lose. */
+ abort ();
+ }
- len = strlen (symbol_str) + 1;
- newstr = alloca (len + 1);
- newstr[0] = SDATA_NAME_FLAG_CHAR;
- memcpy (newstr + 1, symbol_str, len);
+ len = strlen (symbol_str);
+ newstr = alloca (len + 3);
+ newstr[0] = ENCODE_SECTION_INFO_CHAR;
+ newstr[1] = encoding;
+ memcpy (newstr + 2, symbol_str, len + 1);
- XSTR (symbol, 0) = ggc_alloc_string (newstr, len);
+ XSTR (symbol, 0) = ggc_alloc_string (newstr, len + 2);
}
- /* This decl is marked as being in small data/bss but it shouldn't
- be; one likely explanation for this is that the decl has been
- moved into a different section from the one it was in when
- targetm.encode_section_info was first called. Remove the '@'. */
- else if (symbol_str[0] == SDATA_NAME_FLAG_CHAR)
- XSTR (symbol, 0) = ggc_strdup (symbol_str + 1);
+ /* This decl is marked as being in small data/bss but it shouldn't be;
+ one likely explanation for this is that the decl has been moved into
+ a different section from the one it was in when encode_section_info
+ was first called. Remove the encoding. */
+ else if (symbol_str[0] == ENCODE_SECTION_INFO_CHAR)
+ XSTR (symbol, 0) = ggc_strdup (symbol_str + 2);
}
static const char *
ia64_strip_name_encoding (str)
const char *str;
{
- if (str[0] == SDATA_NAME_FLAG_CHAR)
- str++;
+ if (str[0] == ENCODE_SECTION_INFO_CHAR)
+ str += 2;
if (str[0] == '*')
str++;
return str;
Index: gcc/config/ia64/ia64.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/ia64/ia64.h,v
retrieving revision 1.116
diff -c -p -d -u -r1.116 ia64.h
--- gcc/config/ia64/ia64.h 19 May 2002 07:55:35 -0000 1.116
+++ gcc/config/ia64/ia64.h 25 May 2002 02:06:36 -0000
@@ -109,6 +109,11 @@ extern int target_flags;
#define TARGET_DWARF2_ASM (target_flags & MASK_DWARF2_ASM)
+extern int ia64_tls_size;
+#define TARGET_TLS14 (ia64_tls_size == 14)
+#define TARGET_TLS22 (ia64_tls_size == 22)
+#define TARGET_TLS64 (ia64_tls_size == 64)
+
/* This macro defines names of command options to set and clear bits in
`target_flags'. Its definition is an initializer with a subgrouping for
each command option. */
@@ -177,10 +182,13 @@ extern int target_flags;
subgrouping for each command option. */
extern const char *ia64_fixed_range_string;
+extern const char *ia64_tls_size_string;
#define TARGET_OPTIONS \
{ \
{ "fixed-range=", &ia64_fixed_range_string, \
N_("Specify range of registers to make fixed")}, \
+ { "tls-size=", &ia64_tls_size_string, \
+ N_("Specify bit size of immediate TLS offsets")}, \
}
/* Sometimes certain combinations of command options do not make sense on a
@@ -1774,7 +1782,7 @@ do { \
#define BSS_SECTION_ASM_OP "\t.bss"
-#define SDATA_NAME_FLAG_CHAR '@'
+#define ENCODE_SECTION_INFO_CHAR '@'
#define IA64_DEFAULT_GVALUE 8
Index: gcc/config/ia64/ia64.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/ia64/ia64.md,v
retrieving revision 1.86
diff -c -p -d -u -r1.86 ia64.md
--- gcc/config/ia64/ia64.md 17 May 2002 07:51:56 -0000 1.86
+++ gcc/config/ia64/ia64.md 25 May 2002 02:06:36 -0000
@@ -49,20 +49,28 @@
;; ??? Need a better way to describe alternate fp status registers.
(define_constants
- [(UNSPEC_GR_SPILL 1)
- (UNSPEC_GR_RESTORE 2)
- (UNSPEC_FR_SPILL 3)
- (UNSPEC_FR_RESTORE 4)
- (UNSPEC_FR_RECIP_APPROX 5)
- (UNSPEC_PRED_REL_MUTEX 7)
- (UNSPEC_POPCNT 8)
- (UNSPEC_PIC_CALL 9)
- (UNSPEC_MF 12)
- (UNSPEC_CMPXCHG_ACQ 13)
- (UNSPEC_FETCHADD_ACQ 19)
- (UNSPEC_BSP_VALUE 20)
- (UNSPEC_FLUSHRS 21)
- (UNSPEC_BUNDLE_SELECTOR 22)
+ [; Relocations
+ (UNSPEC_LTOFF_DTPMOD 0)
+ (UNSPEC_LTOFF_DTPREL 1)
+ (UNSPEC_DTPREL 2)
+ (UNSPEC_LTOFF_TPREL 3)
+ (UNSPEC_TPREL 4)
+
+ (UNSPEC_LD_BASE 9)
+ (UNSPEC_GR_SPILL 10)
+ (UNSPEC_GR_RESTORE 11)
+ (UNSPEC_FR_SPILL 12)
+ (UNSPEC_FR_RESTORE 13)
+ (UNSPEC_FR_RECIP_APPROX 14)
+ (UNSPEC_PRED_REL_MUTEX 15)
+ (UNSPEC_POPCNT 16)
+ (UNSPEC_PIC_CALL 17)
+ (UNSPEC_MF 18)
+ (UNSPEC_CMPXCHG_ACQ 19)
+ (UNSPEC_FETCHADD_ACQ 20)
+ (UNSPEC_BSP_VALUE 21)
+ (UNSPEC_FLUSHRS 22)
+ (UNSPEC_BUNDLE_SELECTOR 23)
(UNSPEC_ADDP4 24)
(UNSPEC_PROLOGUE_USE 25)
])
@@ -72,9 +80,9 @@
(UNSPECV_BLOCKAGE 1)
(UNSPECV_INSN_GROUP_BARRIER 2)
(UNSPECV_BREAK 3)
- (UNSPECV_SET_BSP 5)
- (UNSPECV_PSAC_ALL 8) ; pred.safe_across_calls
- (UNSPECV_PSAC_NORMAL 9)
+ (UNSPECV_SET_BSP 4)
+ (UNSPECV_PSAC_ALL 5) ; pred.safe_across_calls
+ (UNSPECV_PSAC_NORMAL 6)
])
;; ::::::::::::::::::::
@@ -276,9 +284,10 @@
(match_operand:QI 1 "general_operand" ""))]
""
{
- if (! reload_in_progress && ! reload_completed
- && ! ia64_move_ok (operands[0], operands[1]))
- operands[1] = force_reg (QImode, operands[1]);
+ rtx op1 = ia64_expand_move (operands[0], operands[1]);
+ if (!op1)
+ DONE;
+ operands[1] = op1;
})
(define_insn "*movqi_internal"
@@ -300,9 +309,10 @@
(match_operand:HI 1 "general_operand" ""))]
""
{
- if (! reload_in_progress && ! reload_completed
- && ! ia64_move_ok (operands[0], operands[1]))
- operands[1] = force_reg (HImode, operands[1]);
+ rtx op1 = ia64_expand_move (operands[0], operands[1]);
+ if (!op1)
+ DONE;
+ operands[1] = op1;
})
(define_insn "*movhi_internal"
@@ -324,9 +334,10 @@
(match_operand:SI 1 "general_operand" ""))]
""
{
- if (! reload_in_progress && ! reload_completed
- && ! ia64_move_ok (operands[0], operands[1]))
- operands[1] = force_reg (SImode, operands[1]);
+ rtx op1 = ia64_expand_move (operands[0], operands[1]);
+ if (!op1)
+ DONE;
+ operands[1] = op1;
})
(define_insn "*movsi_internal"
@@ -352,30 +363,10 @@
(match_operand:DI 1 "general_operand" ""))]
""
{
- if (! reload_in_progress && ! reload_completed
- && ! ia64_move_ok (operands[0], operands[1]))
- operands[1] = force_reg (DImode, operands[1]);
- if (! TARGET_NO_PIC && symbolic_operand (operands[1], DImode))
- {
- /* Before optimization starts, delay committing to any particular
- type of PIC address load. If this function gets deferred, we
- may acquire information that changes the value of the
- sdata_symbolic_operand predicate. */
- /* But don't delay for function pointers. Loading a function address
- actually loads the address of the descriptor not the function.
- If we represent these as SYMBOL_REFs, then they get cse'd with
- calls, and we end up with calls to the descriptor address instead of
- calls to the function address. Functions are not candidates for
- sdata anyways. */
- if (rtx_equal_function_value_matters
- && ! (GET_CODE (operands[1]) == SYMBOL_REF
- && SYMBOL_REF_FLAG (operands[1])))
- emit_insn (gen_movdi_symbolic (operands[0], operands[1],
- gen_reg_rtx (DImode)));
- else
- ia64_expand_load_address (operands[0], operands[1], NULL_RTX);
- DONE;
- }
+ rtx op1 = ia64_expand_move (operands[0], operands[1]);
+ if (!op1)
+ DONE;
+ operands[1] = op1;
})
;; This is used during early compilation to delay the decision on
@@ -384,19 +375,22 @@
;; deferred functions, since we may acquire additional information
;; on the variables used in the meantime.
-;; ??? This causes us to lose REG_LABEL notes, because the insn splitter
-;; does not attempt to preserve any REG_NOTES on the input instruction.
-
(define_insn_and_split "movdi_symbolic"
[(set (match_operand:DI 0 "register_operand" "=r")
(match_operand:DI 1 "symbolic_operand" "s"))
- (clobber (match_operand:DI 2 "register_operand" "+r"))
+ (clobber (match_scratch:DI 2 "=r"))
(use (reg:DI 1))]
""
"* abort ();"
- ""
+ "!no_new_pseudos || reload_completed"
[(const_int 0)]
- { ia64_expand_load_address (operands[0], operands[1], operands[2]); DONE; })
+{
+ rtx scratch = operands[2];
+ if (!reload_completed)
+ gen_reg_rtx (Pmode);
+ ia64_expand_load_address (operands[0], operands[1], scratch);
+ DONE;
+})
(define_insn "*movdi_internal"
[(set (match_operand:DI 0 "destination_operand"
@@ -505,6 +499,131 @@
"addl %0 = @ltoff(%1), gp"
[(set_attr "itanium_class" "ialu")])
+(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_DTPMOD)))]
+ ""
+ "addl %0 = @ltoff(@dtpmod(%1)), gp"
+ [(set_attr "itanium_class" "ialu")])
+
+(define_insn "load_ltoff_dtprel"
+ [(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"
+ [(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_DTPREL))]
+ ""
+ "")
+
+(define_insn "*load_dtprel64"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (unspec:DI [(match_operand:DI 1 "symbolic_operand" "")]
+ UNSPEC_DTPREL))]
+ "TARGET_TLS64"
+ "movl %0 = @dtprel(%1)"
+ [(set_attr "itanium_class" "long_i")])
+
+(define_insn "*load_dtprel22"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (unspec:DI [(match_operand:DI 1 "symbolic_operand" "")]
+ UNSPEC_DTPREL))]
+ ""
+ "addl %0 = @dtprel(%1), r0"
+ [(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)))]
+ "!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)))]
+ "TARGET_TLS14"
+ "adds %0 = @dtprel(%2), %1"
+ [(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)))]
+ "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"
+ [(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_TPREL))]
+ ""
+ "")
+
+(define_insn "*load_tprel64"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (unspec:DI [(match_operand:DI 1 "symbolic_operand" "")]
+ UNSPEC_TPREL))]
+ "TARGET_TLS64"
+ "movl %0 = @tprel(%1)"
+ [(set_attr "itanium_class" "long_i")])
+
+(define_insn "*load_tprel22"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (unspec:DI [(match_operand:DI 1 "symbolic_operand" "")]
+ UNSPEC_TPREL))]
+ ""
+ "addl %0 = @tprel(%1), r0"
+ [(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)))]
+ "!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)))]
+ "TARGET_TLS14"
+ "adds %0 = @tprel(%2), %1"
+ [(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)))]
+ "TARGET_TLS22"
+ "addl %0 = @tprel(%2), %1"
+ [(set_attr "itanium_class" "ialu")])
+
;; With no offsettable memory references, we've got to have a scratch
;; around to play with the second word.
(define_expand "movti"
@@ -513,9 +632,10 @@
(clobber (match_scratch:DI 2 ""))])]
""
{
- if (! reload_in_progress && ! reload_completed
- && ! ia64_move_ok (operands[0], operands[1]))
- operands[1] = force_reg (TImode, operands[1]);
+ rtx op1 = ia64_expand_move (operands[0], operands[1]);
+ if (!op1)
+ DONE;
+ operands[1] = op1;
})
(define_insn_and_split "*movti_internal"
@@ -630,9 +750,10 @@
(match_operand:SF 1 "general_operand" ""))]
""
{
- if (! reload_in_progress && ! reload_completed
- && ! ia64_move_ok (operands[0], operands[1]))
- operands[1] = force_reg (SFmode, operands[1]);
+ rtx op1 = ia64_expand_move (operands[0], operands[1]);
+ if (!op1)
+ DONE;
+ operands[1] = op1;
})
(define_insn "*movsf_internal"
@@ -655,9 +776,10 @@
(match_operand:DF 1 "general_operand" ""))]
""
{
- if (! reload_in_progress && ! reload_completed
- && ! ia64_move_ok (operands[0], operands[1]))
- operands[1] = force_reg (DFmode, operands[1]);
+ rtx op1 = ia64_expand_move (operands[0], operands[1]);
+ if (!op1)
+ DONE;
+ operands[1] = op1;
})
(define_insn "*movdf_internal"
Index: gcc/config/ia64/sysv4.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/ia64/sysv4.h,v
retrieving revision 1.25
diff -c -p -d -u -r1.25 sysv4.h
--- gcc/config/ia64/sysv4.h 18 May 2002 23:47:13 -0000 1.25
+++ gcc/config/ia64/sysv4.h 25 May 2002 02:06:36 -0000
@@ -42,8 +42,7 @@ extern int size_directive_output;
#undef ASM_OUTPUT_ALIGNED_LOCAL
#define ASM_OUTPUT_ALIGNED_DECL_LOCAL(FILE, DECL, NAME, SIZE, ALIGN) \
do { \
- if ((DECL) \
- && XSTR (XEXP (DECL_RTL (DECL), 0), 0)[0] == SDATA_NAME_FLAG_CHAR) \
+ if ((DECL) && sdata_symbolic_operand (XEXP (DECL_RTL (DECL), 0), Pmode)) \
sbss_section (); \
else \
bss_section (); \
@@ -62,8 +61,8 @@ do { \
#define ASM_OUTPUT_LABELREF(STREAM, NAME) \
do { \
const char *name_ = NAME; \
- if (*name_ == SDATA_NAME_FLAG_CHAR) \
- name_++; \
+ if (*name_ == ENCODE_SECTION_INFO_CHAR) \
+ name_ += 2; \
if (*name_ == '*') \
name_++; \
else \