From patchwork Tue May 17 14:22:08 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nick Clifton X-Patchwork-Id: 95940 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id 392E2B6EDF for ; Wed, 18 May 2011 00:21:51 +1000 (EST) Received: (qmail 29020 invoked by alias); 17 May 2011 14:21:49 -0000 Received: (qmail 29005 invoked by uid 22791); 17 May 2011 14:21:44 -0000 X-SWARE-Spam-Status: No, hits=-5.4 required=5.0 tests=AWL, BAYES_00, KAM_STOCKGEN, RCVD_IN_DNSWL_HI, SPF_HELO_PASS, T_RP_MATCHES_RCVD, T_TVD_MIME_NO_HEADERS X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Tue, 17 May 2011 14:21:18 +0000 Received: from int-mx01.intmail.prod.int.phx2.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id p4HELIxt018354 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Tue, 17 May 2011 10:21:18 -0400 Received: from Gift.redhat.com (vpn2-11-6.ams2.redhat.com [10.36.11.6]) by int-mx01.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id p4HELE3j014121; Tue, 17 May 2011 10:21:15 -0400 From: Nick Clifton To: rth@redhat.com, law@redhat.com, aoliva@redhat.com Subject: RFA: MN10300: Add TLS support CC: gcc-patches@gcc.gnu.org Date: Tue, 17 May 2011 15:22:08 +0100 Message-ID: MIME-Version: 1.0 X-IsSubscribed: yes Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Hi Richard, Hi Jeff, Hi Alex, Here is another MN10300 patch. This ones adds support for TLS. I must confess that I did not actually write this code - DJ did - but I have been asked to submit it upstream, so here goes: OK to apply ? Cheers Nick gcc/ChangeLog 2011-05-17 DJ Delorie Nick Clifton * config/mn10300/mn10300.c (mn10300_unspec_int_label_counter): New variable. (mn10300_option_override): Disable TLS for the MN10300. (tls_symbolic_operand_kind): New function. (get_some_local_dynamic_name_1): New function. (get_some_local_dynamic_name): New function. (mn10300_print_operand): Handle %&. (mn10300_legitimize_address): Legitimize TLS addresses. (is_legitimate_tls_operand): New function. (mn10300_legitimate_pic_operand_p): TLS operands are legitimate. (mn10300_legitimate_address_p): TLS symbols do not make legitimate addresses. Allow TLS operands under some circumstances. (mn10300_legitimate_constant_p): Handle TLS UNSPECs. (mn10300_init_machine_status): New function. (mn10300_init_expanders): New function. (pic_nonpic_got_ptr): New function. (mn10300_tls_get_addr): New function. (mn10300_legitimize_tls_address): New function. (mn10300_constant_address_p): New function. (TARGET_HAVE_TLS): Define. * config/mn10300/predicates.md (tls_symbolic_operand): New. (nontls_general_operand): New. * config/mn10300/mn10300.h (enum reg_class): Add D0_REGS, A0_REGS. (REG_CLASS_NAMES): Likewise. (REG_CLASS_CONTENTS): Likewise. (struct machine_function): New structure. (INIT_EXPANDERS): Define. (mn10300_unspec_int_label_counter): New variable. (PRINT_OPERAND_PUNCT_VALID_P): Define. (CONSTANT_ADDRESS_P): Define. * config/mn10300/constraints (B): New constraint. (C): New constraint. * config/mn10300/mn10300-protos.h: Alpha sort. (mn10300_init_expanders): Prototype. (mn10300_tls_get_addr): Prototype. (mn10300_legitimize_tls_address): Prototype. (mn10300_constant_address_p): Prototype. * config/mn10300/mn10300.md (TLS_REG): New constant. (UNSPEC_INT_LABEL): New constant. (UNSPEC_TLSGD): New constant. (UNSPEC_TLSLDM): New constant. (UNSPEC_DTPOFF): New constant. (UNSPEC_GOTNTPOFF): New constant. (UNSPEC_INDNTPOFF): New constant. (UNSPEC_TPOFF): New constant. (UNSPEC_TLS_GD): New constant. (UNSPEC_TLS_LD_BASE): New constant. (movsi): Add TLS code. (tls_global_dynamic_i): New pattern. (tls_global_dynamic): New pattern. (tls_local_dynamic_base_i): New pattern. (tls_local_dynamic_base): New pattern. (tls_initial_exec): New pattern. (tls_initial_exec_1): New pattern. (tls_initial_exec_2): New pattern. (am33_set_got): New pattern. (int_label): New pattern. (am33_loadPC_anyreg): New pattern. (add_GOT_to_any_reg): New pattern. Index: gcc/config/mn10300/mn10300.c =================================================================== --- gcc/config/mn10300/mn10300.c (revision 173815) +++ gcc/config/mn10300/mn10300.c (working copy) @@ -46,7 +46,12 @@ #include "df.h" #include "opts.h" #include "cfgloop.h" +#include "ggc.h" +/* This is used by GOTaddr2picreg to uniquely identify + UNSPEC_INT_LABELs. */ +int mn10300_unspec_int_label_counter; + /* This is used in the am33_2.0-linux-gnu port, in which global symbol names are not prefixed by underscores, to tell whether to prefix a label with a plus sign or not, so that the assembler can tell @@ -124,6 +129,9 @@ target_flags &= ~MASK_MULT_BUG; else { + /* We can't do TLS if we don't have the TLS register. */ + targetm.have_tls = false; + /* Disable scheduling for the MN10300 as we do not have timing information available for it. */ flag_schedule_insns = 0; @@ -162,6 +170,51 @@ fprintf (asm_out_file, "\t.am33\n"); } +/* Returns non-zero if OP has the KIND tls model. */ + +static inline bool +tls_symbolic_operand_kind (rtx op, enum tls_model kind) +{ + if (GET_CODE (op) != SYMBOL_REF) + return false; + return SYMBOL_REF_TLS_MODEL (op) == kind; +} + +/* Locate some local-dynamic symbol still in use by this function + so that we can print its name in some tls_local_dynamic_base + pattern. This is used by "%&" in print_operand(). */ + +static int +get_some_local_dynamic_name_1 (rtx *px, void *data ATTRIBUTE_UNUSED) +{ + rtx x = *px; + + if (GET_CODE (x) == SYMBOL_REF + && tls_symbolic_operand_kind (x, TLS_MODEL_LOCAL_DYNAMIC)) + { + cfun->machine->some_ld_name = XSTR (x, 0); + return 1; + } + + return 0; +} + +static const char * +get_some_local_dynamic_name (void) +{ + rtx insn; + + if (cfun->machine->some_ld_name) + return cfun->machine->some_ld_name; + + for (insn = get_insns (); insn ; insn = NEXT_INSN (insn)) + if (NONDEBUG_INSN_P (insn) + && for_each_rtx (&PATTERN (insn), get_some_local_dynamic_name_1, 0)) + return cfun->machine->some_ld_name; + + gcc_unreachable (); +} + /* Note: This list must match the liw_op attribute in mn10300.md. */ static const char *liw_op_names[] = @@ -435,6 +488,10 @@ fprintf (file, "%d", (int)(INTVAL (x) & 0xff)); break; + case '&': + assemble_name (file, get_some_local_dynamic_name ()); + return; + /* For shift counts. The hardware ignores the upper bits of any immediate, but the assembler will flag an out of range shift count as an error. So we mask off the high bits @@ -1824,7 +1881,9 @@ mn10300_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED, enum machine_mode mode ATTRIBUTE_UNUSED) { - if (flag_pic && ! mn10300_legitimate_pic_operand_p (x)) + if (tls_symbolic_operand (x, Pmode)) + x = mn10300_legitimize_tls_address (oldx); + else if (flag_pic && ! mn10300_legitimate_pic_operand_p (x)) x = mn10300_legitimize_pic_address (oldx, NULL_RTX); /* Uh-oh. We might have an address for x[n-100000]. This needs @@ -1899,6 +1958,46 @@ return reg; } +/* Return zero if X references a SYMBOL_REF or LABEL_REF whose + symbol isn't protected by a TLS unspec; nonzero otherwise. */ + +static bool +is_legitimate_tls_operand (rtx x) +{ + const char *fmt; + int i; + + if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF) + return false; + + if (GET_CODE (x) == UNSPEC + && (XINT (x, 1) == UNSPEC_TLSGD + || XINT (x, 1) == UNSPEC_TLSLDM + || XINT (x, 1) == UNSPEC_DTPOFF + || XINT (x, 1) == UNSPEC_GOTNTPOFF + || XINT (x, 1) == UNSPEC_INDNTPOFF + || XINT (x, 1) == UNSPEC_TPOFF + )) + return true; + + fmt = GET_RTX_FORMAT (GET_CODE (x)); + for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--) + { + if (fmt[i] == 'E') + { + int j; + + for (j = XVECLEN (x, i) - 1; j >= 0; j--) + if (! is_legitimate_tls_operand (XVECEXP (x, i, j))) + return false; + } + else if (fmt[i] == 'e' && ! is_legitimate_tls_operand (XEXP (x, i))) + return false; + } + + return true; +} + /* Return zero if X references a SYMBOL_REF or LABEL_REF whose symbol isn't protected by a PIC unspec; nonzero otherwise. */ @@ -1908,6 +2007,9 @@ const char *fmt; int i; + if (is_legitimate_tls_operand (x)) + return 1; + if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF) return 0; @@ -1957,6 +2059,9 @@ { rtx base, index; + if (tls_symbolic_operand (x, Pmode)) + return false; + if (CONSTANT_ADDRESS_P (x)) return !flag_pic || mn10300_legitimate_pic_operand_p (x); @@ -1980,6 +2085,7 @@ if (!REG_P (base)) return false; + if (REG_P (index)) { /* ??? Without AM33 generalized (Ri,Rn) addressing, reg+reg @@ -1997,6 +2103,11 @@ if (CONST_INT_P (index)) return IN_RANGE (INTVAL (index), -1 - 0x7fffffff, 0x7fffffff); + if (GET_MODE_SIZE (mode) == 4 + && GET_CODE (index) != MEM + && is_legitimate_tls_operand (index)) + return true; + if (CONSTANT_ADDRESS_P (index)) return !flag_pic || mn10300_legitimate_pic_operand_p (index); @@ -2075,13 +2186,25 @@ /* Only some unspecs are valid as "constants". */ if (GET_CODE (x) == UNSPEC) { + rtx sym = XVECEXP (x, 0, 0); + switch (XINT (x, 1)) { + case UNSPEC_DTPOFF: + return tls_symbolic_operand_kind (sym, TLS_MODEL_LOCAL_DYNAMIC); + case UNSPEC_GOTNTPOFF: + case UNSPEC_INDNTPOFF: + return tls_symbolic_operand_kind (sym, TLS_MODEL_INITIAL_EXEC); + case UNSPEC_TPOFF: + return tls_symbolic_operand_kind (sym, TLS_MODEL_LOCAL_EXEC); + + case UNSPEC_INT_LABEL: case UNSPEC_PIC: case UNSPEC_GOT: case UNSPEC_GOTOFF: case UNSPEC_PLT: return true; + default: return false; } @@ -2092,6 +2215,11 @@ return false; break; + case SYMBOL_REF: + if (tls_symbolic_operand (x, Pmode)) + return false; + break; + default: break; } @@ -3315,8 +3443,148 @@ } } +static struct machine_function * +mn10300_init_machine_status (void) +{ + return ggc_alloc_cleared_machine_function (); +} + +/* Implements INIT_EXPANDERS. We just set up to call the above + function. */ + +void +mn10300_init_expanders (void) +{ + init_machine_status = mn10300_init_machine_status; +} + +/* Regardless of whether we're in PIC mode or not, return an RTX that + refers to the GOT base. In PIC mode, we return the PIC register. + In non-PIC mode, we calculate the GOT base into a pseudo and cache + it. */ + +static rtx +pic_nonpic_got_ptr (void) +{ + if (flag_pic) + return gen_rtx_REG (SImode, PIC_REG); + + if (cfun->machine->got_ptr == NULL_RTX) + { + rtx uns, insns, note, got, tmp; + + tmp = gen_reg_rtx (SImode); + got = gen_reg_rtx (SImode); + start_sequence (); + emit_insn (gen_am33_set_got (tmp)); + insns = get_insns (); + end_sequence (); + note = gen_rtx_EXPR_LIST (VOIDmode, const0_rtx, NULL); + uns = gen_rtx_SYMBOL_REF (VOIDmode, GOT_SYMBOL_NAME); + note = gen_rtx_EXPR_LIST (VOIDmode, uns, note); + emit_libcall_block (insns, got, tmp, note); + cfun->machine->got_ptr = got; + } + + return cfun->machine->got_ptr; +} + +/* Encapsulates the chosen TLS base register. */ + +rtx +mn10300_tls_get_addr (void) +{ + return gen_rtx_REG (Pmode, TLS_REG); +} + +/* Given a symbol X that has TLS linkage, convert it into a (usually) + unspec pattern that reflects the appropriate TLS access type. */ + +rtx +mn10300_legitimize_tls_address (rtx x) +{ + rtx dest, base, off, uns, a0, insns, note, got; + + switch (SYMBOL_REF_TLS_MODEL (x)) + { + case TLS_MODEL_GLOBAL_DYNAMIC: + got = pic_nonpic_got_ptr (); + a0 = gen_rtx_REG (Pmode, FIRST_ADDRESS_REGNUM); + start_sequence (); + dest = gen_reg_rtx (Pmode); + emit_call_insn (gen_tls_global_dynamic (a0, x, got)); + insns = get_insns (); + end_sequence (); + note = gen_rtx_EXPR_LIST (VOIDmode, const0_rtx, NULL); + uns = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, x), UNSPEC_TLS_GD); + note = gen_rtx_EXPR_LIST (VOIDmode, uns, note); + emit_libcall_block (insns, dest, a0, note); + if (crtl->outgoing_args_size == 0) + crtl->outgoing_args_size = 8; + break; + + case TLS_MODEL_LOCAL_DYNAMIC: + got = pic_nonpic_got_ptr (); + a0 = gen_rtx_REG (Pmode, FIRST_ADDRESS_REGNUM); + start_sequence (); + dest = gen_reg_rtx (Pmode); + base = gen_reg_rtx (Pmode); + emit_call_insn (gen_tls_local_dynamic_base (a0, x, got)); + emit_move_insn (base, a0); + insns = get_insns (); + end_sequence (); + note = gen_rtx_EXPR_LIST (VOIDmode, const0_rtx, NULL); + note = gen_rtx_EXPR_LIST (VOIDmode, GEN_INT (UNSPEC_TLS_LD_BASE), note); + emit_libcall_block (insns, base, a0, note); + + uns = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, x), UNSPEC_DTPOFF); + uns = gen_rtx_CONST (Pmode, uns); + off = gen_reg_rtx (Pmode); + emit_move_insn (off, uns); + emit_insn (gen_addsi3 (dest, off, base)); + if (crtl->outgoing_args_size == 0) + crtl->outgoing_args_size = 8; + break; + + case TLS_MODEL_INITIAL_EXEC: + dest = gen_reg_rtx (Pmode); + emit_insn (gen_tls_initial_exec (dest, x)); + insns = emit_insn (gen_addsi3 (dest, dest, mn10300_tls_get_addr ())); + break; + + case TLS_MODEL_LOCAL_EXEC: + uns = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, x), UNSPEC_TPOFF); + uns = gen_rtx_CONST (Pmode, uns); + off = gen_reg_rtx (Pmode); + emit_move_insn (off, uns); + dest = gen_reg_rtx (Pmode); + emit_insn (gen_addsi3 (dest, off, mn10300_tls_get_addr ())); + break; + + default: + abort (); + } + + return dest; +} + +/* Returns TRUE if X is a valid constant address. Used by + CONSTANT_ADDRESS_P(). This definition makes sure we don't put TLS + symbols in initializers and such. */ + +bool +mn10300_constant_address_p (rtx x) +{ + if (tls_symbolic_operand (x, Pmode)) + return false; + return CONSTANT_P (x) && GET_CODE (x) != CONST_DOUBLE; +} + /* Initialize the GCC target structure. */ +#undef TARGET_HAVE_TLS +#define TARGET_HAVE_TLS true + #undef TARGET_MACHINE_DEPENDENT_REORG #define TARGET_MACHINE_DEPENDENT_REORG mn10300_reorg @@ -3422,3 +3690,4 @@ #define TARGET_FLAGS_REGNUM CC_REG struct gcc_target targetm = TARGET_INITIALIZER; + Index: gcc/config/mn10300/predicates.md =================================================================== --- gcc/config/mn10300/predicates.md (revision 173815) +++ gcc/config/mn10300/predicates.md (working copy) @@ -67,3 +67,18 @@ (define_predicate "liw_operand" (ior (match_operand 0 "register_operand") (match_test "satisfies_constraint_O (op)"))) + +(define_predicate "tls_symbolic_operand" + (match_code "symbol_ref") +{ + return SYMBOL_REF_TLS_MODEL (op); +}) + +(define_predicate "nontls_general_operand" + (match_code "const_int,const_double,const,symbol_ref,label_ref,subreg,reg,mem") +{ + if (tls_symbolic_operand (op, mode)) + return false; + return general_operand (op, mode); +}) + Index: gcc/config/mn10300/mn10300.h =================================================================== --- gcc/config/mn10300/mn10300.h (revision 173815) +++ gcc/config/mn10300/mn10300.h (working copy) @@ -272,7 +272,7 @@ enum reg_class { - NO_REGS, DATA_REGS, ADDRESS_REGS, SP_REGS, SP_OR_ADDRESS_REGS, + NO_REGS, D0_REGS, DATA_REGS, A0_REGS, ADDRESS_REGS, SP_REGS, SP_OR_ADDRESS_REGS, EXTENDED_REGS, FP_REGS, FP_ACC_REGS, CC_REGS, MDR_REGS, GENERAL_REGS, SP_OR_GENERAL_REGS, ALL_REGS, LIM_REG_CLASSES }; @@ -282,7 +282,7 @@ /* Give names of register classes as strings for dump file. */ #define REG_CLASS_NAMES \ -{ "NO_REGS", "DATA_REGS", "ADDRESS_REGS", "SP_REGS", "SP_OR_ADDRESS_REGS", \ +{ "NO_REGS", "D0_REGS", "DATA_REGS", "A0_REGS", "ADDRESS_REGS", "SP_REGS", "SP_OR_ADDRESS_REGS", \ "EXTENDED_REGS", "FP_REGS", "FP_ACC_REGS", "CC_REGS", "MDR_REGS", \ "GENERAL_REGS", "SP_OR_GENERAL_REGS", "ALL_REGS", "LIM_REGS" \ } @@ -293,7 +293,9 @@ #define REG_CLASS_CONTENTS \ { { 0, 0 }, /* No regs */ \ + { 0x00000001, 0 }, /* D0_REGS */ \ { 0x0000000f, 0 }, /* DATA_REGS */ \ + { 0x00000010, 0 }, /* A0_REGS */ \ { 0x000001f0, 0 }, /* ADDRESS_REGS */ \ { 0x00000200, 0 }, /* SP_REGS */ \ { 0x000003f0, 0 }, /* SP_OR_ADDRESS_REGS */ \ @@ -740,3 +742,26 @@ #define FILE_ASM_OP "\t.file\n" +#ifndef GENERATOR_FILE +/* A data structure for per-function information. */ +typedef struct GTY(()) machine_function +{ + /* For non-pic use. */ + rtx got_ptr; + /* For TLS local dynamic. */ + const char * some_ld_name; +} +machine_function; +#endif + +#define INIT_EXPANDERS mn10300_init_expanders () + +extern GTY(()) int mn10300_unspec_int_label_counter; + +/* %& prints some local dynamic TLS symbol. */ + +#define PRINT_OPERAND_PUNCT_VALID_P(CODE) ((CODE) == '&') + +/* 1 if X is an rtx for a constant that is a valid address. */ + +#define CONSTANT_ADDRESS_P(X) mn10300_constant_address_p (X) Index: gcc/config/mn10300/constraints.md =================================================================== --- gcc/config/mn10300/constraints.md (revision 173815) +++ gcc/config/mn10300/constraints.md (working copy) @@ -47,6 +47,9 @@ (define_register_constraint "c" "TARGET_AM33_2 ? FP_ACC_REGS : NO_REGS" "A floating point accumulator register.") +(define_register_constraint "B" "D0_REGS" "The d0 register.") +(define_register_constraint "C" "A0_REGS" "The a0 register.") + (define_memory_constraint "Q" "@internal" (and (match_code "mem") Index: gcc/config/mn10300/mn10300-protos.h =================================================================== --- gcc/config/mn10300/mn10300-protos.h (revision 173815) +++ gcc/config/mn10300/mn10300-protos.h (working copy) @@ -20,30 +20,33 @@ . */ #ifdef RTX_CODE -extern rtx mn10300_legitimize_pic_address (rtx, rtx); -extern int mn10300_legitimate_pic_operand_p (rtx); -extern rtx mn10300_legitimize_reload_address (rtx, enum machine_mode, - int, int, int); -extern bool mn10300_function_value_regno_p (const unsigned int); -extern int mn10300_get_live_callee_saved_regs (void); -extern bool mn10300_hard_regno_mode_ok (unsigned int, enum machine_mode); -extern bool mn10300_modes_tieable (enum machine_mode, enum machine_mode); -extern const char *mn10300_output_add (rtx[3], bool); -extern void mn10300_print_operand (FILE *, rtx, int); -extern void mn10300_print_operand_address (FILE *, rtx); -extern void mn10300_print_reg_list (FILE *, int); +extern bool mn10300_constant_address_p (rtx); +extern bool mn10300_function_value_regno_p (const unsigned int); +extern int mn10300_get_live_callee_saved_regs (void); +extern bool mn10300_hard_regno_mode_ok (unsigned int, enum machine_mode); +extern rtx mn10300_legitimize_pic_address (rtx, rtx); +extern int mn10300_legitimate_pic_operand_p (rtx); +extern rtx mn10300_legitimize_reload_address (rtx, enum machine_mode, int, int, int); +extern rtx mn10300_legitimize_tls_address (rtx); +extern bool mn10300_match_ccmode (rtx, enum machine_mode); +extern bool mn10300_modes_tieable (enum machine_mode, enum machine_mode); +extern const char * mn10300_output_add (rtx[3], bool); +extern void mn10300_print_operand (FILE *, rtx, int); +extern void mn10300_print_operand_address (FILE *, rtx); +extern void mn10300_print_reg_list (FILE *, int); extern enum machine_mode mn10300_select_cc_mode (enum rtx_code, rtx, rtx); -extern int mn10300_store_multiple_operation (rtx, enum machine_mode); -extern int mn10300_symbolic_operand (rtx, enum machine_mode); -extern void mn10300_split_cbranch (enum machine_mode, rtx, rtx); -extern int mn10300_split_and_operand_count (rtx); -extern bool mn10300_match_ccmode (rtx, enum machine_mode); +extern void mn10300_split_cbranch (enum machine_mode, rtx, rtx); +extern int mn10300_split_and_operand_count (rtx); +extern int mn10300_store_multiple_operation (rtx, enum machine_mode); +extern int mn10300_symbolic_operand (rtx, enum machine_mode); +extern rtx mn10300_tls_get_addr (void); #endif /* RTX_CODE */ -extern bool mn10300_regno_in_class_p (unsigned, int, bool); +extern bool mn10300_can_use_retf_insn (void); extern bool mn10300_can_use_rets_insn (void); -extern bool mn10300_can_use_retf_insn (void); +extern void mn10300_expand_epilogue (void); extern void mn10300_expand_prologue (void); -extern void mn10300_expand_epilogue (void); +extern int mn10300_frame_size (void); +extern void mn10300_init_expanders (void); extern int mn10300_initial_offset (int, int); -extern int mn10300_frame_size (void); +extern bool mn10300_regno_in_class_p (unsigned, int, bool); Index: gcc/config/mn10300/mn10300.md =================================================================== --- gcc/config/mn10300/mn10300.md (revision 173815) +++ gcc/config/mn10300/mn10300.md (working copy) @@ -28,9 +28,11 @@ (define_constants [ (PIC_REG 6) (SP_REG 9) + (TLS_REG 12) (MDR_REG 50) (CC_REG 51) + (UNSPEC_INT_LABEL 0) (UNSPEC_PIC 1) (UNSPEC_GOT 2) (UNSPEC_GOTOFF 3) @@ -44,6 +46,18 @@ (UNSPEC_LIW 8) ;; This is for the low overhead loop instructions. (UNSPEC_SETLB 9) + + ;; These put the corresponding @op suffix on TLS variables. + (UNSPEC_TLSGD 100) + (UNSPEC_TLSLDM 101) + (UNSPEC_DTPOFF 102) + (UNSPEC_GOTNTPOFF 103) + (UNSPEC_INDNTPOFF 104) + (UNSPEC_TPOFF 105) + + ;; These are used to differentiate tls-specific insns. + (UNSPEC_TLS_GD 110) + (UNSPEC_TLS_LD_BASE 111) ]) (include "predicates.md") @@ -393,10 +407,33 @@ (match_operand:SI 1 "general_operand"))] "" { + if (tls_symbolic_operand (operands[1], Pmode)) + { + operands[1] = mn10300_legitimize_tls_address (operands[1]); + operands[1] = force_operand (operands[1], operands[0]); + if (operands[1] == operands[0]) + DONE; + } + + if (GET_CODE (operands[1]) == CONST + && GET_CODE (XEXP (operands[1], 0)) == PLUS + && tls_symbolic_operand (XEXP (XEXP (operands[1], 0), 0), Pmode)) + { + rtx plus = XEXP (XEXP (operands[1], 0), 1); + rtx tls = XEXP (XEXP (operands[1], 0), 0); + + operands[1] = mn10300_legitimize_tls_address (tls); + operands[1] = gen_rtx_PLUS (SImode, operands[1], plus); + operands[1] = force_operand (operands[1], operands[0]); + if (operands[1] == operands[0]) + DONE; + } + /* One of the ops has to be in a register. */ if (!register_operand (operand1, SImode) && !register_operand (operand0, SImode)) operands[1] = force_reg (SImode, operand1); + if (flag_pic) { rtx temp; @@ -432,7 +469,7 @@ (define_insn "*movsi_internal" [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,r,m,r, A,*y,*y,*z,*d") - (match_operand:SI 1 "general_operand" + (match_operand:SI 1 "nontls_general_operand" " 0,O,i,r,r,m,*y, A, i,*d,*z"))] "register_operand (operands[0], SImode) || register_operand (operands[1], SImode)" @@ -2204,3 +2241,188 @@ "FL%b0 # loop back to: %1" [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34") (const_int 44) (const_int 11)))] ) + +; We clobber d0 instead of passing it as a parameter so that gcc will +; know that it doesn't have to set a value in it. We use constraints +; to specify it as reload avoids regs that are mentioned explicitly. +; Whoever emits this is responsible for moving the result out of a0 +; into a pseudo, else reload complains sometimes. We use PIC_REG so +; that gcc won't delete the prologue insns that set it. We don't +; split the insns because relaxation requires this specific insn +; sequence. + +(define_insn "tls_global_dynamic_i" + [(parallel + [(set (match_operand:SI 0 "register_operand" "=C") + (call (unspec:SI + [(match_operand:SI 1 "tls_symbolic_operand" "") + (match_operand:SI 2 "register_operand" "a") + (match_operand 4 "register_operand" "")] + UNSPEC_TLS_GD) + (const_int 0))) + (clobber (match_operand 3 "register_operand" "=B"))]) + ] + "" + { + if (flag_pic) + return "mov %1@tlsgd, %3\;add %2, %3\;call __tls_get_addr@PLT,[],0"; + return "mov %1@tlsgd, %3\;add %2, %3\;call __tls_get_addr,[],0"; + } + ;; Timings: AM33 AM34 + ;; MOV 4 3 (latency invoked because ADD uses %3) + ;; ADD 1 1 + ;; CALL 3 5 + ;; ------------------- + ;; total 8 9 + [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34") (const_int 99) (const_int 88)))] +) + +(define_expand "tls_global_dynamic" + [(parallel + [(set (match_operand:SI 0 "register_operand" "") + (call (unspec:SI + [(match_operand:SI 1 "tls_symbolic_operand" "") + (match_operand:SI 2 "register_operand" "") + (match_dup 4)] + UNSPEC_TLS_GD) + (const_int 0))) + (clobber (match_dup 3))]) + ] + "" + { + operands[3] = gen_reg_rtx (SImode); + operands[4] = mn10300_tls_get_addr (); + } +) + +(define_insn "tls_local_dynamic_base_i" + [(parallel + [(set (match_operand:SI 0 "register_operand" "=C") + (call (unspec:SI + [(match_operand:SI 1 "tls_symbolic_operand" "") + (match_operand:SI 2 "register_operand" "a") + (match_operand 4 "register_operand" "")] + UNSPEC_TLS_LD_BASE) + (const_int 0))) + (clobber (match_operand 3 "register_operand" "=B"))]) + ] + "" + { + if (flag_pic) + return "mov %&@tlsldm, %3\;add %2, %3\;call __tls_get_addr@PLT,[],0"; + return "mov %&@tlsldm, %3\;add %2, %3\;call __tls_get_addr,[],0"; + } + ;; Timings: AM33 AM34 + ;; MOV 4 3 (latency invoked because ADD uses %3) + ;; ADD 1 1 + ;; CALL 3 5 + ;; ------------------- + ;; total 8 9 + [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34") (const_int 99) (const_int 88)))] +) + +(define_expand "tls_local_dynamic_base" + [(parallel + [(set (match_operand:SI 0 "register_operand" "") + (call (unspec:SI + [(match_operand:SI 1 "tls_symbolic_operand" "") + (match_operand:SI 2 "register_operand" "") + (match_dup 4)] + UNSPEC_TLS_LD_BASE) + (const_int 0))) + (clobber (match_dup 3))]) + ] + "" + { + operands[3] = gen_reg_rtx (SImode); + operands[4] = mn10300_tls_get_addr (); + } +) + +(define_expand "tls_initial_exec" + [(match_operand:SI 0 "" "") + (match_operand:SI 1 "" "")] + "" + " + { + rtx insn; + + if (flag_pic) + insn = emit_insn (gen_tls_initial_exec_1 (operands[0], operands[1])); + else + insn = emit_insn (gen_tls_initial_exec_2 (operands[0], operands[1])); + + MEM_READONLY_P (SET_SRC (PATTERN (insn))) = 1; + + DONE; + }" +) + +(define_expand "tls_initial_exec_1" + [(set (match_operand:SI 0 "" "") + (mem:SI (plus:SI (reg:SI PIC_REG) + (const (unspec [(match_operand:SI 1 "" "")] + UNSPEC_GOTNTPOFF))))) + ] + "" + "" +) + +(define_expand "tls_initial_exec_2" + [(set (match_operand:SI 0 "" "") + (mem:SI (const (unspec [(match_operand:SI 1 "" "")] + UNSPEC_INDNTPOFF)))) + ] + "" + "" +) + +;; Used for non-pic code; will store in any register. +(define_expand "am33_set_got" + [(match_operand:SI 0 "" "") + (match_dup 1) + ] + "TARGET_AM33" + " + { + rtx tmp = gen_reg_rtx (SImode); + + operands[1] = gen_int_label (GEN_INT (mn10300_unspec_int_label_counter++)); + emit_insn (gen_am33_loadPC_anyreg (tmp, operands[1])); + emit_insn (gen_add_GOT_to_any_reg (operands[0], tmp, operands[1])); + DONE; + }" +) + +(define_expand "int_label" + [(unspec [(match_operand:SI 0 "" "")] UNSPEC_INT_LABEL)] + "" + "" +) + +(define_insn "am33_loadPC_anyreg" + [(parallel + [(set (match_operand 0 "register_operand" "=a") (pc)) + (use (match_operand 1 "" ""))])] + "TARGET_AM33" + "%1:\;mov pc, %0" + ;; [(set_attr "timings" "11")] +) + +(define_expand "add_GOT_to_any_reg" + [(parallel [(set (match_operand:SI 0 "" "") + (plus:SI + (match_operand:SI 1 "" "") + (const + (unspec [(minus:SI + (match_dup 3) + (const (minus:SI + (const (match_operand:SI 2 "" "")) + (pc)))) + ] UNSPEC_PIC)))) + (clobber (reg:CC CC_REG)) + ]) + ] + "" + "operands[3] = gen_rtx_SYMBOL_REF (VOIDmode, GOT_SYMBOL_NAME);" +)