[PATCH] TLS support for powerpc and powerpc64
Janis Johnson
janis187@us.ibm.com
Fri Apr 11 23:35:00 GMT 2003
This patch adds thread local storage support for powerpc-linux and
powerpc64-linux. Bootstrapped and regression tested on
powerpc-unknown-linux-gnu. Regression tests for cross compiler are
still running on powerpc64-unknown-linux-gnu, but they've had no
problems for recent versions of this patch.
OK for mainline, assuming powerpc64 test results are good?
2003-04-11 Janis Johnson <janis187@us.ibm.com>
Alan Modra <amodra@bigpond.net.au>
Jakub Jelinek <jakub@redhat.com>
* configure.in (HAVE_AS_TLS): Add powerpc and powerpc64 tests.
* configure: Rebuild.
* config/rs6000/linux64.h (ASM_OUTPUT_LABELREF): Handle TLS symbols.
* config/rs6000/rs6000-protos.h: Update.
* config/rs6000/rs6000.c (rs6000_tls_size): New.
(rs6000_tls_size_string): New.
(rs6000_parse_tls_size_option): New.
(legitimize_tls_address): New.
(rs6000_tls_get_addr): New.
(rs6000_got_sym): New.
(encode_tls_info): New.
(tls_model tls_symbolic_operand_type): New.
(rs6000_tls_symbol_ref_1): New.
(get_some_local_dynamic_name): New.
(get_some_local_dynamic_name_1): New.
(TARGET_HAVE_TLS): New.
(TARGET_CANNOT_FORCE_CONST_MEM): New.
(rs6000_override_options): Handle -mtls-size option.
(constant_pool_expr_1): Handle TLS symbols.
(rs6000_legitimize_address): Handle TLS symbols.
(rs6000_tls_referenced_p): New.
(rs6000_legitimate_address): Handle TLS symbols.
(rs6000_emit_move): Handle TLS symbols.
(mtcrf_operation): Use symbol for unspec constant.
(print_operand): Handle TLS symbols.
(uses_TOC): Handle TLS symbols.
(rs6000_emit_prologue): Use symbol for unspec constant.
(rs6000_elf_encode_section_info): Handle TLS symbols.
(rs6000_elf_strip_name_encoding): Handle TLS symbols.
* config/rs6000/rs6000.h (HAVE_AS_TLS): New.
(some_ld_name): New.
(LEGITIMATE_CONSTANT_P): Handle TLS symbols.
(PRINT_OPERAND_PUNCT_VALID_P): Handle TLS symbols.
(PREDICATE_CODES): Add rs6000_tls_symbol_ref.
* config/rs6000/rs6000.md (define_constants): Define constants for
all UNSPEC usage, including new values for TLS support.
(aux_truncdfsf2, gpc_reg_operand, movsi_got, movsi_got_internal,
load_toc_aix_si, load_toc_aix_di, load_toc_v4_pic_si,
load_toc_v4_PIC_1, load_toc_v4_PIC_1b, load_macho_picbase,
macho_correct_pic, blockage, gpc_reg_operand, movesi_from_cr,
stack_tie, movsi_to_cr_one, movsi_to_cr, mtcrfsi, eh_set_lr_si,
eh_set_lr_di): Use symbol for unspec constant.
(gpc_reg_operand): Use symbol for unspec constant.
(tls_gd_32, tls_gd_64, tls_ld_32, tls_ld_64, tls_dtprel_32,
tls_dtprel_64, tls_dtprel_ha_32, tls_dtprel_ha_64, tls_dtprel_lo_32,
tls_dtprel_lo_64, tls_got_dtprel_32, tls_got_dtprel_64, tls_tprel_32,
tls_tprel_64, tls_tprel_ha_32, tls_tprel_ha_64, tls_tprel_lo_32,
tls_tprel_lo_64, tls_got_tprel_32, tls_got_tprel_64, tls_tls_32,
tls_tls_64): New.
* config/rs6000/sysv4.h (SUBTARGET_OPTIONS): Add tls_size.
(ASM_OUTPUT_LABELREF): Handle TLS symbols.
Index: gcc/configure.in
===================================================================
RCS file: /home/janis/gcc_rsync/gcc-cvs/gcc/gcc/configure.in,v
retrieving revision 1.656
diff -u -p -r1.656 configure.in
--- gcc/configure.in 28 Mar 2003 23:15:41 -0000 1.656
+++ gcc/configure.in 11 Apr 2003 15:48:55 -0000
@@ -1991,6 +1991,7 @@ gcc_cv_as_tls=no
conftest_s=
tls_first_major=
tls_first_minor=
+tls_as_opt=
case "$target" in
changequote(,)dnl
alpha*-*-*)
@@ -2066,6 +2067,66 @@ foo: data8 25
tls_first_major=2
tls_first_minor=13
;;
+ powerpc-*-*)
+ conftest_s='
+ .section ".tdata","awT",@progbits
+ .align 2
+ld0: .space 4
+ld1: .space 4
+x1: .space 4
+x2: .space 4
+x3: .space 4
+ .text
+ addi 3,31,ld0@got@tlsgd
+ bl __tls_get_addr
+ addi 3,31,x1@got@tlsld
+ bl __tls_get_addr
+ addi 9,3,x1@dtprel
+ addis 9,3,x2@dtprel@ha
+ addi 9,9,x2@dtprel@l
+ lwz 9,x3@got@tprel(31)
+ add 9,9,x@tls
+ addi 9,2,x1@tprel
+ addis 9,2,x2@tprel@ha
+ addi 9,9,x2@tprel@l'
+ tls_first_major=2
+ tls_first_minor=13
+ tls_as_opt=-a32
+ ;;
+ powerpc64-*-*)
+ conftest_s='
+ .section ".tdata","awT",@progbits
+ .align 3
+ld0: .space 8
+ld1: .space 8
+x1: .space 8
+x2: .space 8
+x3: .space 8
+ .text
+ addi 3,2,ld0@got@tlsgd
+ bl .__tls_get_addr
+ nop
+ addi 3,2,ld1@toc
+ bl .__tls_get_addr
+ nop
+ addi 3,2,x1@got@tlsld
+ bl .__tls_get_addr
+ nop
+ addi 9,3,x1@dtprel
+ bl .__tls_get_addr
+ nop
+ addis 9,3,x2@dtprel@ha
+ addi 9,9,x2@dtprel@l
+ bl .__tls_get_addr
+ nop
+ ld 9,x3@got@dtprel(2)
+ add 9,9,3
+ bl .__tls_get_addr
+ nop'
+ tls_first_major=2
+ tls_first_minor=13
+ tls_as_opt=-a64
+ ;;
s390-*-*)
conftest_s='
.section ".tdata","awT",@progbits
@@ -2083,6 +2144,7 @@ foo: .long 25
bas %r14,0(%r1,%r13):tls_ldcall:foo'
tls_first_major=2
tls_first_minor=14
+ tls_as_opt=-m31
;;
s390x-*-*)
conftest_s='
@@ -2100,6 +2162,7 @@ foo: .long 25
brasl %r14,__tls_get_offset@PLT:tls_ldcall:foo'
tls_first_major=2
tls_first_minor=14
+ tls_as_opt=-m64
;;
esac
if test -z "$tls_first_major"; then
@@ -2110,7 +2173,7 @@ elif test $in_tree_gas = yes ; then
])
elif test x$gcc_cv_as != x; then
echo "$conftest_s" > conftest.s
- if $gcc_cv_as --fatal-warnings -o conftest.o conftest.s > /dev/null 2>&1
+ if $gcc_cv_as $tls_as_opt --fatal-warnings -o conftest.o conftest.s > /dev/null 2>&1
then
gcc_cv_as_tls=yes
fi
Index: gcc/config/rs6000/linux64.h
===================================================================
RCS file: /home/janis/gcc_rsync/gcc-cvs/gcc/gcc/config/rs6000/linux64.h,v
retrieving revision 1.35
diff -u -p -r1.35 linux64.h
--- gcc/config/rs6000/linux64.h 18 Mar 2003 02:28:46 -0000 1.35
+++ gcc/config/rs6000/linux64.h 11 Apr 2003 15:48:55 -0000
@@ -282,6 +282,8 @@ do { \
const char *_name = NAME; \
if (*_name == '@') \
_name++; \
+ else if (*_name == '%') \
+ _name += 2; \
\
if (*_name == '*') \
fprintf (FILE, "%s", _name + 1); \
Index: gcc/config/rs6000/rs6000-protos.h
===================================================================
RCS file: /home/janis/gcc_rsync/gcc-cvs/gcc/gcc/config/rs6000/rs6000-protos.h,v
retrieving revision 1.50
diff -u -p -r1.50 rs6000-protos.h
--- gcc/config/rs6000/rs6000-protos.h 1 Apr 2003 13:40:11 -0000 1.50
+++ gcc/config/rs6000/rs6000-protos.h 11 Apr 2003 15:48:55 -0000
@@ -195,6 +195,8 @@ extern int rs6000_register_move_cost PAR
enum reg_class, enum reg_class));
extern int rs6000_memory_move_cost PARAMS ((enum machine_mode,
enum reg_class, int));
+extern bool rs6000_tls_referenced_p PARAMS ((rtx));
+extern int rs6000_tls_symbol_ref PARAMS ((rtx, enum machine_mode));
/* Declare functions in rs6000-c.c */
Index: gcc/config/rs6000/rs6000.c
===================================================================
RCS file: /home/janis/gcc_rsync/gcc-cvs/gcc/gcc/config/rs6000/rs6000.c,v
retrieving revision 1.454
diff -u -p -r1.454 rs6000.c
--- gcc/config/rs6000/rs6000.c 8 Apr 2003 14:01:58 -0000 1.454
+++ gcc/config/rs6000/rs6000.c 11 Apr 2003 15:48:55 -0000
@@ -132,6 +132,10 @@ enum rs6000_sdata_type rs6000_sdata = SD
/* Which small data model to use */
const char *rs6000_sdata_name = (char *)0;
+/* Bit size of immediate TLS offsets and string from which it is decoded. */
+int rs6000_tls_size = 32;
+const char *rs6000_tls_size_string;
+
/* Counter for labels which are to be placed in .fixup. */
int fixuplabelno = 0;
#endif
@@ -283,6 +287,7 @@ static rtx altivec_expand_abs_builtin PA
static rtx altivec_expand_predicate_builtin PARAMS ((enum insn_code, const char *, tree, rtx));
static rtx altivec_expand_stv_builtin PARAMS ((enum insn_code, tree));
static void rs6000_parse_abi_options PARAMS ((void));
+static void rs6000_parse_tls_size_option PARAMS ((void));
static void rs6000_parse_yes_no_option (const char *, const char *, int *);
static int first_altivec_reg_to_save PARAMS ((void));
static unsigned int compute_vrsave_mask PARAMS ((void));
@@ -292,6 +297,14 @@ int easy_vector_constant PARAMS ((rtx, e
static int easy_vector_same PARAMS ((rtx, enum machine_mode));
static bool is_ev64_opaque_type PARAMS ((tree));
static rtx rs6000_dwarf_register_span PARAMS ((rtx));
+static rtx legitimize_tls_address PARAMS ((rtx, enum tls_model));
+static rtx rs6000_tls_get_addr PARAMS ((void));
+static rtx rs6000_got_sym PARAMS ((void));
+static void encode_tls_info PARAMS ((tree));
+static enum tls_model tls_symbolic_operand_type PARAMS ((rtx));
+static int rs6000_tls_symbol_ref_1 PARAMS ((rtx *, void *));
+static const char *get_some_local_dynamic_name PARAMS ((void));
+static int get_some_local_dynamic_name_1 PARAMS ((rtx *, void *));
/* Hash table stuff for keeping track of TOC entries. */
@@ -405,6 +418,12 @@ static const char alt_reg_names[][8] =
#define TARGET_ASM_ASSEMBLE_VISIBILITY rs6000_assemble_visibility
#endif
+#undef TARGET_HAVE_TLS
+#define TARGET_HAVE_TLS HAVE_AS_TLS
+
+#undef TARGET_CANNOT_FORCE_CONST_MEM
+#define TARGET_CANNOT_FORCE_CONST_MEM rs6000_tls_referenced_p
+
#undef TARGET_ASM_FUNCTION_PROLOGUE
#define TARGET_ASM_FUNCTION_PROLOGUE rs6000_output_function_prologue
#undef TARGET_ASM_FUNCTION_EPILOGUE
@@ -718,6 +737,9 @@ rs6000_override_options (default_cpu)
rs6000_parse_yes_no_option ("float-gprs", rs6000_float_gprs_string,
&rs6000_float_gprs);
+ /* Handle -mtls-size option. */
+ rs6000_parse_tls_size_option ();
+
#ifdef SUBTARGET_OVERRIDE_OPTIONS
SUBTARGET_OVERRIDE_OPTIONS;
#endif
@@ -848,6 +870,21 @@ rs6000_parse_abi_options ()
error ("unknown ABI specified: '%s'", rs6000_abi_string);
}
+static void
+rs6000_parse_tls_size_option ()
+{
+ if (rs6000_tls_size_string == 0)
+ return;
+ else if (strcmp (rs6000_tls_size_string, "16") == 0)
+ rs6000_tls_size = 16;
+ else if (strcmp (rs6000_tls_size_string, "32") == 0)
+ rs6000_tls_size = 32;
+ else if (strcmp (rs6000_tls_size_string, "64") == 0)
+ rs6000_tls_size = 64;
+ else
+ error ("bad value `%s' for -mtls-size-switch", rs6000_tls_size_string);
+}
+
void
optimization_options (level, size)
int level ATTRIBUTE_UNUSED;
@@ -2218,7 +2255,9 @@ constant_pool_expr_1 (op, have_sym, have
switch (GET_CODE(op))
{
case SYMBOL_REF:
- if (CONSTANT_POOL_ADDRESS_P (op))
+ if (tls_symbolic_operand_type (op))
+ return 0;
+ else if (CONSTANT_POOL_ADDRESS_P (op))
{
if (ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (get_pool_constant (op), Pmode))
{
@@ -2294,6 +2333,13 @@ rs6000_legitimize_address (x, oldx, mode
rtx oldx ATTRIBUTE_UNUSED;
enum machine_mode mode;
{
+ if (GET_CODE (x) == SYMBOL_REF)
+ {
+ enum tls_model model = tls_symbolic_operand_type (x);
+ if (model != 0)
+ return legitimize_tls_address (x, model);
+ }
+
if (GET_CODE (x) == PLUS
&& GET_CODE (XEXP (x, 0)) == REG
&& GET_CODE (XEXP (x, 1)) == CONST_INT
@@ -2394,6 +2440,284 @@ rs6000_legitimize_address (x, oldx, mode
return NULL_RTX;
}
+/* Construct the SYMBOL_REF for the tls_get_addr function. */
+
+static GTY(()) rtx rs6000_tls_symbol;
+static rtx
+rs6000_tls_get_addr ()
+{
+ if (!rs6000_tls_symbol)
+ rs6000_tls_symbol = gen_rtx_SYMBOL_REF (Pmode, "__tls_get_addr");
+
+ return rs6000_tls_symbol;
+}
+
+/* Construct the SYMBOL_REF for TLS GOT references. */
+
+static GTY(()) rtx rs6000_got_symbol;
+static rtx
+rs6000_got_sym ()
+{
+ if (!rs6000_got_symbol)
+ rs6000_got_symbol = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_");
+
+ return rs6000_got_symbol;
+}
+
+/* ADDR contains a thread-local SYMBOL_REF. Generate code to compute
+ this (thread-local) address. */
+
+static rtx
+legitimize_tls_address (addr, model)
+ rtx addr;
+ enum tls_model model;
+{
+ rtx dest, insn;
+
+ dest = gen_reg_rtx (Pmode);
+ if (model == TLS_MODEL_LOCAL_EXEC && rs6000_tls_size == 16)
+ {
+ rtx tlsreg;
+
+ if (TARGET_64BIT)
+ {
+ tlsreg = gen_rtx_REG (Pmode, 13);
+ insn = gen_tls_tprel_64 (dest, tlsreg, addr);
+ }
+ else
+ {
+ tlsreg = gen_rtx_REG (Pmode, 2);
+ insn = gen_tls_tprel_32 (dest, tlsreg, addr);
+ }
+ emit_insn (insn);
+ }
+ else if (model == TLS_MODEL_LOCAL_EXEC && rs6000_tls_size == 32)
+ {
+ rtx tlsreg, tmp;
+
+ tmp = gen_reg_rtx (Pmode);
+ if (TARGET_64BIT)
+ {
+ tlsreg = gen_rtx_REG (Pmode, 13);
+ insn = gen_tls_tprel_ha_64 (tmp, tlsreg, addr);
+ }
+ else
+ {
+ tlsreg = gen_rtx_REG (Pmode, 2);
+ insn = gen_tls_tprel_ha_32 (tmp, tlsreg, addr);
+ }
+ emit_insn (insn);
+ if (TARGET_64BIT)
+ insn = gen_tls_tprel_lo_64 (dest, tmp, addr);
+ else
+ insn = gen_tls_tprel_lo_32 (dest, tmp, addr);
+ emit_insn (insn);
+ }
+ else
+ {
+ rtx r3, got, tga, tmp1, tmp2, eqv;
+
+ if (TARGET_64BIT)
+ got = gen_rtx_REG (Pmode, TOC_REGISTER);
+ else
+ {
+ if (flag_pic == 1)
+ got = gen_rtx_REG (Pmode, RS6000_PIC_OFFSET_TABLE_REGNUM);
+ else
+ {
+ rtx gsym = rs6000_got_sym ();
+ got = gen_reg_rtx (Pmode);
+ if (flag_pic == 0)
+ rs6000_emit_move (got, gsym, Pmode);
+ else
+ {
+ char buf[30];
+ static int tls_got_labelno = 0;
+ rtx tempLR, lab, tmp3, mem;
+ rtx first, last;
+
+ ASM_GENERATE_INTERNAL_LABEL (buf, "LTLS", tls_got_labelno++);
+ lab = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
+ tempLR = gen_reg_rtx (Pmode);
+ tmp1 = gen_reg_rtx (Pmode);
+ tmp2 = gen_reg_rtx (Pmode);
+ tmp3 = gen_reg_rtx (Pmode);
+ mem = gen_rtx_MEM (Pmode, tmp1);
+ RTX_UNCHANGING_P (mem) = 1;
+
+ first = emit_insn (gen_load_toc_v4_PIC_1b (tempLR, lab,
+ gsym));
+ emit_move_insn (tmp1, tempLR);
+ emit_move_insn (tmp2, mem);
+ emit_insn (gen_addsi3 (tmp3, tmp1, tmp2));
+ last = emit_move_insn (got, tmp3);
+ REG_NOTES (last) = gen_rtx_EXPR_LIST (REG_EQUAL, gsym,
+ REG_NOTES (last));
+ REG_NOTES (first) = gen_rtx_INSN_LIST (REG_LIBCALL, last,
+ REG_NOTES (first));
+ REG_NOTES (last) = gen_rtx_INSN_LIST (REG_RETVAL, first,
+ REG_NOTES (last));
+ }
+ }
+ }
+
+ if (model == TLS_MODEL_GLOBAL_DYNAMIC)
+ {
+ r3 = gen_rtx_REG (Pmode, 3);
+ if (TARGET_64BIT)
+ insn = gen_tls_gd_64 (r3, got, addr);
+ else
+ insn = gen_tls_gd_32 (r3, got, addr);
+ start_sequence ();
+ emit_insn (insn);
+ tga = gen_rtx_MEM (Pmode, rs6000_tls_get_addr ());
+ insn = gen_call_value (r3, tga, const0_rtx, const0_rtx);
+ insn = emit_call_insn (insn);
+ CONST_OR_PURE_CALL_P (insn) = 1;
+ use_reg (&CALL_INSN_FUNCTION_USAGE (insn), r3);
+ insn = get_insns ();
+ end_sequence ();
+ emit_libcall_block (insn, dest, r3, addr);
+ }
+ else if (model == TLS_MODEL_LOCAL_DYNAMIC)
+ {
+ r3 = gen_rtx_REG (Pmode, 3);
+ if (TARGET_64BIT)
+ insn = gen_tls_ld_64 (r3, got);
+ else
+ insn = gen_tls_ld_32 (r3, got);
+ start_sequence ();
+ emit_insn (insn);
+ tga = gen_rtx_MEM (Pmode, rs6000_tls_get_addr ());
+ insn = gen_call_value (r3, tga, const0_rtx, const0_rtx);
+ insn = emit_call_insn (insn);
+ CONST_OR_PURE_CALL_P (insn) = 1;
+ use_reg (&CALL_INSN_FUNCTION_USAGE (insn), r3);
+ insn = get_insns ();
+ end_sequence ();
+ tmp1 = gen_reg_rtx (Pmode);
+ eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx),
+ UNSPEC_TLSLD);
+ emit_libcall_block (insn, tmp1, r3, eqv);
+ if (rs6000_tls_size == 16)
+ {
+ if (TARGET_64BIT)
+ insn = gen_tls_dtprel_64 (dest, tmp1, addr);
+ else
+ insn = gen_tls_dtprel_32 (dest, tmp1, addr);
+ }
+ else if (rs6000_tls_size == 32)
+ {
+ tmp2 = gen_reg_rtx (Pmode);
+ if (TARGET_64BIT)
+ insn = gen_tls_dtprel_ha_64 (tmp2, tmp1, addr);
+ else
+ insn = gen_tls_dtprel_ha_32 (tmp2, tmp1, addr);
+ emit_insn (insn);
+ if (TARGET_64BIT)
+ insn = gen_tls_dtprel_lo_64 (dest, tmp2, addr);
+ else
+ insn = gen_tls_dtprel_lo_32 (dest, tmp2, addr);
+ }
+ else
+ {
+ tmp2 = gen_reg_rtx (Pmode);
+ if (TARGET_64BIT)
+ insn = gen_tls_got_dtprel_64 (tmp2, got, addr);
+ else
+ insn = gen_tls_got_dtprel_32 (tmp2, got, addr);
+ emit_insn (insn);
+ insn = gen_rtx_SET (Pmode, dest,
+ gen_rtx_PLUS (Pmode, tmp2, tmp1));
+ }
+ emit_insn (insn);
+ }
+ else
+ {
+ /* IE, or 64 bit offset LE. */
+ tmp2 = gen_reg_rtx (Pmode);
+ if (TARGET_64BIT)
+ insn = gen_tls_got_tprel_64 (tmp2, got, addr);
+ else
+ insn = gen_tls_got_tprel_32 (tmp2, got, addr);
+ emit_insn (insn);
+ if (TARGET_64BIT)
+ insn = gen_tls_tls_64 (dest, tmp2, addr);
+ else
+ insn = gen_tls_tls_32 (dest, tmp2, addr);
+ emit_insn (insn);
+ }
+ }
+
+ return dest;
+}
+
+/* If OP is a SYMBOL_REF of a thread-local symbol, return its TLS type,
+ otherwise return 0. */
+
+static enum tls_model
+tls_symbolic_operand_type (op)
+ rtx op;
+{
+ const char *str;
+
+ if (GET_CODE (op) != SYMBOL_REF)
+ return 0;
+
+ str = XSTR (op, 0);
+ if (str[0] != '%')
+ return 0;
+
+ switch (str[1])
+ {
+ case 'G':
+ return TLS_MODEL_GLOBAL_DYNAMIC;
+ case 'L':
+ /* Local dynamic is a waste if we're not going to combine
+ the __tls_get_addr calls. So avoid it if not optimizing. */
+ if (optimize)
+ return TLS_MODEL_LOCAL_DYNAMIC;
+ else
+ return TLS_MODEL_GLOBAL_DYNAMIC;
+ case 'i':
+ return TLS_MODEL_INITIAL_EXEC;
+ case 'l':
+ return TLS_MODEL_LOCAL_EXEC;
+ }
+ return 0;
+}
+
+/* Return 1 if X is a SYMBOL_REF for a TLS symbol. */
+
+int
+rs6000_tls_symbol_ref (x, mode)
+ rtx x;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+ if (GET_CODE (x) != SYMBOL_REF)
+ return 0;
+ return tls_symbolic_operand_type (x) != 0;
+}
+
+/* Determine if X contains a thread-local symbol. */
+
+bool
+rs6000_tls_referenced_p (x)
+ rtx x;
+{
+ return for_each_rtx (&x, &rs6000_tls_symbol_ref_1, 0);
+}
+
+static int
+rs6000_tls_symbol_ref_1 (x, data)
+ rtx *x;
+ void *data ATTRIBUTE_UNUSED;
+{
+ if (GET_CODE (*x) != SYMBOL_REF)
+ return 0;
+ return tls_symbolic_operand_type (*x);
+}
+
/* The convention appears to be to define this wherever it is used.
With legitimize_reload_address now defined here, REG_MODE_OK_FOR_BASE_P
is now used here. */
@@ -2562,6 +2886,8 @@ rs6000_legitimate_address (mode, x, reg_
rtx x;
int reg_ok_strict;
{
+ if (GET_CODE (x) == SYMBOL_REF && tls_symbolic_operand_type (x) != 0)
+ return 0;
if (LEGITIMATE_INDIRECT_ADDRESS_P (x, reg_ok_strict))
return 1;
if ((GET_CODE (x) == PRE_INC || GET_CODE (x) == PRE_DEC)
@@ -2844,6 +3170,15 @@ rs6000_emit_move (dest, source, mode)
}
}
+ /* Recognize the case where operand[1] is a reference to thread-local
+ data and load its address to a register. */
+ if (GET_CODE (operands[1]) == SYMBOL_REF)
+ {
+ enum tls_model model = tls_symbolic_operand_type (operands[1]);
+ if (model != 0)
+ operands[1] = legitimize_tls_address (operands[1], model);
+ }
+
/* Handle the case where reload calls us with an invalid address;
and the case of CONSTANT_P_RTX. */
if (!ALTIVEC_VECTOR_MODE (mode)
@@ -6789,7 +7124,7 @@ mtcrf_operation (op, mode)
maskval = 1 << (MAX_CR_REGNO - REGNO (SET_DEST (exp)));
if (GET_CODE (unspec) != UNSPEC
- || XINT (unspec, 1) != 20
+ || XINT (unspec, 1) != UNSPEC_MOVESI_TO_CR
|| XVECLEN (unspec, 0) != 2
|| XVECEXP (unspec, 0, 0) != src_reg
|| GET_CODE (XVECEXP (unspec, 0, 1)) != CONST_INT
@@ -7633,6 +7968,45 @@ extract_ME (op)
return i;
}
+/* Locate some local-dynamic symbol still in use by this function
+ so that we can print its name in some tls_ld pattern. */
+
+static const char *
+get_some_local_dynamic_name ()
+{
+ rtx insn;
+
+ if (cfun->machine->some_ld_name)
+ return cfun->machine->some_ld_name;
+
+ for (insn = get_insns (); insn ; insn = NEXT_INSN (insn))
+ if (INSN_P (insn)
+ && for_each_rtx (&PATTERN (insn), get_some_local_dynamic_name_1, 0))
+ return cfun->machine->some_ld_name;
+
+ abort ();
+}
+
+static int
+get_some_local_dynamic_name_1 (px, data)
+ rtx *px;
+ void *data ATTRIBUTE_UNUSED;
+{
+ rtx x = *px;
+
+ if (GET_CODE (x) == SYMBOL_REF)
+ {
+ const char *str = XSTR (x, 0);
+ if (str[0] == '%' && str[1] == 'L')
+ {
+ cfun->machine->some_ld_name = str;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
/* Print an operand. Recognize special options, documented below. */
#if TARGET_ELF
@@ -8284,6 +8658,10 @@ print_operand (file, x, code)
output_addr_const (file, x);
return;
+ case '&':
+ assemble_name (file, get_some_local_dynamic_name ());
+ return;
+
default:
output_operand_lossage ("invalid %%xn code");
}
@@ -10030,27 +10408,34 @@ get_TOC_alias_set ()
}
/* This retuns nonzero if the current function uses the TOC. This is
- determined by the presence of (unspec ... 7), which is generated by
- the various load_toc_* patterns. */
+ determined by the presence of (unspec ... UNSPEC_TOC), which is
+ generated by the various load_toc_* patterns. */
int
uses_TOC ()
{
- rtx insn;
+ rtx insn;
- for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
- if (INSN_P (insn))
- {
- rtx pat = PATTERN (insn);
- int i;
+ for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+ if (INSN_P (insn))
+ {
+ rtx pat = PATTERN (insn);
+ int i;
- if (GET_CODE (pat) == PARALLEL)
- for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++)
- if (GET_CODE (XVECEXP (PATTERN (insn), 0, i)) == UNSPEC
- && XINT (XVECEXP (PATTERN (insn), 0, i), 1) == 7)
- return 1;
- }
- return 0;
+ if (GET_CODE (pat) == PARALLEL)
+ for (i = 0; i < XVECLEN (pat, 0); i++)
+ {
+ rtx sub = XVECEXP (pat, 0, i);
+ if (GET_CODE (sub) == USE)
+ {
+ sub = XEXP (sub, 0);
+ if (GET_CODE (sub) == UNSPEC
+ && XINT (sub, 1) == UNSPEC_TOC)
+ return 1;
+ }
+ }
+ }
+ return 0;
}
rtx
@@ -10888,9 +11273,9 @@ rs6000_emit_prologue ()
insn = emit_move_insn (mem, cr_save_rtx);
/* Now, there's no way that dwarf2out_frame_debug_expr is going
- to understand '(unspec:SI [(reg:CC 68) ...] 19)'. But that's
- OK. All we have to do is specify that _one_ condition code
- register is saved in this stack slot. The thrower's epilogue
+ to understand '(unspec:SI [(reg:CC 68) ...] UNSPEC_MOVESI_FROM_CR)'.
+ But that's OK. All we have to do is specify that _one_ condition
+ code register is saved in this stack slot. The thrower's epilogue
will then restore all the call-saved registers.
We use CR2_REGNO (70) to be compatible with gcc-2.95 on Linux. */
rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
@@ -11291,7 +11676,7 @@ rs6000_emit_epilogue (sibcall)
RTVEC_ELT (r, 1) = GEN_INT (1 << (7-i));
RTVEC_ELT (p, ndx) =
gen_rtx_SET (VOIDmode, gen_rtx_REG (CCmode, CR0_REGNO+i),
- gen_rtx_UNSPEC (CCmode, r, 20));
+ gen_rtx_UNSPEC (CCmode, r, UNSPEC_MOVESI_TO_CR));
ndx++;
}
emit_insn (gen_rtx_PARALLEL (VOIDmode, p));
@@ -12882,6 +13267,53 @@ rs6000_longcall_ref (call_ref)
return force_reg (Pmode, call_ref);
}
+/* Encode the TLS model into the name of a thread-local variable. */
+
+static void
+encode_tls_info (decl)
+ tree decl;
+{
+ /* Encode thread-local data with %[GLil] for the TLS model. */
+ rtx sym_ref = XEXP (DECL_RTL (decl), 0);
+ const char *symbol_str = XSTR (sym_ref, 0);
+ char *newstr;
+ size_t len;
+ char encoding = 0;
+
+ switch (decl_tls_model (decl))
+ {
+ case TLS_MODEL_GLOBAL_DYNAMIC:
+ encoding = 'G';
+ break;
+ case TLS_MODEL_LOCAL_DYNAMIC:
+ encoding = 'L';
+ break;
+ case TLS_MODEL_INITIAL_EXEC:
+ encoding = 'i';
+ break;
+ case TLS_MODEL_LOCAL_EXEC:
+ encoding = 'l';
+ break;
+ }
+
+ /* Strip an existing TLS encoding, which might be there for aliases. */
+ if (symbol_str[0] == '%')
+ {
+ if (symbol_str[1] == encoding)
+ return;
+ symbol_str += 2;
+ }
+
+ len = strlen (symbol_str) + 1;
+ newstr = alloca (len + 2);
+
+ newstr[0] = '%';
+ newstr[1] = encoding;
+ memcpy (newstr + 2, symbol_str, len);
+
+ XSTR (sym_ref, 0) = ggc_alloc_string (newstr, len + 2 - 1);
+}
+
#ifdef USING_ELFOS_H
@@ -12944,13 +13376,18 @@ rs6000_elf_unique_section (decl, reloc)
flag_pic || DEFAULT_ABI == ABI_AIX);
}
-/* If we are referencing a function that is static or is known to be
+/* Encode symbol attributes of a SYMBOL_REF into its name and
+ SYMBOL_REF_FLAG.
+
+ If we are referencing a function that is static or is known to be
in this file, make the SYMBOL_REF special. We can use this to indicate
that we can branch to this function without emitting a no-op after the
call. For real AIX calling sequences, we also replace the
function name with the real name (1 or 2 leading .'s), rather than
the function descriptor name. This saves a lot of overriding code
- to read the prefixes. */
+ to read the prefixes.
+
+ For a TLS symbol we encode the TLS model. */
static void
rs6000_elf_encode_section_info (decl, first)
@@ -12978,6 +13415,8 @@ rs6000_elf_encode_section_info (decl, fi
XSTR (sym_ref, 0) = ggc_alloc_string (str, len1 + len2);
}
}
+ else if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL (decl))
+ encode_tls_info (decl);
else if (rs6000_sdata != SDATA_NONE
&& DEFAULT_ABI == ABI_V4
&& TREE_CODE (decl) == VAR_DECL)
@@ -13027,11 +13466,17 @@ rs6000_elf_encode_section_info (decl, fi
}
}
+/* Undo the effects of the above for printing symbol names. */
+
static const char *
rs6000_elf_strip_name_encoding (str)
const char *str;
{
- while (*str == '*' || *str == '@')
+ if (*str == '@')
+ str++;
+ else if (*str == '%')
+ str += 2;
+ if (*str == '*')
str++;
return str;
}
Index: gcc/config/rs6000/rs6000.h
===================================================================
RCS file: /home/janis/gcc_rsync/gcc-cvs/gcc/gcc/config/rs6000/rs6000.h,v
retrieving revision 1.263
diff -u -p -r1.263 rs6000.h
--- gcc/config/rs6000/rs6000.h 7 Apr 2003 18:49:10 -0000 1.263
+++ gcc/config/rs6000/rs6000.h 11 Apr 2003 15:48:55 -0000
@@ -210,6 +210,10 @@ extern int target_flags;
#define TARGET_UPDATE (! TARGET_NO_UPDATE)
#define TARGET_FUSED_MADD (! TARGET_NO_FUSED_MADD)
+#ifndef HAVE_AS_TLS
+#define HAVE_AS_TLS 0
+#endif
+
#ifdef IN_LIBGCC2
/* For libgcc2 we make sure this is a compile time constant */
#if defined (__64BIT__) || defined (__powerpc64__)
@@ -1674,6 +1678,8 @@ typedef struct machine_function GTY(())
int sysv_varargs_p;
/* Flags if __builtin_return_address (n) with n >= 1 was used. */
int ra_needs_full_frame;
+ /* Some local-dynamic symbol. */
+ const char *some_ld_name;
/* Whether the instruction chain has been scanned already. */
int insn_chain_scanned_p;
} machine_function;
@@ -2012,9 +2018,10 @@ typedef struct rs6000_args
acceptable. */
#define LEGITIMATE_CONSTANT_P(X) \
- (GET_CODE (X) != CONST_DOUBLE || GET_MODE (X) == VOIDmode \
- || (TARGET_POWERPC64 && GET_MODE (X) == DImode) \
- || easy_fp_constant (X, GET_MODE (X)))
+ ((GET_CODE (X) != CONST_DOUBLE || GET_MODE (X) == VOIDmode \
+ || (TARGET_POWERPC64 && GET_MODE (X) == DImode) \
+ || easy_fp_constant (X, GET_MODE (X))) \
+ && !rs6000_tls_referenced_p (X))
/* The macros REG_OK_FOR..._P assume that the arg is a REG rtx
and check its validity for a certain class.
@@ -2718,7 +2725,7 @@ extern char rs6000_reg_names[][8]; /* re
/* Define which CODE values are valid. */
#define PRINT_OPERAND_PUNCT_VALID_P(CODE) \
- ((CODE) == '.')
+ ((CODE) == '.' || (CODE) == '&')
/* Print a memory address as an operand to reference that memory location. */
@@ -2772,6 +2779,7 @@ extern char rs6000_reg_names[][8]; /* re
{"count_register_operand", {REG}}, \
{"xer_operand", {REG}}, \
{"symbol_ref_operand", {SYMBOL_REF}}, \
+ {"rs6000_tls_symbol_ref", {SYMBOL_REF}}, \
{"call_operand", {SYMBOL_REF, REG}}, \
{"current_file_function_operand", {SYMBOL_REF}}, \
{"input_operand", {SUBREG, MEM, REG, CONST_INT, \
Index: gcc/config/rs6000/rs6000.md
===================================================================
RCS file: /home/janis/gcc_rsync/gcc-cvs/gcc/gcc/config/rs6000/rs6000.md,v
retrieving revision 1.245
diff -u -p -r1.245 rs6000.md
--- gcc/config/rs6000/rs6000.md 1 Apr 2003 18:05:46 -0000 1.245
+++ gcc/config/rs6000/rs6000.md 11 Apr 2003 15:48:55 -0000
@@ -22,20 +22,43 @@
;;- See file "rtl.def" for documentation on define_insn, match_*, et. al.
-;; `unspec' values used in rs6000.md:
-;; Number Use
-;; 0 frsp for POWER machines
-;; 0/v blockage
-;; 5 used to tie the stack contents and the stack pointer
-;; 6 address of a word pointing to the TOC
-;; 7 address of the TOC (more-or-less)
-;; 8 movsi_got
-;; 9/v eh_reg_restore
-;; 10 fctiwz
-;; 15 load_macho_picbase
-;; 16 macho_correct_pic
-;; 19 movesi_from_cr
-;; 20 movsi_to_cr
+;;
+;; UNSPEC usage
+;;
+
+(define_constants
+ [(UNSPEC_FRSP 0) ; frsp for POWER machines
+ (UNSPEC_TIE 5) ; tie stack contents and stack pointer
+ (UNSPEC_TOCPTR 6) ; address of a word pointing to the TOC
+ (UNSPEC_TOC 7) ; address of the TOC (more-or-less)
+ (UNSPEC_MOVSI_GOT 8)
+ (UNSPEC_MV_CR_OV 9) ; move_from_CR_ov_bit
+ (UNSPEC_FCTIWZ 10)
+ (UNSPEC_LD_MPIC 15) ; load_macho_picbase
+ (UNSPEC_MPIC_CORRECT 16) ; macho_correct_pic
+ (UNSPEC_TLSGD 17)
+ (UNSPEC_TLSLD 18)
+ (UNSPEC_MOVESI_FROM_CR 19)
+ (UNSPEC_MOVESI_TO_CR 20)
+ (UNSPEC_TLSDTPREL 21)
+ (UNSPEC_TLSDTPRELHA 22)
+ (UNSPEC_TLSDTPRELLO 23)
+ (UNSPEC_TLSGOTDTPREL 24)
+ (UNSPEC_TLSTPREL 25)
+ (UNSPEC_TLSTPRELHA 26)
+ (UNSPEC_TLSTPRELLO 27)
+ (UNSPEC_TLSGOTTPREL 28)
+ (UNSPEC_TLSTLS 29)
+ ])
+
+;;
+;; UNSPEC_VOLATILE usage
+;;
+
+(define_constants
+ [(UNSPECV_BLOCK 0)
+ (UNSPECV_EH_RR 9) ; eh_reg_restore
+ ])
;; Define an insn type attribute. This is used in function unit delay
;; computations.
@@ -4362,7 +4385,7 @@
(define_insn "aux_truncdfsf2"
[(set (match_operand:SF 0 "gpc_reg_operand" "=f")
- (unspec:SF [(match_operand:SF 1 "gpc_reg_operand" "f")] 0))]
+ (unspec:SF [(match_operand:SF 1 "gpc_reg_operand" "f")] UNSPEC_FRSP))]
"! TARGET_POWERPC && TARGET_HARD_FLOAT && TARGET_FPRS"
"frsp %0,%1"
[(set_attr "type" "fp")])
@@ -5148,13 +5171,14 @@
DONE;
}")
-; Here, we use (set (reg) (unspec:DI [(fix:SI ...)] 10))
+; Here, we use (set (reg) (unspec:DI [(fix:SI ...)] UNSPEC_FCTIWZ))
; rather than (set (subreg:SI (reg)) (fix:SI ...))
; because the first makes it clear that operand 0 is not live
; before the instruction.
(define_insn "fctiwz"
[(set (match_operand:DI 0 "gpc_reg_operand" "=*f")
- (unspec:DI [(fix:SI (match_operand:DF 1 "gpc_reg_operand" "f"))] 10))]
+ (unspec:DI [(fix:SI (match_operand:DF 1 "gpc_reg_operand" "f"))]
+ UNSPEC_FCTIWZ))]
"(TARGET_POWER2 || TARGET_POWERPC) && TARGET_HARD_FLOAT && TARGET_FPRS"
"{fcirz|fctiwz} %0,%1"
[(set_attr "type" "fp")])
@@ -7497,7 +7521,7 @@
(define_expand "movsi_got"
[(set (match_operand:SI 0 "gpc_reg_operand" "")
(unspec:SI [(match_operand:SI 1 "got_operand" "")
- (match_dup 2)] 8))]
+ (match_dup 2)] UNSPEC_MOVSI_GOT))]
"DEFAULT_ABI == ABI_V4 && flag_pic == 1"
"
{
@@ -7523,7 +7547,8 @@
(define_insn "*movsi_got_internal"
[(set (match_operand:SI 0 "gpc_reg_operand" "=r")
(unspec:SI [(match_operand:SI 1 "got_no_const_operand" "")
- (match_operand:SI 2 "gpc_reg_operand" "b")] 8))]
+ (match_operand:SI 2 "gpc_reg_operand" "b")]
+ UNSPEC_MOVSI_GOT))]
"DEFAULT_ABI == ABI_V4 && flag_pic == 1"
"{l|lwz} %0,%a1@got(%2)"
[(set_attr "type" "load")])
@@ -7533,12 +7558,14 @@
(define_split
[(set (match_operand:SI 0 "gpc_reg_operand" "")
(unspec:SI [(match_operand:SI 1 "got_no_const_operand" "")
- (match_operand:SI 2 "memory_operand" "")] 8))]
+ (match_operand:SI 2 "memory_operand" "")]
+ UNSPEC_MOVSI_GOT))]
"DEFAULT_ABI == ABI_V4
&& flag_pic == 1
&& (reload_in_progress || reload_completed)"
[(set (match_dup 0) (match_dup 2))
- (set (match_dup 0) (unspec:SI [(match_dup 1)(match_dup 0)] 8))]
+ (set (match_dup 0) (unspec:SI [(match_dup 1)(match_dup 0)]
+ UNSPEC_MOVSI_GOT))]
"")
;; For SI, we special-case integers that can't be loaded in one insn. We
@@ -9689,6 +9716,186 @@
&& addrs_ok_for_quad_peep (XEXP (operands[0], 0), XEXP (operands[2], 0))"
"stfq%U0%X0 %1,%0")
+;; TLS support.
+
+;; "b" output constraint here and on tls_ld to support tls linker optimization.
+(define_insn "tls_gd_32"
+ [(set (match_operand:SI 0 "register_operand" "=b")
+ (unspec:SI [(match_operand:SI 1 "register_operand" "b")
+ (match_operand:SI 2 "rs6000_tls_symbol_ref" "")]
+ UNSPEC_TLSGD))]
+ "HAVE_AS_TLS && !TARGET_64BIT"
+ "addi %0,%1,%2@got@tlsgd")
+
+(define_insn "tls_gd_64"
+ [(set (match_operand:DI 0 "register_operand" "=b")
+ (unspec:DI [(match_operand:DI 1 "register_operand" "b")
+ (match_operand:DI 2 "rs6000_tls_symbol_ref" "")]
+ UNSPEC_TLSGD))]
+ "HAVE_AS_TLS && TARGET_64BIT"
+ "addi %0,%1,%2@got@tlsgd")
+
+(define_insn "tls_ld_32"
+ [(set (match_operand:SI 0 "register_operand" "=b")
+ (unspec:SI [(match_operand:SI 1 "register_operand" "b")]
+ UNSPEC_TLSLD))]
+ "HAVE_AS_TLS && !TARGET_64BIT"
+ "addi %0,%1,%&@got@tlsld")
+
+(define_insn "tls_ld_64"
+ [(set (match_operand:DI 0 "register_operand" "=b")
+ (unspec:DI [(match_operand:DI 1 "register_operand" "b")]
+ UNSPEC_TLSLD))]
+ "HAVE_AS_TLS && TARGET_64BIT"
+ "addi %0,%1,%&@got@tlsld")
+
+(define_insn "tls_dtprel_32"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec:SI [(match_operand:SI 1 "register_operand" "b")
+ (match_operand:SI 2 "rs6000_tls_symbol_ref" "")]
+ UNSPEC_TLSDTPREL))]
+ "HAVE_AS_TLS && !TARGET_64BIT"
+ "addi %0,%1,%2@dtprel")
+
+(define_insn "tls_dtprel_64"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (unspec:DI [(match_operand:DI 1 "register_operand" "b")
+ (match_operand:DI 2 "rs6000_tls_symbol_ref" "")]
+ UNSPEC_TLSDTPREL))]
+ "HAVE_AS_TLS && TARGET_64BIT"
+ "addi %0,%1,%2@dtprel")
+
+(define_insn "tls_dtprel_ha_32"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec:SI [(match_operand:SI 1 "register_operand" "b")
+ (match_operand:SI 2 "rs6000_tls_symbol_ref" "")]
+ UNSPEC_TLSDTPRELHA))]
+ "HAVE_AS_TLS && !TARGET_64BIT"
+ "addis %0,%1,%2@dtprel@ha")
+
+(define_insn "tls_dtprel_ha_64"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (unspec:DI [(match_operand:DI 1 "register_operand" "b")
+ (match_operand:DI 2 "rs6000_tls_symbol_ref" "")]
+ UNSPEC_TLSDTPRELHA))]
+ "HAVE_AS_TLS && TARGET_64BIT"
+ "addis %0,%1,%2@dtprel@ha")
+
+(define_insn "tls_dtprel_lo_32"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec:SI [(match_operand:SI 1 "register_operand" "b")
+ (match_operand:SI 2 "rs6000_tls_symbol_ref" "")]
+ UNSPEC_TLSDTPRELLO))]
+ "HAVE_AS_TLS && !TARGET_64BIT"
+ "addi %0,%1,%2@dtprel@l")
+
+(define_insn "tls_dtprel_lo_64"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (unspec:DI [(match_operand:DI 1 "register_operand" "b")
+ (match_operand:DI 2 "rs6000_tls_symbol_ref" "")]
+ UNSPEC_TLSDTPRELLO))]
+ "HAVE_AS_TLS && TARGET_64BIT"
+ "addi %0,%1,%2@dtprel@l")
+
+(define_insn "tls_got_dtprel_32"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec:SI [(match_operand:SI 1 "register_operand" "b")
+ (match_operand:SI 2 "rs6000_tls_symbol_ref" "")]
+ UNSPEC_TLSGOTDTPREL))]
+ "HAVE_AS_TLS && !TARGET_64BIT"
+ "lwz %0,%2@got@dtprel(%1)")
+
+(define_insn "tls_got_dtprel_64"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (unspec:DI [(match_operand:DI 1 "register_operand" "b")
+ (match_operand:DI 2 "rs6000_tls_symbol_ref" "")]
+ UNSPEC_TLSGOTDTPREL))]
+ "HAVE_AS_TLS && TARGET_64BIT"
+ "ld %0,%2@got@dtprel(%1)")
+
+(define_insn "tls_tprel_32"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec:SI [(match_operand:SI 1 "register_operand" "b")
+ (match_operand:SI 2 "rs6000_tls_symbol_ref" "")]
+ UNSPEC_TLSTPREL))]
+ "HAVE_AS_TLS && !TARGET_64BIT"
+ "addi %0,%1,%2@tprel")
+
+(define_insn "tls_tprel_64"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (unspec:DI [(match_operand:DI 1 "register_operand" "b")
+ (match_operand:DI 2 "rs6000_tls_symbol_ref" "")]
+ UNSPEC_TLSTPREL))]
+ "HAVE_AS_TLS && TARGET_64BIT"
+ "addi %0,%1,%2@tprel")
+
+(define_insn "tls_tprel_ha_32"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec:SI [(match_operand:SI 1 "register_operand" "b")
+ (match_operand:SI 2 "rs6000_tls_symbol_ref" "")]
+ UNSPEC_TLSTPRELHA))]
+ "HAVE_AS_TLS && !TARGET_64BIT"
+ "addis %0,%1,%2@tprel@ha")
+
+(define_insn "tls_tprel_ha_64"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (unspec:DI [(match_operand:DI 1 "register_operand" "b")
+ (match_operand:DI 2 "rs6000_tls_symbol_ref" "")]
+ UNSPEC_TLSTPRELHA))]
+ "HAVE_AS_TLS && TARGET_64BIT"
+ "addis %0,%1,%2@tprel@ha")
+
+(define_insn "tls_tprel_lo_32"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec:SI [(match_operand:SI 1 "register_operand" "b")
+ (match_operand:SI 2 "rs6000_tls_symbol_ref" "")]
+ UNSPEC_TLSTPRELLO))]
+ "HAVE_AS_TLS && !TARGET_64BIT"
+ "addi %0,%1,%2@tprel@l")
+
+(define_insn "tls_tprel_lo_64"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (unspec:DI [(match_operand:DI 1 "register_operand" "b")
+ (match_operand:DI 2 "rs6000_tls_symbol_ref" "")]
+ UNSPEC_TLSTPRELLO))]
+ "HAVE_AS_TLS && TARGET_64BIT"
+ "addi %0,%1,%2@tprel@l")
+
+;; "b" output contraint here and on tls_tls input to support linker tls
+;; optimization. The linker may edit the instructions emitted by a
+;; tls_got_tprel/tls_tls pair to addis,addi.
+(define_insn "tls_got_tprel_32"
+ [(set (match_operand:SI 0 "register_operand" "=b")
+ (unspec:SI [(match_operand:SI 1 "register_operand" "b")
+ (match_operand:SI 2 "rs6000_tls_symbol_ref" "")]
+ UNSPEC_TLSGOTTPREL))]
+ "HAVE_AS_TLS && !TARGET_64BIT"
+ "lwz %0,%2@got@tprel(%1)")
+
+(define_insn "tls_got_tprel_64"
+ [(set (match_operand:DI 0 "register_operand" "=b")
+ (unspec:DI [(match_operand:DI 1 "register_operand" "b")
+ (match_operand:DI 2 "rs6000_tls_symbol_ref" "")]
+ UNSPEC_TLSGOTTPREL))]
+ "HAVE_AS_TLS && TARGET_64BIT"
+ "ld %0,%2@got@tprel(%1)")
+
+(define_insn "tls_tls_32"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec:SI [(match_operand:SI 1 "register_operand" "b")
+ (match_operand:SI 2 "rs6000_tls_symbol_ref" "")]
+ UNSPEC_TLSTLS))]
+ "HAVE_AS_TLS && !TARGET_64BIT"
+ "add %0,%1,%2@tls")
+
+(define_insn "tls_tls_64"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (unspec:DI [(match_operand:DI 1 "register_operand" "b")
+ (match_operand:DI 2 "rs6000_tls_symbol_ref" "")]
+ UNSPEC_TLSTLS))]
+ "HAVE_AS_TLS && TARGET_64BIT"
+ "add %0,%1,%2@tls")
+
;; Next come insns related to the calling sequence.
;;
;; First, an insn to allocate new stack space for dynamic use (e.g., alloca).
@@ -9820,7 +10027,7 @@
(define_insn "load_toc_aix_si"
[(parallel [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
- (unspec:SI [(const_int 0)] 7))
+ (unspec:SI [(const_int 0)] UNSPEC_TOC))
(use (reg:SI 2))])]
"DEFAULT_ABI == ABI_AIX && TARGET_32BIT"
"*
@@ -9835,7 +10042,7 @@
(define_insn "load_toc_aix_di"
[(parallel [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
- (unspec:DI [(const_int 0)] 7))
+ (unspec:DI [(const_int 0)] UNSPEC_TOC))
(use (reg:DI 2))])]
"DEFAULT_ABI == ABI_AIX && TARGET_64BIT"
"*
@@ -9857,7 +10064,7 @@
(define_insn "load_toc_v4_pic_si"
[(set (match_operand:SI 0 "register_operand" "=l")
- (unspec:SI [(const_int 0)] 7))]
+ (unspec:SI [(const_int 0)] UNSPEC_TOC))]
"DEFAULT_ABI == ABI_V4 && flag_pic == 1 && TARGET_32BIT"
"bl _GLOBAL_OFFSET_TABLE_@local-4"
[(set_attr "type" "branch")
@@ -9866,7 +10073,7 @@
(define_insn "load_toc_v4_PIC_1"
[(set (match_operand:SI 0 "register_operand" "=l")
(match_operand:SI 1 "immediate_operand" "s"))
- (unspec [(match_dup 1)] 7)]
+ (use (unspec [(match_dup 1)] UNSPEC_TOC))]
"TARGET_ELF && DEFAULT_ABI != ABI_AIX && flag_pic == 2"
"bcl 20,31,%1\\n%1:"
[(set_attr "type" "branch")
@@ -9875,9 +10082,10 @@
(define_insn "load_toc_v4_PIC_1b"
[(set (match_operand:SI 0 "register_operand" "=l")
(match_operand:SI 1 "immediate_operand" "s"))
- (unspec [(match_dup 1) (match_operand 2 "immediate_operand" "s")] 6)]
+ (use (unspec [(match_dup 1) (match_operand 2 "immediate_operand" "s")]
+ UNSPEC_TOCPTR))]
"TARGET_ELF && DEFAULT_ABI != ABI_AIX && flag_pic == 2"
- "bcl 20,31,%1\\n\\t.long %2-%1+4\\n%1:"
+ "bcl 20,31,%1+4\\n%1:\\n\\t.long %2-%1"
[(set_attr "type" "branch")
(set_attr "length" "8")])
@@ -9892,7 +10100,8 @@
(define_insn "load_macho_picbase"
[(set (match_operand:SI 0 "register_operand" "=l")
- (unspec:SI [(match_operand:SI 1 "immediate_operand" "s")] 15))]
+ (unspec:SI [(match_operand:SI 1 "immediate_operand" "s")]
+ UNSPEC_LD_MPIC))]
"(DEFAULT_ABI == ABI_DARWIN) && flag_pic"
"bcl 20,31,%1\\n%1:"
[(set_attr "type" "branch")
@@ -9903,7 +10112,7 @@
(plus:SI (match_operand:SI 1 "gpc_reg_operand" "r")
(unspec:SI [(match_operand:SI 2 "immediate_operand" "s")
(match_operand:SI 3 "immediate_operand" "s")]
- 16)))]
+ UNSPEC_MPIC_CORRECT)))]
"DEFAULT_ABI == ABI_DARWIN"
"addis %0,%1,ha16(%2-%3)\n\taddi %0,%0,lo16(%2-%3)"
[(set_attr "length" "8")])
@@ -10697,7 +10906,7 @@
;; all of memory. This blocks insns from being moved across this point.
(define_insn "blockage"
- [(unspec_volatile [(const_int 0)] 0)]
+ [(unspec_volatile [(const_int 0)] UNSPECV_BLOCK)]
""
"")
@@ -11123,7 +11332,7 @@
;; Same as above, but get the OV/ORDERED bit.
(define_insn "move_from_CR_ov_bit"
[(set (match_operand:SI 0 "gpc_reg_operand" "=r")
- (unspec:SI [(match_operand 1 "cc_reg_operand" "y")] 724))]
+ (unspec:SI [(match_operand 1 "cc_reg_operand" "y")] UNSPEC_MV_CR_OV))]
"TARGET_ISEL"
"%D1mfcr %0\;{rlinm|rlwinm} %0,%0,%t1,1"
[(set_attr "type" "mfcr")
@@ -14185,7 +14394,8 @@
(define_insn "movesi_from_cr"
[(set (match_operand:SI 0 "gpc_reg_operand" "=r")
(unspec:SI [(reg:CC 68) (reg:CC 69) (reg:CC 70) (reg:CC 71)
- (reg:CC 72) (reg:CC 73) (reg:CC 74) (reg:CC 75)] 19))]
+ (reg:CC 72) (reg:CC 73) (reg:CC 74) (reg:CC 75)]
+ UNSPEC_MOVESI_FROM_CR))]
""
"mfcr %0"
[(set_attr "type" "mfcr")])
@@ -14219,7 +14429,7 @@
; not be moved over stores to stack memory.
(define_insn "stack_tie"
[(set (match_operand:BLK 0 "memory_operand" "+m")
- (unspec:BLK [(match_dup 0)] 5))]
+ (unspec:BLK [(match_dup 0)] UNSPEC_TIE))]
""
""
[(set_attr "length" "0")])
@@ -14241,7 +14451,7 @@
(define_expand "movsi_to_cr_one"
[(set (match_operand:CC 0 "cc_reg_operand" "=y")
(unspec:CC [(match_operand:SI 1 "gpc_reg_operand" "r")
- (match_dup 2)] 20))]
+ (match_dup 2)] UNSPEC_MOVESI_TO_CR))]
""
"operands[2] = GEN_INT (1 << (75 - REGNO (operands[0])));")
@@ -14250,7 +14460,7 @@
[(set (match_operand:CC 1 "cc_reg_operand" "=y")
(unspec:CC [(match_operand:SI 2 "gpc_reg_operand" "r")
(match_operand 3 "immediate_operand" "n")]
- 20))])]
+ UNSPEC_MOVESI_TO_CR))])]
""
"*
{
@@ -14266,7 +14476,8 @@
(define_insn "*mtcrfsi"
[(set (match_operand:CC 0 "cc_reg_operand" "=y")
(unspec:CC [(match_operand:SI 1 "gpc_reg_operand" "r")
- (match_operand 2 "immediate_operand" "n")] 20))]
+ (match_operand 2 "immediate_operand" "n")]
+ UNSPEC_MOVESI_TO_CR))]
"GET_CODE (operands[0]) == REG
&& CR_REGNO_P (REGNO (operands[0]))
&& GET_CODE (operands[2]) == CONST_INT
@@ -14342,19 +14553,22 @@
; We can't expand this before we know where the link register is stored.
(define_insn "eh_set_lr_si"
- [(unspec_volatile [(match_operand:SI 0 "register_operand" "r")] 9)
+ [(unspec_volatile [(match_operand:SI 0 "register_operand" "r")]
+ UNSPECV_EH_RR)
(clobber (match_scratch:SI 1 "=&b"))]
"TARGET_32BIT"
"#")
(define_insn "eh_set_lr_di"
- [(unspec_volatile [(match_operand:DI 0 "register_operand" "r")] 9)
+ [(unspec_volatile [(match_operand:DI 0 "register_operand" "r")]
+ UNSPECV_EH_RR)
(clobber (match_scratch:DI 1 "=&b"))]
"TARGET_64BIT"
"#")
(define_split
- [(unspec_volatile [(match_operand 0 "register_operand" "")] 9)
+ [(unspec_volatile [(match_operand 0 "register_operand" "")]
+ UNSPECV_EH_RR)
(clobber (match_scratch 1 ""))]
"reload_completed"
[(const_int 0)]
Index: gcc/config/rs6000/sysv4.h
===================================================================
RCS file: /home/janis/gcc_rsync/gcc-cvs/gcc/gcc/config/rs6000/sysv4.h,v
retrieving revision 1.118
diff -u -p -r1.118 sysv4.h
--- gcc/config/rs6000/sysv4.h 23 Mar 2003 22:44:04 -0000 1.118
+++ gcc/config/rs6000/sysv4.h 11 Apr 2003 15:48:55 -0000
@@ -80,12 +80,15 @@ extern enum rs6000_sdata_type rs6000_sda
/* Strings provided by SUBTARGET_OPTIONS */
extern const char *rs6000_abi_name;
extern const char *rs6000_sdata_name;
+extern const char *rs6000_tls_size_string; /* For -mtls-size= */
/* Override rs6000.h definition. */
#undef SUBTARGET_OPTIONS
-#define SUBTARGET_OPTIONS \
- { "call-", &rs6000_abi_name, N_("Select ABI calling convention") }, \
- { "sdata=", &rs6000_sdata_name, N_("Select method for sdata handling") }
+#define SUBTARGET_OPTIONS \
+ { "call-", &rs6000_abi_name, N_("Select ABI calling convention") }, \
+ { "sdata=", &rs6000_sdata_name, N_("Select method for sdata handling") }, \
+ { "tls-size=", &rs6000_tls_size_string, \
+ N_("Specify bit size of immediate TLS offsets") }
/* Max # of bytes for variables to automatically be put into the .sdata
or .sdata2 sections. */
@@ -791,6 +794,8 @@ do { \
const char *_name = NAME; \
if (*_name == '@') \
_name++; \
+ else if (*_name == '%') \
+ _name += 2; \
\
if (*_name == '*') \
fprintf (FILE, "%s", _name + 1); \
More information about the Gcc-patches
mailing list