diff options
author | Eric Botcazou <ebotcazou@adacore.com> | 2010-12-19 12:19:12 +0000 |
---|---|---|
committer | Eric Botcazou <ebotcazou@gcc.gnu.org> | 2010-12-19 12:19:12 +0000 |
commit | a6fed83ffa62aa01d7add21c9d2b36ba12efb731 (patch) | |
tree | 76cc3ddd8315fc60ee1aa286b0d55ec81acc588c | |
parent | 2f8bed161326b1ffd27a3614ac8d8391a5eb7dd0 (diff) | |
download | gcc-a6fed83ffa62aa01d7add21c9d2b36ba12efb731.zip gcc-a6fed83ffa62aa01d7add21c9d2b36ba12efb731.tar.gz gcc-a6fed83ffa62aa01d7add21c9d2b36ba12efb731.tar.bz2 |
re PR target/46729 (32-bit 30_threads execution tests fail on Solaris 10/SPARC with Sun as)
PR target/46729
* config/sparc/sparc.h (GLOBAL_OFFSET_TABLE_REGNUM): New macro.
(PIC_OFFSET_TABLE_REGNUM): Rewrite in terms of above macro.
* config/sparc/sparc.c (pic_helper_needed): Delete.
(global_offset_table): Likewise.
(pic_helper_symbol): Rename to...
(got_helper_rtx): ...this.
(global_offset_table_rtx): New global variable.
(sparc_got_symbol): Likewise.
(sparc_got): New static function.
(check_pic): Use local variable and call sparc_got.
(sparc_tls_symbol): Initialize to NULL_RTX.
(sparc_tls_got): In non-PIC mode, reload the GOT register for Sun TLS
and 32-bit ABI and copy the GOT symbol to a new register otherwise.
(get_pc_thunk_name): Rename local variable.
(gen_load_pcrel_sym): New wrapper around load_pcrel_sym{si,di}.
(load_pic_register): Rename to...
(load_got_register): ...this. Adjust and call gen_load_pcrel_sym.
(sparc_expand_prologue): Do not test flag_pic.
(sparc_output_mi_thunk): Use pic_offset_table_rtx directly.
(sparc_file_end): Test got_helper_rtx instead of pic_helper_needed.
Rename local variable and do not call get_pc_thunk_name again.
* config/sparc/sparc.md (load_pcrel_sym): Add operand #3.
From-SVN: r168049
-rw-r--r-- | gcc/ChangeLog | 26 | ||||
-rw-r--r-- | gcc/config/sparc/sparc.c | 163 | ||||
-rw-r--r-- | gcc/config/sparc/sparc.h | 7 | ||||
-rw-r--r-- | gcc/config/sparc/sparc.md | 7 |
4 files changed, 131 insertions, 72 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 8a6523d..68bb8f7 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,29 @@ +2010-12-19 Eric Botcazou <ebotcazou@adacore.com> + + PR target/46729 + * config/sparc/sparc.h (GLOBAL_OFFSET_TABLE_REGNUM): New macro. + (PIC_OFFSET_TABLE_REGNUM): Rewrite in terms of above macro. + * config/sparc/sparc.c (pic_helper_needed): Delete. + (global_offset_table): Likewise. + (pic_helper_symbol): Rename to... + (got_helper_rtx): ...this. + (global_offset_table_rtx): New global variable. + (sparc_got_symbol): Likewise. + (sparc_got): New static function. + (check_pic): Use local variable and call sparc_got. + (sparc_tls_symbol): Initialize to NULL_RTX. + (sparc_tls_got): In non-PIC mode, reload the GOT register for Sun TLS + and 32-bit ABI and copy the GOT symbol to a new register otherwise. + (get_pc_thunk_name): Rename local variable. + (gen_load_pcrel_sym): New wrapper around load_pcrel_sym{si,di}. + (load_pic_register): Rename to... + (load_got_register): ...this. Adjust and call gen_load_pcrel_sym. + (sparc_expand_prologue): Do not test flag_pic. + (sparc_output_mi_thunk): Use pic_offset_table_rtx directly. + (sparc_file_end): Test got_helper_rtx instead of pic_helper_needed. + Rename local variable and do not call get_pc_thunk_name again. + * config/sparc/sparc.md (load_pcrel_sym): Add operand #3. + 2010-12-19 Dave Korn <dave.korn.cygwin@gmail.com> PR middle-end/46674 diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c index 760ff6e..a066b2a 100644 --- a/gcc/config/sparc/sparc.c +++ b/gcc/config/sparc/sparc.c @@ -391,7 +391,7 @@ static rtx sparc_builtin_saveregs (void); static int epilogue_renumber (rtx *, int); static bool sparc_assemble_integer (rtx, unsigned int, int); static int set_extends (rtx); -static void load_pic_register (void); +static void load_got_register (void); static int save_or_restore_regs (int, int, rtx, int, int); static void emit_save_or_restore_regs (int); static void sparc_asm_function_prologue (FILE *, HOST_WIDE_INT); @@ -3020,26 +3020,39 @@ sparc_cannot_force_const_mem (rtx x) } } -/* PIC support. */ -static GTY(()) bool pic_helper_needed = false; -static GTY(()) rtx pic_helper_symbol; -static GTY(()) rtx global_offset_table; +/* Global Offset Table support. */ +static GTY(()) rtx got_helper_rtx = NULL_RTX; +static GTY(()) rtx global_offset_table_rtx = NULL_RTX; + +/* Return the SYMBOL_REF for the Global Offset Table. */ + +static GTY(()) rtx sparc_got_symbol = NULL_RTX; + +static rtx +sparc_got (void) +{ + if (!sparc_got_symbol) + sparc_got_symbol = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_"); + + return sparc_got_symbol; +} /* Ensure that we are not using patterns that are not OK with PIC. */ int check_pic (int i) { + rtx op; + switch (flag_pic) { case 1: - gcc_assert (GET_CODE (recog_data.operand[i]) != SYMBOL_REF - && (GET_CODE (recog_data.operand[i]) != CONST - || (GET_CODE (XEXP (recog_data.operand[i], 0)) == MINUS - && (XEXP (XEXP (recog_data.operand[i], 0), 0) - == global_offset_table) - && (GET_CODE (XEXP (XEXP (recog_data.operand[i], 0), 1)) - == CONST)))); + op = recog_data.operand[i]; + gcc_assert (GET_CODE (op) != SYMBOL_REF + && (GET_CODE (op) != CONST + || (GET_CODE (XEXP (op, 0)) == MINUS + && XEXP (XEXP (op, 0), 0) == sparc_got () + && GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST))); case 2: default: return 1; @@ -3274,9 +3287,9 @@ sparc_legitimate_address_p (enum machine_mode mode, rtx addr, bool strict) return 1; } -/* Construct the SYMBOL_REF for the tls_get_offset function. */ +/* Return the SYMBOL_REF for the tls_get_addr function. */ -static GTY(()) rtx sparc_tls_symbol; +static GTY(()) rtx sparc_tls_symbol = NULL_RTX; static rtx sparc_tls_get_addr (void) @@ -3287,21 +3300,28 @@ sparc_tls_get_addr (void) return sparc_tls_symbol; } +/* Return the Global Offset Table to be used in TLS mode. */ + static rtx sparc_tls_got (void) { - rtx temp; + /* In PIC mode, this is just the PIC offset table. */ if (flag_pic) { crtl->uses_pic_offset_table = 1; return pic_offset_table_rtx; } - if (!global_offset_table) - global_offset_table = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_"); - temp = gen_reg_rtx (Pmode); - emit_move_insn (temp, global_offset_table); - return temp; + /* In non-PIC mode, Sun as (unlike GNU as) emits PC-relative relocations for + the GOT symbol with the 32-bit ABI, so we reload the GOT register. */ + if (TARGET_SUN_TLS && TARGET_ARCH32) + { + load_got_register (); + return global_offset_table_rtx; + } + + /* In all other cases, we load a new pseudo with the GOT symbol. */ + return copy_to_reg (sparc_got ()); } /* Return true if X contains a thread-local symbol. */ @@ -3741,59 +3761,69 @@ sparc_mode_dependent_address_p (const_rtx addr) static void get_pc_thunk_name (char name[32], unsigned int regno) { - const char *pic_name = reg_names[regno]; + const char *reg_name = reg_names[regno]; /* Skip the leading '%' as that cannot be used in a symbol name. */ - pic_name += 1; + reg_name += 1; if (USE_HIDDEN_LINKONCE) - sprintf (name, "__sparc_get_pc_thunk.%s", pic_name); + sprintf (name, "__sparc_get_pc_thunk.%s", reg_name); else ASM_GENERATE_INTERNAL_LABEL (name, "LADDPC", regno); } -/* Emit code to load the PIC register. */ +/* Wrapper around the load_pcrel_sym{si,di} patterns. */ -static void -load_pic_register (void) +static rtx +gen_load_pcrel_sym (rtx op0, rtx op1, rtx op2, rtx op3) { int orig_flag_pic = flag_pic; + rtx insn; - if (TARGET_VXWORKS_RTP) - { - emit_insn (gen_vxworks_load_got ()); - emit_use (pic_offset_table_rtx); - return; - } - - /* If we haven't initialized the special PIC symbols, do so now. */ - if (!pic_helper_needed) - { - char name[32]; + /* The load_pcrel_sym{si,di} patterns require absolute addressing. */ + flag_pic = 0; + if (TARGET_ARCH64) + insn = gen_load_pcrel_symdi (op0, op1, op2, op3); + else + insn = gen_load_pcrel_symsi (op0, op1, op2, op3); + flag_pic = orig_flag_pic; - pic_helper_needed = true; + return insn; +} - get_pc_thunk_name (name, REGNO (pic_offset_table_rtx)); - pic_helper_symbol = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (name)); +/* Emit code to load the GOT register. */ - global_offset_table = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_"); - } +static void +load_got_register (void) +{ + /* In PIC mode, this will retrieve pic_offset_table_rtx. */ + if (!global_offset_table_rtx) + global_offset_table_rtx = gen_rtx_REG (Pmode, GLOBAL_OFFSET_TABLE_REGNUM); - flag_pic = 0; - if (TARGET_ARCH64) - emit_insn (gen_load_pcrel_symdi (pic_offset_table_rtx, global_offset_table, - pic_helper_symbol)); + if (TARGET_VXWORKS_RTP) + emit_insn (gen_vxworks_load_got ()); else - emit_insn (gen_load_pcrel_symsi (pic_offset_table_rtx, global_offset_table, - pic_helper_symbol)); - flag_pic = orig_flag_pic; + { + /* The GOT symbol is subject to a PC-relative relocation so we need a + helper function to add the PC value and thus get the final value. */ + if (!got_helper_rtx) + { + char name[32]; + get_pc_thunk_name (name, GLOBAL_OFFSET_TABLE_REGNUM); + got_helper_rtx = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (name)); + } + + emit_insn (gen_load_pcrel_sym (global_offset_table_rtx, sparc_got (), + got_helper_rtx, + GEN_INT (GLOBAL_OFFSET_TABLE_REGNUM))); + } /* Need to emit this whether or not we obey regdecls, since setjmp/longjmp can cause life info to screw up. ??? In the case where we don't obey regdecls, this is not sufficient since we may not fall out the bottom. */ - emit_use (pic_offset_table_rtx); + emit_use (global_offset_table_rtx); } /* Emit a call instruction with the pattern given by PAT. ADDR is the @@ -4479,7 +4509,7 @@ gen_stack_pointer_dec (rtx decrement) /* Expand the function prologue. The prologue is responsible for reserving storage for the frame, saving the call-saved registers and loading the - PIC register if needed. */ + GOT register if needed. */ void sparc_expand_prologue (void) @@ -4587,9 +4617,9 @@ sparc_expand_prologue (void) if (num_gfregs) emit_save_or_restore_regs (SORR_SAVE); - /* Load the PIC register if needed. */ - if (flag_pic && crtl->uses_pic_offset_table) - load_pic_register (); + /* Load the GOT register if needed. */ + if (crtl->uses_pic_offset_table) + load_got_register (); } /* This function generates the assembly code for function entry, which boils @@ -9157,7 +9187,7 @@ sparc_rtx_costs (rtx x, int code, int outer_code, int *total, /* Emit the sequence of insns SEQ while preserving the registers REG and REG2. This is achieved by means of a manual dynamic stack space allocation in the current frame. We make the assumption that SEQ doesn't contain any - function calls, with the possible exception of calls to the PIC helper. */ + function calls, with the possible exception of calls to the GOT helper. */ static void emit_and_preserve (rtx seq, rtx reg, rtx reg2) @@ -9320,20 +9350,19 @@ sparc_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED, { /* The hoops we have to jump through in order to generate a sibcall without using delay slots... */ - rtx spill_reg, spill_reg2, seq, scratch = gen_rtx_REG (Pmode, 1); + rtx spill_reg, seq, scratch = gen_rtx_REG (Pmode, 1); if (flag_pic) { spill_reg = gen_rtx_REG (word_mode, 15); /* %o7 */ - spill_reg2 = gen_rtx_REG (word_mode, PIC_OFFSET_TABLE_REGNUM); start_sequence (); - /* Delay emitting the PIC helper function because it needs to + /* Delay emitting the GOT helper function because it needs to change the section and we are emitting assembly code. */ - load_pic_register (); /* clobbers %o7 */ + load_got_register (); /* clobbers %o7 */ scratch = sparc_legitimize_pic_address (funexp, scratch); seq = get_insns (); end_sequence (); - emit_and_preserve (seq, spill_reg, spill_reg2); + emit_and_preserve (seq, spill_reg, pic_offset_table_rtx); } else if (TARGET_ARCH32) { @@ -9484,17 +9513,15 @@ sparc_output_dwarf_dtprel (FILE *file, int size, rtx x) static void sparc_file_end (void) { - /* If need to emit the special PIC helper function, do so now. */ - if (pic_helper_needed) + /* If we need to emit the special GOT helper function, do so now. */ + if (got_helper_rtx) { - unsigned int regno = REGNO (pic_offset_table_rtx); - const char *pic_name = reg_names[regno]; - char name[32]; + const char *name = XSTR (got_helper_rtx, 0); + const char *reg_name = reg_names[GLOBAL_OFFSET_TABLE_REGNUM]; #ifdef DWARF2_UNWIND_INFO bool do_cfi; #endif - get_pc_thunk_name (name, regno); if (USE_HIDDEN_LINKONCE) { tree decl = build_decl (BUILTINS_LOCATION, FUNCTION_DECL, @@ -9529,10 +9556,10 @@ sparc_file_end (void) #endif if (flag_delayed_branch) fprintf (asm_out_file, "\tjmp\t%%o7+8\n\t add\t%%o7, %s, %s\n", - pic_name, pic_name); + reg_name, reg_name); else fprintf (asm_out_file, "\tadd\t%%o7, %s, %s\n\tjmp\t%%o7+8\n\t nop\n", - pic_name, pic_name); + reg_name, reg_name); #ifdef DWARF2_UNWIND_INFO if (do_cfi) fprintf (asm_out_file, "\t.cfi_endproc\n"); diff --git a/gcc/config/sparc/sparc.h b/gcc/config/sparc/sparc.h index a2ed8d0..c41a623 100644 --- a/gcc/config/sparc/sparc.h +++ b/gcc/config/sparc/sparc.h @@ -906,10 +906,15 @@ extern int sparc_mode_class[]; not be a register used by the prologue. */ #define STATIC_CHAIN_REGNUM (TARGET_ARCH64 ? 5 : 2) +/* Register which holds the global offset table, if any. */ + +#define GLOBAL_OFFSET_TABLE_REGNUM 23 + /* Register which holds offset table for position-independent data references. */ -#define PIC_OFFSET_TABLE_REGNUM (flag_pic ? 23 : INVALID_REGNUM) +#define PIC_OFFSET_TABLE_REGNUM \ + (flag_pic ? GLOBAL_OFFSET_TABLE_REGNUM : INVALID_REGNUM) /* Pick a default value we can notice from override_options: !v9: Default is on. diff --git a/gcc/config/sparc/sparc.md b/gcc/config/sparc/sparc.md index f8939dd..853bd2f 100644 --- a/gcc/config/sparc/sparc.md +++ b/gcc/config/sparc/sparc.md @@ -1113,14 +1113,15 @@ ;; Load in operand 0 the (absolute) address of operand 1, which is a symbolic ;; value subject to a PC-relative relocation. Operand 2 is a helper function -;; that adds the PC value at the call point to operand 0. +;; that adds the PC value at the call point to register #(operand 3). (define_insn "load_pcrel_sym<P:mode>" [(set (match_operand:P 0 "register_operand" "=r") (unspec:P [(match_operand:P 1 "symbolic_operand" "") - (match_operand:P 2 "call_address_operand" "")] UNSPEC_LOAD_PCREL_SYM)) + (match_operand:P 2 "call_address_operand" "") + (match_operand:P 3 "const_int_operand" "")] UNSPEC_LOAD_PCREL_SYM)) (clobber (reg:P 15))] - "" + "REGNO (operands[0]) == INTVAL (operands[3])" { if (flag_delayed_branch) return "sethi\t%%hi(%a1-4), %0\n\tcall\t%a2\n\t add\t%0, %%lo(%a1+4), %0"; |