diff options
Diffstat (limited to 'gcc/config/sparc')
-rw-r--r-- | gcc/config/sparc/sol2.h | 4 | ||||
-rw-r--r-- | gcc/config/sparc/sparc.c | 88 | ||||
-rw-r--r-- | gcc/config/sparc/sparc.md | 25 |
3 files changed, 85 insertions, 32 deletions
diff --git a/gcc/config/sparc/sol2.h b/gcc/config/sparc/sol2.h index fe4e98c3c03..ff3339d0f1f 100644 --- a/gcc/config/sparc/sol2.h +++ b/gcc/config/sparc/sol2.h @@ -142,8 +142,8 @@ Boston, MA 02111-1307, USA. */ "%{h*} %{v:-V} \ %{b} %{Wl,*:%*} \ %{static:-dn -Bstatic} \ - %{shared:-G -dy %{!mimpure-text:-z text} %{!h*:%{o*:-h %*}}} \ - %{symbolic:-Bsymbolic -G -dy -z text %{!h*:%{o*:-h %*}}} \ + %{shared:-G -dy %{!mimpure-text:-z text}} \ + %{symbolic:-Bsymbolic -G -dy -z text} \ %{G:-G} \ %{YP,*} \ %{R*} \ diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c index 692ba41f790..58da5ac35fc 100644 --- a/gcc/config/sparc/sparc.c +++ b/gcc/config/sparc/sparc.c @@ -100,8 +100,16 @@ char leaf_reg_remap[] = static char *frame_base_name; static int frame_base_offset; -static rtx find_addr_reg (); -static void sparc_init_modes (); +static rtx pic_setup_code PROTO((void)); +static rtx find_addr_reg PROTO((rtx)); +static void sparc_init_modes PROTO((void)); +static int save_regs PROTO((FILE *, int, int, char *, + int, int, int)); +static int restore_regs PROTO((FILE *, int, int, char *, int, int)); +static void build_big_number PROTO((FILE *, int, char *)); +static function_arg_slotno PROTO((const CUMULATIVE_ARGS *, + enum machine_mode, tree, int, int, + int *, int *)); #ifdef DWARF2_DEBUGGING_INFO extern char *dwarf2out_cfi_label (); @@ -1324,9 +1332,8 @@ reg_unused_after (reg, insn) return 1; } -/* The rtx for the global offset table which is a special form - that *is* a position independent symbolic constant. */ -static rtx pic_pc_rtx; +/* The table we use to reference PIC data. */ +static rtx global_offset_table; /* Ensure that we are not using patterns that are not OK with PIC. */ @@ -1339,7 +1346,11 @@ check_pic (i) case 1: if (GET_CODE (recog_operand[i]) == SYMBOL_REF || (GET_CODE (recog_operand[i]) == CONST - && ! rtx_equal_p (pic_pc_rtx, recog_operand[i]))) + && ! (GET_CODE (XEXP (recog_operand[i], 0)) == MINUS + && (XEXP (XEXP (recog_operand[i], 0), 0) + == global_offset_table) + && (GET_CODE (XEXP (XEXP (recog_operand[i], 0), 1)) + == CONST)))) abort (); case 2: default: @@ -1472,39 +1483,26 @@ initialize_pic () { } -/* Emit special PIC prologues and epilogues. */ +/* Return the RTX for insns to set the PIC register. */ -void -finalize_pic () +static rtx +pic_setup_code () { - /* The table we use to reference PIC data. */ - rtx global_offset_table; - /* Labels to get the PC in the prologue of this function. */ + rtx pic_pc_rtx; rtx l1, l2; rtx seq; - int orig_flag_pic = flag_pic; - - if (current_function_uses_pic_offset_table == 0) - return; - - if (! flag_pic) - abort (); - - flag_pic = 0; start_sequence (); l1 = gen_label_rtx (); - /* Initialize every time through, since we can't easily - know this to be permanent. */ - global_offset_table = gen_rtx (SYMBOL_REF, Pmode, "_GLOBAL_OFFSET_TABLE_"); pic_pc_rtx = gen_rtx (CONST, Pmode, gen_rtx (MINUS, Pmode, global_offset_table, gen_rtx (CONST, Pmode, gen_rtx (MINUS, Pmode, - gen_rtx (LABEL_REF, VOIDmode, l1), + gen_rtx (LABEL_REF, + VOIDmode, l1), pc_rtx)))); /* sparc64: the RDPC instruction doesn't pair, and puts 4 bubbles in the @@ -1543,14 +1541,46 @@ finalize_pic () LABEL_PRESERVE_P (l1) = 1; LABEL_PRESERVE_P (l2) = 1; - flag_pic = orig_flag_pic; - seq = gen_sequence (); end_sequence (); - emit_insn_after (seq, get_insns ()); + + return seq; +} + +/* Emit special PIC prologues and epilogues. */ + +void +finalize_pic () +{ + /* Labels to get the PC in the prologue of this function. */ + int orig_flag_pic = flag_pic; + rtx insn; + + if (current_function_uses_pic_offset_table == 0) + return; + + if (! flag_pic) + abort (); + + /* Initialize every time through, since we can't easily + know this to be permanent. */ + global_offset_table = gen_rtx (SYMBOL_REF, Pmode, "_GLOBAL_OFFSET_TABLE_"); + flag_pic = 0; + + emit_insn_after (pic_setup_code (), get_insns ()); + + /* Insert the code in each nonlocal goto receiver. */ + for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) + if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == UNSPEC_VOLATILE + && XINT (PATTERN (insn), 1) == 4) + emit_insn_after (pic_setup_code (), insn); + + flag_pic = orig_flag_pic; /* 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 + since we may not fall out the bottom. */ emit_insn (gen_rtx (USE, VOIDmode, pic_offset_table_rtx)); } diff --git a/gcc/config/sparc/sparc.md b/gcc/config/sparc/sparc.md index 8ec12f5197a..6efa3320852 100644 --- a/gcc/config/sparc/sparc.md +++ b/gcc/config/sparc/sparc.md @@ -5014,7 +5014,21 @@ (define_insn "jump" [(set (pc) (label_ref (match_operand 0 "" "")))] "" - "b%* %l0%(" + "* +{ + /* Some implementations are reported to have problems with + foo: b,a foo + i.e. an empty loop with the annul bit set. The workaround is to use + foo: b foo; nop + instead. */ + + if (flag_delayed_branch + && (insn_addresses[INSN_UID (operands[0])] + == insn_addresses[INSN_UID (insn)])) + return \"b %l0%#\"; + else + return \"b%* %l0%(\"; +}" [(set_attr "type" "uncond_branch")]) (define_expand "tablejump" @@ -6136,3 +6150,12 @@ (set (reg:CC 100) (compare (match_dup 0) (const_int 0)))] "" "subxcc %r1,0,%0") + +;; After a nonlocal goto, we need to restore the PIC register, but only +;; if we need it. So do nothing much here, but we'll check for this in +;; finalize_pic. + +(define_insn "nonlocal_goto_receiver" + [(unspec_volatile [(const_int 0)] 4)] + "flag_pic" + "") |