Commit a6fed83f by Eric Botcazou Committed by Eric Botcazou

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
parent 2f8bed16
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> 2010-12-19 Dave Korn <dave.korn.cygwin@gmail.com>
PR middle-end/46674 PR middle-end/46674
...@@ -391,7 +391,7 @@ static rtx sparc_builtin_saveregs (void); ...@@ -391,7 +391,7 @@ static rtx sparc_builtin_saveregs (void);
static int epilogue_renumber (rtx *, int); static int epilogue_renumber (rtx *, int);
static bool sparc_assemble_integer (rtx, unsigned int, int); static bool sparc_assemble_integer (rtx, unsigned int, int);
static int set_extends (rtx); 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 int save_or_restore_regs (int, int, rtx, int, int);
static void emit_save_or_restore_regs (int); static void emit_save_or_restore_regs (int);
static void sparc_asm_function_prologue (FILE *, HOST_WIDE_INT); static void sparc_asm_function_prologue (FILE *, HOST_WIDE_INT);
...@@ -3020,26 +3020,39 @@ sparc_cannot_force_const_mem (rtx x) ...@@ -3020,26 +3020,39 @@ sparc_cannot_force_const_mem (rtx x)
} }
} }
/* PIC support. */ /* Global Offset Table support. */
static GTY(()) bool pic_helper_needed = false; static GTY(()) rtx got_helper_rtx = NULL_RTX;
static GTY(()) rtx pic_helper_symbol; static GTY(()) rtx global_offset_table_rtx = NULL_RTX;
static GTY(()) rtx global_offset_table;
/* 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. */ /* Ensure that we are not using patterns that are not OK with PIC. */
int int
check_pic (int i) check_pic (int i)
{ {
rtx op;
switch (flag_pic) switch (flag_pic)
{ {
case 1: case 1:
gcc_assert (GET_CODE (recog_data.operand[i]) != SYMBOL_REF op = recog_data.operand[i];
&& (GET_CODE (recog_data.operand[i]) != CONST gcc_assert (GET_CODE (op) != SYMBOL_REF
|| (GET_CODE (XEXP (recog_data.operand[i], 0)) == MINUS && (GET_CODE (op) != CONST
&& (XEXP (XEXP (recog_data.operand[i], 0), 0) || (GET_CODE (XEXP (op, 0)) == MINUS
== global_offset_table) && XEXP (XEXP (op, 0), 0) == sparc_got ()
&& (GET_CODE (XEXP (XEXP (recog_data.operand[i], 0), 1)) && GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST)));
== CONST))));
case 2: case 2:
default: default:
return 1; return 1;
...@@ -3274,9 +3287,9 @@ sparc_legitimate_address_p (enum machine_mode mode, rtx addr, bool strict) ...@@ -3274,9 +3287,9 @@ sparc_legitimate_address_p (enum machine_mode mode, rtx addr, bool strict)
return 1; 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 static rtx
sparc_tls_get_addr (void) sparc_tls_get_addr (void)
...@@ -3287,21 +3300,28 @@ sparc_tls_get_addr (void) ...@@ -3287,21 +3300,28 @@ sparc_tls_get_addr (void)
return sparc_tls_symbol; return sparc_tls_symbol;
} }
/* Return the Global Offset Table to be used in TLS mode. */
static rtx static rtx
sparc_tls_got (void) sparc_tls_got (void)
{ {
rtx temp; /* In PIC mode, this is just the PIC offset table. */
if (flag_pic) if (flag_pic)
{ {
crtl->uses_pic_offset_table = 1; crtl->uses_pic_offset_table = 1;
return pic_offset_table_rtx; return pic_offset_table_rtx;
} }
if (!global_offset_table) /* In non-PIC mode, Sun as (unlike GNU as) emits PC-relative relocations for
global_offset_table = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_"); the GOT symbol with the 32-bit ABI, so we reload the GOT register. */
temp = gen_reg_rtx (Pmode); if (TARGET_SUN_TLS && TARGET_ARCH32)
emit_move_insn (temp, global_offset_table); {
return temp; 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. */ /* Return true if X contains a thread-local symbol. */
...@@ -3741,59 +3761,69 @@ sparc_mode_dependent_address_p (const_rtx addr) ...@@ -3741,59 +3761,69 @@ sparc_mode_dependent_address_p (const_rtx addr)
static void static void
get_pc_thunk_name (char name[32], unsigned int regno) 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 /* Skip the leading '%' as that cannot be used in a
symbol name. */ symbol name. */
pic_name += 1; reg_name += 1;
if (USE_HIDDEN_LINKONCE) if (USE_HIDDEN_LINKONCE)
sprintf (name, "__sparc_get_pc_thunk.%s", pic_name); sprintf (name, "__sparc_get_pc_thunk.%s", reg_name);
else else
ASM_GENERATE_INTERNAL_LABEL (name, "LADDPC", regno); 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 static rtx
load_pic_register (void) gen_load_pcrel_sym (rtx op0, rtx op1, rtx op2, rtx op3)
{ {
int orig_flag_pic = flag_pic; int orig_flag_pic = flag_pic;
rtx insn;
if (TARGET_VXWORKS_RTP) /* The load_pcrel_sym{si,di} patterns require absolute addressing. */
{ flag_pic = 0;
emit_insn (gen_vxworks_load_got ()); if (TARGET_ARCH64)
emit_use (pic_offset_table_rtx); insn = gen_load_pcrel_symdi (op0, op1, op2, op3);
return; else
} insn = gen_load_pcrel_symsi (op0, op1, op2, op3);
flag_pic = orig_flag_pic;
/* If we haven't initialized the special PIC symbols, do so now. */
if (!pic_helper_needed)
{
char name[32];
pic_helper_needed = true; return insn;
}
get_pc_thunk_name (name, REGNO (pic_offset_table_rtx)); /* Emit code to load the GOT register. */
pic_helper_symbol = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (name));
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_VXWORKS_RTP)
if (TARGET_ARCH64) emit_insn (gen_vxworks_load_got ());
emit_insn (gen_load_pcrel_symdi (pic_offset_table_rtx, global_offset_table,
pic_helper_symbol));
else else
emit_insn (gen_load_pcrel_symsi (pic_offset_table_rtx, global_offset_table, {
pic_helper_symbol)); /* The GOT symbol is subject to a PC-relative relocation so we need a
flag_pic = orig_flag_pic; 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, /* Need to emit this whether or not we obey regdecls,
since setjmp/longjmp can cause life info to screw up. since setjmp/longjmp can cause life info to screw up.
??? In the case where we don't obey regdecls, this is not sufficient ??? In the case where we don't obey regdecls, this is not sufficient
since we may not fall out the bottom. */ 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 /* Emit a call instruction with the pattern given by PAT. ADDR is the
...@@ -4479,7 +4509,7 @@ gen_stack_pointer_dec (rtx decrement) ...@@ -4479,7 +4509,7 @@ gen_stack_pointer_dec (rtx decrement)
/* Expand the function prologue. The prologue is responsible for reserving /* Expand the function prologue. The prologue is responsible for reserving
storage for the frame, saving the call-saved registers and loading the storage for the frame, saving the call-saved registers and loading the
PIC register if needed. */ GOT register if needed. */
void void
sparc_expand_prologue (void) sparc_expand_prologue (void)
...@@ -4587,9 +4617,9 @@ sparc_expand_prologue (void) ...@@ -4587,9 +4617,9 @@ sparc_expand_prologue (void)
if (num_gfregs) if (num_gfregs)
emit_save_or_restore_regs (SORR_SAVE); emit_save_or_restore_regs (SORR_SAVE);
/* Load the PIC register if needed. */ /* Load the GOT register if needed. */
if (flag_pic && crtl->uses_pic_offset_table) if (crtl->uses_pic_offset_table)
load_pic_register (); load_got_register ();
} }
/* This function generates the assembly code for function entry, which boils /* 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, ...@@ -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. /* 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 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 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 static void
emit_and_preserve (rtx seq, rtx reg, rtx reg2) emit_and_preserve (rtx seq, rtx reg, rtx reg2)
...@@ -9320,20 +9350,19 @@ sparc_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED, ...@@ -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 /* The hoops we have to jump through in order to generate a sibcall
without using delay slots... */ 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) if (flag_pic)
{ {
spill_reg = gen_rtx_REG (word_mode, 15); /* %o7 */ spill_reg = gen_rtx_REG (word_mode, 15); /* %o7 */
spill_reg2 = gen_rtx_REG (word_mode, PIC_OFFSET_TABLE_REGNUM);
start_sequence (); 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. */ 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); scratch = sparc_legitimize_pic_address (funexp, scratch);
seq = get_insns (); seq = get_insns ();
end_sequence (); end_sequence ();
emit_and_preserve (seq, spill_reg, spill_reg2); emit_and_preserve (seq, spill_reg, pic_offset_table_rtx);
} }
else if (TARGET_ARCH32) else if (TARGET_ARCH32)
{ {
...@@ -9484,17 +9513,15 @@ sparc_output_dwarf_dtprel (FILE *file, int size, rtx x) ...@@ -9484,17 +9513,15 @@ sparc_output_dwarf_dtprel (FILE *file, int size, rtx x)
static void static void
sparc_file_end (void) sparc_file_end (void)
{ {
/* If need to emit the special PIC helper function, do so now. */ /* If we need to emit the special GOT helper function, do so now. */
if (pic_helper_needed) if (got_helper_rtx)
{ {
unsigned int regno = REGNO (pic_offset_table_rtx); const char *name = XSTR (got_helper_rtx, 0);
const char *pic_name = reg_names[regno]; const char *reg_name = reg_names[GLOBAL_OFFSET_TABLE_REGNUM];
char name[32];
#ifdef DWARF2_UNWIND_INFO #ifdef DWARF2_UNWIND_INFO
bool do_cfi; bool do_cfi;
#endif #endif
get_pc_thunk_name (name, regno);
if (USE_HIDDEN_LINKONCE) if (USE_HIDDEN_LINKONCE)
{ {
tree decl = build_decl (BUILTINS_LOCATION, FUNCTION_DECL, tree decl = build_decl (BUILTINS_LOCATION, FUNCTION_DECL,
...@@ -9529,10 +9556,10 @@ sparc_file_end (void) ...@@ -9529,10 +9556,10 @@ sparc_file_end (void)
#endif #endif
if (flag_delayed_branch) if (flag_delayed_branch)
fprintf (asm_out_file, "\tjmp\t%%o7+8\n\t add\t%%o7, %s, %s\n", 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 else
fprintf (asm_out_file, "\tadd\t%%o7, %s, %s\n\tjmp\t%%o7+8\n\t nop\n", 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 #ifdef DWARF2_UNWIND_INFO
if (do_cfi) if (do_cfi)
fprintf (asm_out_file, "\t.cfi_endproc\n"); fprintf (asm_out_file, "\t.cfi_endproc\n");
......
...@@ -906,10 +906,15 @@ extern int sparc_mode_class[]; ...@@ -906,10 +906,15 @@ extern int sparc_mode_class[];
not be a register used by the prologue. */ not be a register used by the prologue. */
#define STATIC_CHAIN_REGNUM (TARGET_ARCH64 ? 5 : 2) #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 /* Register which holds offset table for position-independent
data references. */ 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: /* Pick a default value we can notice from override_options:
!v9: Default is on. !v9: Default is on.
......
...@@ -1113,14 +1113,15 @@ ...@@ -1113,14 +1113,15 @@
;; Load in operand 0 the (absolute) address of operand 1, which is a symbolic ;; 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 ;; 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>" (define_insn "load_pcrel_sym<P:mode>"
[(set (match_operand:P 0 "register_operand" "=r") [(set (match_operand:P 0 "register_operand" "=r")
(unspec:P [(match_operand:P 1 "symbolic_operand" "") (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))] (clobber (reg:P 15))]
"" "REGNO (operands[0]) == INTVAL (operands[3])"
{ {
if (flag_delayed_branch) if (flag_delayed_branch)
return "sethi\t%%hi(%a1-4), %0\n\tcall\t%a2\n\t add\t%0, %%lo(%a1+4), %0"; return "sethi\t%%hi(%a1-4), %0\n\tcall\t%a2\n\t add\t%0, %%lo(%a1+4), %0";
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment