From 8cc9a5a584a57e06f1e2c83cb8ccd18a02a1bc91 Mon Sep 17 00:00:00 2001 From: "Edgar E. Iglesias" Date: Thu, 14 Mar 2013 15:43:23 +0000 Subject: [PATCH] Add support for TLS in MicroBlaze * configure.ac: Add MicroBlaze TLS support detection. * configure: Regenerate. * config/microblaze/microblaze-protos.h: (microblaze_cannot_force_const_mem, microblaze_tls_referenced_p, symbol_mentioned_p, label_mentioned_p): Add prototypes. * config/microblaze/microblaze.c (microblaze_address_type): Add ADDRESS_TLS and tls_reloc address types. (microblaze_address_info): Add tls_reloc. (TARGET_HAVE_TLS): Define. (get_tls_get_addr, microblaze_tls_symbol_p, microblaze_tls_operand_p_1, microblaze_tls_referenced_p, microblaze_cannot_force_const_mem, symbol_mentioned_p, label_mentioned_p, tls_mentioned_p, load_tls_operand, microblaze_call_tls_get_addr, microblaze_legitimize_tls_address): New functions. (microblaze_classify_unspec): Handle UNSPEC_TLS. (get_base_reg): Use microblaze_tls_symbol_p. (microblaze_classify_address): Handle TLS. (microblaze_legitimate_pic_operand): Use symbol_mentioned_p, label_mentioned_p and microblaze_tls_referenced_p. (microblaze_legitimize_address): Handle TLS. (microblaze_address_insns): Handle ADDRESS_TLS. (pic_address_needs_scratch): Handle TLS. (print_operand_address): Handle TLS. (microblaze_expand_prologue): Check TLS_NEEDS_GOT. (microblaze_expand_move): Handle TLS. (microblaze_legitimate_constant_p): Check microblaze_cannot_force_const_mem and microblaze_tls_symbol_p. (TARGET_CANNOT_FORCE_CONST_MEM): Define. * config/microblaze/microblaze.h (TLS_NEEDS_GOT): Define (PIC_OFFSET_TABLE_REGNUM): Set. * config/microblaze/linux.h (TLS_NEEDS_GOT): Define. * config/microblaze/microblaze.md (UNSPEC_TLS): Define. (addsi3, movsi_internal2, movdf_internal): Update constraints * config/microblaze/predicates.md (arith_plus_operand): Define (move_operand): Redefine as move_src_operand, check microblaze_tls_referenced_p. Co-Authored-By: David Holsgrove From-SVN: r196659 --- gcc/ChangeLog | 38 ++ gcc/config/microblaze/linux.h | 3 + gcc/config/microblaze/microblaze-protos.h | 4 + gcc/config/microblaze/microblaze.c | 596 ++++++++++++++++++---- gcc/config/microblaze/microblaze.h | 7 +- gcc/config/microblaze/microblaze.md | 19 +- gcc/config/microblaze/predicates.md | 57 ++- gcc/configure | 12 + gcc/configure.ac | 12 + 9 files changed, 623 insertions(+), 125 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 19ecdba0b88..c7639ea470a 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,41 @@ +2013-03-14 Edgar E. Iglesias + David Holsgrove + + * configure.ac: Add MicroBlaze TLS support detection. + * configure: Regenerate. + * config/microblaze/microblaze-protos.h: (microblaze_cannot_force_const_mem, + microblaze_tls_referenced_p, symbol_mentioned_p, label_mentioned_p): + Add prototypes. + * config/microblaze/microblaze.c (microblaze_address_type): Add ADDRESS_TLS + and tls_reloc address types. + (microblaze_address_info): Add tls_reloc. + (TARGET_HAVE_TLS): Define. + (get_tls_get_addr, microblaze_tls_symbol_p, microblaze_tls_operand_p_1, + microblaze_tls_referenced_p, microblaze_cannot_force_const_mem, + symbol_mentioned_p, label_mentioned_p, tls_mentioned_p, load_tls_operand, + microblaze_call_tls_get_addr, microblaze_legitimize_tls_address): New functions. + (microblaze_classify_unspec): Handle UNSPEC_TLS. + (get_base_reg): Use microblaze_tls_symbol_p. + (microblaze_classify_address): Handle TLS. + (microblaze_legitimate_pic_operand): Use symbol_mentioned_p, label_mentioned_p + and microblaze_tls_referenced_p. + (microblaze_legitimize_address): Handle TLS. + (microblaze_address_insns): Handle ADDRESS_TLS. + (pic_address_needs_scratch): Handle TLS. + (print_operand_address): Handle TLS. + (microblaze_expand_prologue): Check TLS_NEEDS_GOT. + (microblaze_expand_move): Handle TLS. + (microblaze_legitimate_constant_p): Check microblaze_cannot_force_const_mem + and microblaze_tls_symbol_p. + (TARGET_CANNOT_FORCE_CONST_MEM): Define. + * config/microblaze/microblaze.h (TLS_NEEDS_GOT): Define + (PIC_OFFSET_TABLE_REGNUM): Set. + * config/microblaze/linux.h (TLS_NEEDS_GOT): Define. + * config/microblaze/microblaze.md (UNSPEC_TLS): Define. + (addsi3, movsi_internal2, movdf_internal): Update constraints + * config/microblaze/predicates.md (arith_plus_operand): Define + (move_operand): Redefine as move_src_operand, check microblaze_tls_referenced_p. + 2013-03-14 Ian Bolton * config/aarch64/aarch64.md: (*and3nr_compare0): Use CC_NZ. diff --git a/gcc/config/microblaze/linux.h b/gcc/config/microblaze/linux.h index eca777640a7..a7b7a1adcfa 100644 --- a/gcc/config/microblaze/linux.h +++ b/gcc/config/microblaze/linux.h @@ -22,6 +22,9 @@ #undef TARGET_SUPPORTS_PIC #define TARGET_SUPPORTS_PIC 1 +#undef TLS_NEEDS_GOT +#define TLS_NEEDS_GOT 1 + #define DYNAMIC_LINKER "/lib/ld.so.1" #undef SUBTARGET_EXTRA_SPECS #define SUBTARGET_EXTRA_SPECS \ diff --git a/gcc/config/microblaze/microblaze-protos.h b/gcc/config/microblaze/microblaze-protos.h index e19939f0930..34be76ffa63 100644 --- a/gcc/config/microblaze/microblaze-protos.h +++ b/gcc/config/microblaze/microblaze-protos.h @@ -50,6 +50,10 @@ extern void microblaze_declare_object (FILE *, const char *, const char *, const char *, int); extern void microblaze_asm_output_ident (const char *); extern int microblaze_legitimate_pic_operand (rtx); +extern bool microblaze_tls_referenced_p (rtx); +extern int symbol_mentioned_p (rtx); +extern int label_mentioned_p (rtx); +extern bool microblaze_cannot_force_const_mem (enum machine_mode, rtx); #endif /* RTX_CODE */ /* Declare functions in microblaze-c.c. */ diff --git a/gcc/config/microblaze/microblaze.c b/gcc/config/microblaze/microblaze.c index 3a5299410b9..c121c2baec3 100644 --- a/gcc/config/microblaze/microblaze.c +++ b/gcc/config/microblaze/microblaze.c @@ -84,7 +84,8 @@ enum microblaze_address_type ADDRESS_CONST_INT, ADDRESS_SYMBOLIC, ADDRESS_GOTOFF, - ADDRESS_PLT + ADDRESS_PLT, + ADDRESS_TLS }; /* Classifies symbols @@ -98,6 +99,15 @@ enum microblaze_symbol_type SYMBOL_TYPE_GENERAL }; +/* TLS Address Type. */ +enum tls_reloc { + TLS_GD, + TLS_LDM, + TLS_DTPREL, + TLS_IE, + TLS_LE +}; + /* Classification of a MicroBlaze address. */ struct microblaze_address_info { @@ -108,6 +118,7 @@ struct microblaze_address_info rtx offset; /* Contains valid values on ADDRESS_CONST_INT and ADDRESS_REG. */ rtx symbol; /* Contains valid values on ADDRESS_SYMBOLIC. */ enum microblaze_symbol_type symbol_type; + enum tls_reloc tls_type; }; /* Structure to be filled in by compute_frame_size with register @@ -215,6 +226,11 @@ static int microblaze_interrupt_function_p (tree); section *sdata2_section; +#ifdef HAVE_AS_TLS +#undef TARGET_HAVE_TLS +#define TARGET_HAVE_TLS true +#endif + /* Return truth value if a CONST_DOUBLE is ok to be a legitimate constant. */ static bool microblaze_const_double_ok (rtx op, enum machine_mode mode) @@ -287,6 +303,9 @@ simple_memory_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) plus0 = XEXP (addr, 0); plus1 = XEXP (addr, 1); + if (GET_CODE (plus0) != REG) + return 0; + if (GET_CODE (plus0) == REG && GET_CODE (plus1) == CONST_INT && SMALL_INT (plus1)) { @@ -386,6 +405,225 @@ microblaze_valid_base_register_p (rtx x, && microblaze_regno_ok_for_base_p (REGNO (x), strict)); } +/* Build the SYMBOL_REF for __tls_get_addr. */ + +static GTY(()) rtx tls_get_addr_libfunc; + +static rtx +get_tls_get_addr (void) +{ + if (!tls_get_addr_libfunc) + tls_get_addr_libfunc = init_one_libfunc ("__tls_get_addr"); + return tls_get_addr_libfunc; +} + +/* Return TRUE if X is a thread-local symbol. */ +bool +microblaze_tls_symbol_p (rtx x) +{ + if (!TARGET_HAVE_TLS) + return false; + + if (GET_CODE (x) != SYMBOL_REF) + return false; + + return SYMBOL_REF_TLS_MODEL (x) != 0; +} + +static int +microblaze_tls_operand_p_1 (rtx *x, void *data ATTRIBUTE_UNUSED) +{ + if (GET_CODE (*x) == SYMBOL_REF) + return SYMBOL_REF_TLS_MODEL (*x) != 0; + + /* Don't recurse into UNSPEC_TLS looking for TLS symbols; these are + TLS offsets, not real symbol references. */ + if (GET_CODE (*x) == UNSPEC && XINT (*x, 1) == UNSPEC_TLS) + return -1; + + return 0; +} + +/* Return TRUE if X contains any TLS symbol references. */ + +bool +microblaze_tls_referenced_p (rtx x) +{ + if (!TARGET_HAVE_TLS) + return false; + + return for_each_rtx (&x, microblaze_tls_operand_p_1, NULL); +} + +bool +microblaze_cannot_force_const_mem (enum machine_mode mode ATTRIBUTE_UNUSED, rtx x) +{ + return microblaze_tls_referenced_p(x); +} + +/* Return TRUE if X references a SYMBOL_REF. */ +int +symbol_mentioned_p (rtx x) +{ + const char * fmt; + int i; + + if (GET_CODE (x) == SYMBOL_REF) + return 1; + + /* UNSPEC entries for a symbol include the SYMBOL_REF, but they + are constant offsets, not symbols. */ + if (GET_CODE (x) == UNSPEC) + return 0; + + 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 (symbol_mentioned_p (XVECEXP (x, i, j))) + return 1; + } + else if (fmt[i] == 'e' && symbol_mentioned_p (XEXP (x, i))) + return 1; + } + + return 0; +} + +/* Return TRUE if X references a LABEL_REF. */ +int +label_mentioned_p (rtx x) +{ + const char * fmt; + int i; + + if (GET_CODE (x) == LABEL_REF) + return 1; + + /* UNSPEC entries for a symbol include a LABEL_REF for the referencing + instruction, but they are constant offsets, not symbols. */ + if (GET_CODE (x) == UNSPEC) + return 0; + + 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 (label_mentioned_p (XVECEXP (x, i, j))) + return 1; + } + else if (fmt[i] == 'e' && label_mentioned_p (XEXP (x, i))) + return 1; + } + + return 0; +} + +int +tls_mentioned_p (rtx x) +{ + switch (GET_CODE (x)) + { + case CONST: + return tls_mentioned_p (XEXP (x, 0)); + + case UNSPEC: + if (XINT (x, 1) == UNSPEC_TLS) + return 1; + + default: + return 0; + } +} + +static rtx +load_tls_operand (rtx x, rtx reg) +{ + rtx tmp; + + if (reg == NULL_RTX) + reg = gen_reg_rtx (Pmode); + + tmp = gen_rtx_CONST (Pmode, x); + + emit_insn (gen_rtx_SET (VOIDmode, reg, + gen_rtx_PLUS (Pmode, pic_offset_table_rtx, tmp))); + + return reg; +} + +static rtx +microblaze_call_tls_get_addr (rtx x, rtx reg, rtx *valuep, int reloc) +{ + rtx insns, tls_entry; + + df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true); + + start_sequence (); + + tls_entry = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, x, GEN_INT (reloc)), + UNSPEC_TLS); + + reg = load_tls_operand (tls_entry, reg); + + *valuep = emit_library_call_value (get_tls_get_addr (), NULL_RTX, + LCT_PURE, /* LCT_CONST? */ + Pmode, 1, reg, Pmode); + + insns = get_insns (); + end_sequence (); + + return insns; +} + +rtx +microblaze_legitimize_tls_address(rtx x, rtx reg) +{ + rtx dest, insns, ret, eqv, addend; + enum tls_model model; + model = SYMBOL_REF_TLS_MODEL (x); + + switch (model) + { + case TLS_MODEL_LOCAL_DYNAMIC: + case TLS_MODEL_GLOBAL_DYNAMIC: + case TLS_MODEL_INITIAL_EXEC: + insns = microblaze_call_tls_get_addr (x, reg, &ret, TLS_GD); + dest = gen_reg_rtx (Pmode); + emit_libcall_block (insns, dest, ret, x); + break; + + case TLS_MODEL_LOCAL_EXEC: + insns = microblaze_call_tls_get_addr (x, reg, &ret, TLS_LDM); + + /* Attach a unique REG_EQUIV, to allow the RTL optimizers to + share the LDM result with other LD model accesses. */ + eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const1_rtx), UNSPEC_TLS); + dest = gen_reg_rtx (Pmode); + emit_libcall_block (insns, dest, ret, eqv); + + /* Load the addend. */ + addend = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, x, GEN_INT (TLS_DTPREL)), + UNSPEC_TLS); + addend = force_reg (SImode, gen_rtx_CONST (SImode, addend)); + dest = gen_rtx_PLUS (Pmode, dest, addend); + break; + + default: + gcc_unreachable (); + } + return dest; +} + static bool microblaze_classify_unspec (struct microblaze_address_info *info, rtx x) { @@ -401,6 +639,11 @@ microblaze_classify_unspec (struct microblaze_address_info *info, rtx x) { info->type = ADDRESS_PLT; } + else if (XINT (x, 1) == UNSPEC_TLS) + { + info->type = ADDRESS_TLS; + info->tls_type = tls_reloc INTVAL(XVECEXP(x, 0, 1)); + } else { return false; @@ -431,7 +674,12 @@ static int get_base_reg (rtx x) { tree decl; - int base_reg = (flag_pic ? MB_ABI_PIC_ADDR_REGNUM : MB_ABI_BASE_REGNUM); + int base_reg; + + if (!flag_pic || microblaze_tls_symbol_p(x)) + base_reg = MB_ABI_BASE_REGNUM; + else if (flag_pic) + base_reg = MB_ABI_PIC_ADDR_REGNUM; if (TARGET_XLGPOPT && GET_CODE (x) == SYMBOL_REF @@ -509,28 +757,61 @@ microblaze_classify_address (struct microblaze_address_info *info, rtx x, } else if (GET_CODE (xplus1) == UNSPEC) { + /* Need offsettable address. */ + if (GET_MODE_SIZE (mode) > UNITS_PER_WORD) + return false; + return microblaze_classify_unspec (info, xplus1); } else if ((GET_CODE (xplus1) == SYMBOL_REF || - GET_CODE (xplus1) == LABEL_REF) && flag_pic == 2) - { - return false; - } - else if (GET_CODE (xplus1) == SYMBOL_REF || - GET_CODE (xplus1) == LABEL_REF || - GET_CODE (xplus1) == CONST) + GET_CODE (xplus1) == LABEL_REF)) { - if (GET_CODE (XEXP (xplus1, 0)) == UNSPEC) - return microblaze_classify_unspec (info, XEXP (xplus1, 0)); - else if (flag_pic == 2) - { - return false; - } + if (flag_pic == 2 || microblaze_tls_symbol_p(xplus1)) + return false; info->type = ADDRESS_SYMBOLIC; info->symbol = xplus1; info->symbol_type = SYMBOL_TYPE_GENERAL; return true; } + else if (GET_CODE (xplus1) == CONST) + { + rtx xconst0 = XEXP(xplus1, 0); + + /* base + unspec. */ + if (GET_CODE (xconst0) == UNSPEC) + { + /* Need offsettable address. */ + if (GET_MODE_SIZE (mode) > UNITS_PER_WORD) + return false; + return microblaze_classify_unspec(info, xconst0); + } + + /* for (plus x const_int) just look at x. */ + if (GET_CODE (xconst0) == PLUS + && GET_CODE (XEXP (xconst0, 1)) == CONST_INT + && SMALL_INT (XEXP (xconst0, 1))) + { + /* This is ok as info->symbol is set to xplus1 the full + const-expression below. */ + xconst0 = XEXP (xconst0, 0); + } + + if (GET_CODE (xconst0) == SYMBOL_REF + || GET_CODE (xconst0) == LABEL_REF) + { + if (flag_pic == 2 || microblaze_tls_symbol_p(xconst0)) + return false; + + info->type = ADDRESS_SYMBOLIC; + info->symbol = xplus1; + info->symbol_type = SYMBOL_TYPE_GENERAL; + return true; + } + + /* Not base + symbol || base + UNSPEC. */ + return false; + + } else if (GET_CODE (xplus1) == REG && microblaze_valid_index_register_p (xplus1, mode, strict) @@ -562,13 +843,20 @@ microblaze_classify_address (struct microblaze_address_info *info, rtx x, if (GET_CODE (x) == CONST) { - return !(flag_pic && pic_address_needs_scratch (x)); - } - else if (flag_pic == 2) - { - return false; + if (GET_CODE (XEXP (x, 0)) == UNSPEC) + { + info->regA = gen_rtx_raw_REG (mode, + get_base_reg (XVECEXP (XEXP (x,0), 0, 0))); + return microblaze_classify_unspec (info, XEXP (x, 0)); + } + return !(flag_pic && pic_address_needs_scratch (x)); } + if (flag_pic == 2) + return false; + else if (microblaze_tls_symbol_p(x)) + return false; + return true; } @@ -616,11 +904,10 @@ microblaze_valid_pic_const (rtx x) int microblaze_legitimate_pic_operand (rtx x) { - struct microblaze_address_info addr; - - if (pic_address_needs_scratch (x)) + if (flag_pic == 2 && (symbol_mentioned_p(x) || label_mentioned_p(x))) return 0; - if (!microblaze_valid_pic_const(x)) + + if (microblaze_tls_referenced_p(x)) return 0; return 1; @@ -706,7 +993,7 @@ microblaze_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED, return result; } - if (code0 == REG && REG_OK_FOR_BASE_P (xplus0) && flag_pic == 2) + if (code0 == REG && REG_OK_FOR_BASE_P (xplus0)) { if (reload_in_progress) df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true); @@ -717,26 +1004,58 @@ microblaze_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED, } if (code1 == SYMBOL_REF) { - result = - gen_rtx_UNSPEC (Pmode, gen_rtvec (1, xplus1), UNSPEC_GOTOFF); - result = gen_rtx_CONST (Pmode, result); - result = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, result); - result = gen_const_mem (Pmode, result); - result = gen_rtx_PLUS (Pmode, xplus0, result); - return result; + if (microblaze_tls_symbol_p(xplus1)) + { + rtx tls_ref, reg; + reg = gen_reg_rtx (Pmode); + + tls_ref = microblaze_legitimize_tls_address (xplus1, + NULL_RTX); + emit_move_insn (reg, tls_ref); + + result = gen_rtx_PLUS (Pmode, xplus0, reg); + + return result; + } + else if (flag_pic == 2) + { + rtx pic_ref, reg; + reg = gen_reg_rtx (Pmode); + + pic_ref = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, xplus1), + UNSPEC_GOTOFF); + pic_ref = gen_rtx_CONST (Pmode, pic_ref); + pic_ref = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, pic_ref); + pic_ref = gen_const_mem (Pmode, pic_ref); + emit_move_insn (reg, pic_ref); + result = gen_rtx_PLUS (Pmode, xplus0, reg); + return result; + } } } } if (GET_CODE (xinsn) == SYMBOL_REF) { - if (reload_in_progress) - df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true); - result = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, xinsn), UNSPEC_GOTOFF); - result = gen_rtx_CONST (Pmode, result); - result = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, result); - result = gen_const_mem (Pmode, result); - return result; + rtx reg; + if (microblaze_tls_symbol_p(xinsn)) + { + reg = microblaze_legitimize_tls_address (xinsn, NULL_RTX); + } + else + { + rtx pic_ref; + + if (reload_in_progress) + df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true); + + pic_ref = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, xinsn), UNSPEC_GOTOFF); + pic_ref = gen_rtx_CONST (Pmode, pic_ref); + pic_ref = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, pic_ref); + pic_ref = gen_const_mem (Pmode, pic_ref); + reg = pic_ref; + } + return reg; } return x; @@ -1061,10 +1380,22 @@ microblaze_address_insns (rtx x, enum machine_mode mode) else return 2; case ADDRESS_REG_INDEX: - case ADDRESS_SYMBOLIC: return 1; + case ADDRESS_SYMBOLIC: case ADDRESS_GOTOFF: return 2; + case ADDRESS_TLS: + switch (addr.tls_type) + { + case TLS_GD: + return 2; + case TLS_LDM: + return 2; + case TLS_DTPREL: + return 1; + default : + abort(); + } default: break; } @@ -1088,13 +1419,18 @@ microblaze_address_cost (rtx addr, enum machine_mode mode ATTRIBUTE_UNUSED, int pic_address_needs_scratch (rtx x) { - /* An address which is a symbolic plus a non SMALL_INT needs a temp reg. */ - if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS - && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF - && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT - && (flag_pic == 2 || !SMALL_INT (XEXP (XEXP (x, 0), 1)))) - return 1; + if (GET_CODE (x) == CONST && GET_CODE (XEXP (x,0)) == PLUS) + { + rtx p0, p1; + p0 = XEXP (XEXP (x, 0), 0); + p1 = XEXP (XEXP (x, 0), 1); + + if ((GET_CODE (p0) == SYMBOL_REF || GET_CODE (p0) == LABEL_REF) + && (GET_CODE (p1) == CONST_INT) + && (flag_pic == 2 || microblaze_tls_symbol_p (p0) || !SMALL_INT (p1))) + return 1; + } return 0; } @@ -1918,6 +2254,7 @@ print_operand (FILE * file, rtx op, int letter) case ADDRESS_CONST_INT: case ADDRESS_SYMBOLIC: case ADDRESS_GOTOFF: + case ADDRESS_TLS: fputs ("i", file); break; case ADDRESS_REG_INDEX: @@ -2034,10 +2371,19 @@ print_operand (FILE * file, rtx op, int letter) else if (letter == 't') fputs (code == EQ ? "t" : "f", file); - else if (code == CONST && GET_CODE (XEXP (op, 0)) == REG) + else if (code == CONST + && ((GET_CODE (XEXP (op, 0)) == REG) + || (GET_CODE (XEXP (op, 0)) == UNSPEC))) { print_operand (file, XEXP (op, 0), letter); } + else if (code == CONST + && (GET_CODE (XEXP (op, 0)) == PLUS) + && (GET_CODE (XEXP (XEXP (op, 0), 0)) == REG) + && (GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST)) + { + print_operand_address (file, XEXP (op, 0)); + } else if (letter == 'm') fprintf (file, HOST_WIDE_INT_PRINT_DEC, (1L << INTVAL (op))); else @@ -2098,6 +2444,7 @@ print_operand_address (FILE * file, rtx addr) case ADDRESS_SYMBOLIC: case ADDRESS_GOTOFF: case ADDRESS_PLT: + case ADDRESS_TLS: if (info.regA) fprintf (file, "%s,", reg_names[REGNO (info.regA)]); output_addr_const (file, info.symbol); @@ -2109,6 +2456,24 @@ print_operand_address (FILE * file, rtx addr) { fputs ("@PLT", file); } + else if (type == ADDRESS_TLS) + { + switch (info.tls_type) + { + case TLS_GD: + fputs ("@TLSGD", file); + break; + case TLS_LDM: + fputs ("@TLSLDM", file); + break; + case TLS_DTPREL: + fputs ("@TLSDTPREL", file); + break; + default : + abort(); + break; + } + } break; case ADDRESS_INVALID: fatal_insn ("invalid address", addr); @@ -2471,7 +2836,8 @@ microblaze_expand_prologue (void) } } - if (flag_pic == 2 && df_regs_ever_live_p (MB_ABI_PIC_ADDR_REGNUM)) + if ((flag_pic == 2 || TLS_NEEDS_GOT ) + && df_regs_ever_live_p (MB_ABI_PIC_ADDR_REGNUM)) { SET_REGNO (pic_offset_table_rtx, MB_ABI_PIC_ADDR_REGNUM); emit_insn (gen_set_got (pic_offset_table_rtx)); /* setting GOT. */ @@ -2701,83 +3067,62 @@ expand_pic_symbol_ref (enum machine_mode mode ATTRIBUTE_UNUSED, rtx op) bool microblaze_expand_move (enum machine_mode mode, rtx operands[]) { + rtx op0, op1; + + op0 = operands[0]; + op1 = operands[1]; + + if (!register_operand (op0, SImode) + && !register_operand (op1, SImode) + && (GET_CODE (op1) != CONST_INT || INTVAL (op1) != 0)) + { + rtx temp = force_reg (SImode, op1); + emit_move_insn (op0, temp); + return true; + } /* If operands[1] is a constant address invalid for pic, then we need to handle it just like LEGITIMIZE_ADDRESS does. */ - if (flag_pic) + if (GET_CODE (op1) == SYMBOL_REF || GET_CODE (op1) == LABEL_REF) { - if (GET_CODE (operands[0]) == MEM) + rtx result; + if (microblaze_tls_symbol_p(op1)) { - rtx addr = XEXP (operands[0], 0); - if (GET_CODE (addr) == SYMBOL_REF) - { - rtx ptr_reg, result; - - if (reload_in_progress) - df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true); - - addr = expand_pic_symbol_ref (mode, addr); - ptr_reg = gen_reg_rtx (Pmode); - emit_move_insn (ptr_reg, addr); - result = gen_rtx_MEM (mode, ptr_reg); - operands[0] = result; - } + result = microblaze_legitimize_tls_address (op1, NULL_RTX); + emit_move_insn (op0, result); + return true; } - if (GET_CODE (operands[1]) == SYMBOL_REF - || GET_CODE (operands[1]) == LABEL_REF) + else if (flag_pic) { - rtx result; if (reload_in_progress) df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true); - result = expand_pic_symbol_ref (mode, operands[1]); - if (GET_CODE (operands[0]) != REG) - { - rtx ptr_reg = gen_reg_rtx (Pmode); - emit_move_insn (ptr_reg, result); - emit_move_insn (operands[0], ptr_reg); - } - else - { - emit_move_insn (operands[0], result); - } + result = expand_pic_symbol_ref (mode, op1); + emit_move_insn (op0, result); return true; } - else if (GET_CODE (operands[1]) == MEM && - GET_CODE (XEXP (operands[1], 0)) == SYMBOL_REF) - { - rtx result; - rtx ptr_reg; - if (reload_in_progress) - df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true); - result = expand_pic_symbol_ref (mode, XEXP (operands[1], 0)); + } + /* Handle Case of (const (plus symbol const_int)). */ + if (GET_CODE (op1) == CONST && GET_CODE (XEXP (op1,0)) == PLUS) + { + rtx p0, p1; - ptr_reg = gen_reg_rtx (Pmode); + p0 = XEXP (XEXP (op1, 0), 0); + p1 = XEXP (XEXP (op1, 0), 1); - emit_move_insn (ptr_reg, result); - result = gen_rtx_MEM (mode, ptr_reg); - emit_move_insn (operands[0], result); - return true; - } - else if (pic_address_needs_scratch (operands[1])) + if ((GET_CODE (p1) == CONST_INT) + && ((GET_CODE (p0) == UNSPEC) + || ((GET_CODE (p0) == SYMBOL_REF || GET_CODE (p0) == LABEL_REF) + && (flag_pic == 2 || microblaze_tls_symbol_p (p0) + || !SMALL_INT (p1))))) { - rtx temp = force_reg (SImode, XEXP (XEXP (operands[1], 0), 0)); - rtx temp2 = XEXP (XEXP (operands[1], 0), 1); + rtx temp = force_reg (SImode, p0); + rtx temp2 = p1; - if (reload_in_progress) + if (flag_pic && reload_in_progress) df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true); - emit_move_insn (operands[0], gen_rtx_PLUS (SImode, temp, temp2)); + emit_move_insn (op0, gen_rtx_PLUS (SImode, temp, temp2)); return true; } } - - if ((reload_in_progress | reload_completed) == 0 - && !register_operand (operands[0], SImode) - && !register_operand (operands[1], SImode) - && (GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) != 0)) - { - rtx temp = force_reg (SImode, operands[1]); - emit_move_insn (operands[0], temp); - return true; - } return false; } @@ -3048,10 +3393,40 @@ microblaze_adjust_cost (rtx insn ATTRIBUTE_UNUSED, rtx link, At present, GAS doesn't understand li.[sd], so don't allow it to be generated at present. */ static bool -microblaze_legitimate_constant_p (enum machine_mode mode, rtx x) +microblaze_legitimate_constant_p (enum machine_mode mode ATTRIBUTE_UNUSED, rtx x) { - return GET_CODE (x) != CONST_DOUBLE || microblaze_const_double_ok (x, mode); + + if (microblaze_cannot_force_const_mem(mode, x)) + return false; + + if (GET_CODE (x) == CONST_DOUBLE) + { + return microblaze_const_double_ok (x, GET_MODE (x)); + } + + /* Handle Case of (const (plus unspec const_int)). */ + if (GET_CODE (x) == CONST && GET_CODE (XEXP (x,0)) == PLUS) + { + rtx p0, p1; + + p0 = XEXP (XEXP (x, 0), 0); + p1 = XEXP (XEXP (x, 0), 1); + + if (GET_CODE(p1) == CONST_INT) + { + /* Const offset from UNSPEC is not supported. */ + if ((GET_CODE (p0) == UNSPEC)) + return false; + + if ((GET_CODE (p0) == SYMBOL_REF || GET_CODE (p0) == LABEL_REF) + && (microblaze_tls_symbol_p (p0) || !SMALL_INT (p1))) + return false; + } + } + + return true; } + #undef TARGET_ENCODE_SECTION_INFO #define TARGET_ENCODE_SECTION_INFO microblaze_encode_section_info @@ -3068,6 +3443,9 @@ microblaze_legitimate_constant_p (enum machine_mode mode, rtx x) #undef TARGET_RTX_COSTS #define TARGET_RTX_COSTS microblaze_rtx_costs +#undef TARGET_CANNOT_FORCE_CONST_MEM +#define TARGET_CANNOT_FORCE_CONST_MEM microblaze_cannot_force_const_mem + #undef TARGET_ADDRESS_COST #define TARGET_ADDRESS_COST microblaze_address_cost diff --git a/gcc/config/microblaze/microblaze.h b/gcc/config/microblaze/microblaze.h index 8fbe5bf8085..bc4d9a128d1 100644 --- a/gcc/config/microblaze/microblaze.h +++ b/gcc/config/microblaze/microblaze.h @@ -65,6 +65,9 @@ extern enum pipeline_type microblaze_pipe; /* The default is to support PIC. */ #define TARGET_SUPPORTS_PIC 1 +/* The default is to not need GOT for TLS. */ +#define TLS_NEEDS_GOT 0 + /* What is the default setting for -mcpu= . We set it to v4.00.a even though we are actually ahead. This is safest version that has generate code compatible for the original ISA */ @@ -326,9 +329,7 @@ extern char microblaze_hard_regno_mode_ok[][FIRST_PSEUDO_REGISTER]; #define NO_FUNCTION_CSE 1 -#define PIC_OFFSET_TABLE_REGNUM \ - (flag_pic ? (GP_REG_FIRST + MB_ABI_PIC_ADDR_REGNUM) : \ - INVALID_REGNUM) +#define PIC_OFFSET_TABLE_REGNUM (GP_REG_FIRST + MB_ABI_PIC_ADDR_REGNUM) enum reg_class { diff --git a/gcc/config/microblaze/microblaze.md b/gcc/config/microblaze/microblaze.md index 02857875022..3618cad524b 100644 --- a/gcc/config/microblaze/microblaze.md +++ b/gcc/config/microblaze/microblaze.md @@ -40,6 +40,7 @@ (UNSPEC_PLT 103) ;; jump table (UNSPEC_CMP 104) ;; signed compare (UNSPEC_CMPU 105) ;; unsigned compare + (UNSPEC_TLS 106) ;; jump table ]) @@ -459,7 +460,7 @@ (define_insn "addsi3" [(set (match_operand:SI 0 "register_operand" "=d,d,d") (plus:SI (match_operand:SI 1 "reg_or_0_operand" "%dJ,dJ,dJ") - (match_operand:SI 2 "arith_operand" "d,I,i")))] + (match_operand:SI 2 "arith_plus_operand" "d,I,i")))] "" "@ addk\t%0,%z1,%2 @@ -892,8 +893,8 @@ (define_insn "*movdi_internal" - [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,d,d,d,R,m") - (match_operand:DI 1 "general_operand" " d,i,J,R,m,d,d"))] + [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,d,d,d,R,o") + (match_operand:DI 1 "general_operand" " d,i,J,R,o,d,d"))] "" { switch (which_alternative) @@ -999,13 +1000,9 @@ (set_attr "length" "4")]) (define_insn "*movsi_internal2" - [(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,d, d,d,R, T") - (match_operand:SI 1 "move_operand" " d,I,Mnis,R,m,dJ,dJ"))] - "(register_operand (operands[0], SImode) - || register_operand (operands[1], SImode) - || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0)) - && (flag_pic != 2 || (GET_CODE (operands[1]) != SYMBOL_REF - && GET_CODE (operands[1]) != LABEL_REF))" + [(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,d, d,d,R,m") + (match_operand:SI 1 "move_src_operand" " d,I,Mnis,R,m,dJ,dJ"))] + "" "@ addk\t%0,%1,r0 addik\t%0,r0,%1\t# %X1 @@ -1196,7 +1193,7 @@ ;; Applies to both TARGET_SOFT_FLOAT and TARGET_HARD_FLOAT ;; (define_insn "*movdf_internal" - [(set (match_operand:DF 0 "nonimmediate_operand" "=d,d,d,d,To") + [(set (match_operand:DF 0 "nonimmediate_operand" "=d,d,d,d,o") (match_operand:DF 1 "general_operand" "dG,o,F,T,d"))] "" { diff --git a/gcc/config/microblaze/predicates.md b/gcc/config/microblaze/predicates.md index e6e99836024..5fd1bd40372 100644 --- a/gcc/config/microblaze/predicates.md +++ b/gcc/config/microblaze/predicates.md @@ -30,6 +30,52 @@ (and (match_code "const_int,const_double") (match_test "LARGE_INT (op)")))) +(define_predicate "arith_plus_operand" + (match_operand 0 "general_operand") +{ + switch (GET_CODE (op)) + { + default: + return 0; + case CONST_INT: + case REG: + return 1; + case SYMBOL_REF: + case LABEL_REF: + if (flag_pic || microblaze_tls_referenced_p(op)) + return 0; + return 1; + case CONST: + { + rtx const0; + const0 = XEXP (op, 0); + + switch (GET_CODE(const0)) + { + default: + return 0; + case UNSPEC : + return 1; + + case PLUS : + { + rtx p0, p1; + p0 = XEXP (const0, 0); + p1 = XEXP (const0, 1); + + if ((GET_CODE(p0) == SYMBOL_REF + || GET_CODE (p0) == LABEL_REF) + && GET_CODE(p1) == CONST_INT) + { + return arith_plus_operand (p0, GET_MODE(p0)); + } + } + } + } + } + return 0; +}) + (define_predicate "const_0_operand" (and (match_code "const_int,const_double") (match_test "op == CONST0_RTX (GET_MODE (op))"))) @@ -54,14 +100,21 @@ (match_test "GET_CODE (op) == REG || GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == CONST_INT"))) ;; Return if OPERAND is valid as a source operand for a move instruction. -(define_predicate "move_operand" +(define_predicate "move_src_operand" (and ( not ( and (match_code "plus") (not (match_test "(GET_CODE (XEXP (op, 0)) == REG) ^ (GET_CODE (XEXP (op,1)) == REG)")) ) ) - (match_operand 0 "general_operand"))) + (match_operand 0 "general_operand")) +{ + if (microblaze_tls_referenced_p(op) + || (flag_pic && (symbol_mentioned_p(op) || label_mentioned_p(op)))) + return false; + + return true; +}) ;; Test for valid PIC call operand (define_predicate "call_insn_plt_operand" diff --git a/gcc/configure b/gcc/configure index d4f49bbeceb..e12a1803140 100755 --- a/gcc/configure +++ b/gcc/configure @@ -23205,6 +23205,18 @@ foo: data8 25 tls_first_minor=13 tls_as_opt=--fatal-warnings ;; + microblaze*-*-*) + conftest_s=' + .section .tdata,"awT",@progbits +x: + .word 2 + .text + addik r5,r20,x@TLSGD + addik r5,r20,x@TLSLDM' + tls_first_major=2 + tls_first_minor=20 + tls_as_opt='--fatal-warnings' + ;; mips*-*-*) conftest_s=' .section .tdata,"awT",@progbits diff --git a/gcc/configure.ac b/gcc/configure.ac index 811c296cb81..eba35774648 100644 --- a/gcc/configure.ac +++ b/gcc/configure.ac @@ -2968,6 +2968,18 @@ foo: data8 25 tls_first_minor=13 tls_as_opt=--fatal-warnings ;; + microblaze*-*-*) + conftest_s=' + .section .tdata,"awT",@progbits +x: + .word 2 + .text + addik r5,r20,x@TLSGD + addik r5,r20,x@TLSLDM' + tls_first_major=2 + tls_first_minor=20 + tls_as_opt='--fatal-warnings' + ;; mips*-*-*) conftest_s=' .section .tdata,"awT",@progbits -- 2.30.2