summaryrefslogtreecommitdiff
path: root/gcc/config
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/config')
-rw-r--r--gcc/config/i386/i386.c169
-rw-r--r--gcc/config/i386/i386.h14
2 files changed, 108 insertions, 75 deletions
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index 4c4a6eb317d..2a64d2d3611 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -6141,6 +6141,68 @@ ix86_maybe_switch_abi (void)
reinit_regs ();
}
+/* Return 1 if pseudo register should be created and used to hold
+ GOT address for PIC code. */
+static bool
+ix86_use_pseudo_pic_reg (void)
+{
+ if ((TARGET_64BIT
+ && (ix86_cmodel == CM_SMALL_PIC
+ || TARGET_PECOFF))
+ || !flag_pic)
+ return false;
+ return true;
+}
+
+/* Create and initialize PIC register if required. */
+static void
+ix86_init_pic_reg (void)
+{
+ edge entry_edge;
+ rtx_insn *seq;
+
+ if (!ix86_use_pseudo_pic_reg ())
+ return;
+
+ start_sequence ();
+
+ if (TARGET_64BIT)
+ {
+ if (ix86_cmodel == CM_LARGE_PIC)
+ {
+ rtx_code_label *label;
+ rtx tmp_reg;
+
+ gcc_assert (Pmode == DImode);
+ label = gen_label_rtx ();
+ emit_label (label);
+ LABEL_PRESERVE_P (label) = 1;
+ tmp_reg = gen_rtx_REG (Pmode, R11_REG);
+ gcc_assert (REGNO (pic_offset_table_rtx) != REGNO (tmp_reg));
+ emit_insn (gen_set_rip_rex64 (pic_offset_table_rtx,
+ label));
+ emit_insn (gen_set_got_offset_rex64 (tmp_reg, label));
+ emit_insn (ix86_gen_add3 (pic_offset_table_rtx,
+ pic_offset_table_rtx, tmp_reg));
+ }
+ else
+ emit_insn (gen_set_got_rex64 (pic_offset_table_rtx));
+ }
+ else
+ {
+ rtx insn = emit_insn (gen_set_got (pic_offset_table_rtx));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ add_reg_note (insn, REG_CFA_FLUSH_QUEUE, NULL_RTX);
+ }
+
+ seq = get_insns ();
+ end_sequence ();
+
+ entry_edge = single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun));
+ insert_insn_on_edge (seq, entry_edge);
+ commit_one_edge_insertion (entry_edge);
+}
+
/* Initialize a variable CUM of type CUMULATIVE_ARGS
for a call to a function whose data type is FNTYPE.
For a library call, FNTYPE is 0. */
@@ -9383,6 +9445,9 @@ gen_pop (rtx arg)
static unsigned int
ix86_select_alt_pic_regnum (void)
{
+ if (ix86_use_pseudo_pic_reg ())
+ return INVALID_REGNUM;
+
if (crtl->is_leaf
&& !crtl->profile
&& !ix86_current_function_calls_tls_descriptor)
@@ -9407,6 +9472,7 @@ static bool
ix86_save_reg (unsigned int regno, bool maybe_eh_return)
{
if (pic_offset_table_rtx
+ && !ix86_use_pseudo_pic_reg ()
&& regno == REAL_PIC_OFFSET_TABLE_REGNUM
&& (df_regs_ever_live_p (REAL_PIC_OFFSET_TABLE_REGNUM)
|| crtl->profile
@@ -10759,7 +10825,6 @@ ix86_expand_prologue (void)
{
struct machine_function *m = cfun->machine;
rtx insn, t;
- bool pic_reg_used;
struct ix86_frame frame;
HOST_WIDE_INT allocate;
bool int_registers_saved;
@@ -11206,60 +11271,6 @@ ix86_expand_prologue (void)
if (!sse_registers_saved)
ix86_emit_save_sse_regs_using_mov (frame.sse_reg_save_offset);
- pic_reg_used = false;
- /* We don't use pic-register for pe-coff target. */
- if (pic_offset_table_rtx
- && !TARGET_PECOFF
- && (df_regs_ever_live_p (REAL_PIC_OFFSET_TABLE_REGNUM)
- || crtl->profile))
- {
- unsigned int alt_pic_reg_used = ix86_select_alt_pic_regnum ();
-
- if (alt_pic_reg_used != INVALID_REGNUM)
- SET_REGNO (pic_offset_table_rtx, alt_pic_reg_used);
-
- pic_reg_used = true;
- }
-
- if (pic_reg_used)
- {
- if (TARGET_64BIT)
- {
- if (ix86_cmodel == CM_LARGE_PIC)
- {
- rtx_code_label *label;
- rtx tmp_reg;
-
- gcc_assert (Pmode == DImode);
- label = gen_label_rtx ();
- emit_label (label);
- LABEL_PRESERVE_P (label) = 1;
- tmp_reg = gen_rtx_REG (Pmode, R11_REG);
- gcc_assert (REGNO (pic_offset_table_rtx) != REGNO (tmp_reg));
- insn = emit_insn (gen_set_rip_rex64 (pic_offset_table_rtx,
- label));
- insn = emit_insn (gen_set_got_offset_rex64 (tmp_reg, label));
- insn = emit_insn (ix86_gen_add3 (pic_offset_table_rtx,
- pic_offset_table_rtx, tmp_reg));
- }
- else
- insn = emit_insn (gen_set_got_rex64 (pic_offset_table_rtx));
- }
- else
- {
- insn = emit_insn (gen_set_got (pic_offset_table_rtx));
- RTX_FRAME_RELATED_P (insn) = 1;
- add_reg_note (insn, REG_CFA_FLUSH_QUEUE, NULL_RTX);
- }
- }
-
- /* In the pic_reg_used case, make sure that the got load isn't deleted
- when mcount needs it. Blockage to avoid call movement across mcount
- call is emitted in generic code after the NOTE_INSN_PROLOGUE_END
- note. */
- if (crtl->profile && !flag_fentry && pic_reg_used)
- emit_insn (gen_prologue_use (pic_offset_table_rtx));
-
if (crtl->drap_reg && !crtl->stack_realign_needed)
{
/* vDRAP is setup but after reload it turns out stack realign
@@ -11800,7 +11811,8 @@ ix86_expand_epilogue (int style)
static void
ix86_output_function_epilogue (FILE *file ATTRIBUTE_UNUSED, HOST_WIDE_INT)
{
- if (pic_offset_table_rtx)
+ if (pic_offset_table_rtx
+ && !ix86_use_pseudo_pic_reg ())
SET_REGNO (pic_offset_table_rtx, REAL_PIC_OFFSET_TABLE_REGNUM);
#if TARGET_MACHO
/* Mach-O doesn't support labels at the end of objects, so if
@@ -13120,6 +13132,15 @@ ix86_GOT_alias_set (void)
return set;
}
+/* Set regs_ever_live for PIC base address register
+ to true if required. */
+static void
+set_pic_reg_ever_live ()
+{
+ if (reload_in_progress)
+ df_set_regs_ever_live (REGNO (pic_offset_table_rtx), true);
+}
+
/* Return a legitimate reference for ORIG (an address) using the
register REG. If REG is 0, a new pseudo is generated.
@@ -13170,8 +13191,7 @@ legitimize_pic_address (rtx orig, rtx reg)
/* This symbol may be referenced via a displacement from the PIC
base address (@GOTOFF). */
- if (reload_in_progress)
- df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
+ set_pic_reg_ever_live ();
if (GET_CODE (addr) == CONST)
addr = XEXP (addr, 0);
if (GET_CODE (addr) == PLUS)
@@ -13203,8 +13223,7 @@ legitimize_pic_address (rtx orig, rtx reg)
/* This symbol may be referenced via a displacement from the PIC
base address (@GOTOFF). */
- if (reload_in_progress)
- df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
+ set_pic_reg_ever_live ();
if (GET_CODE (addr) == CONST)
addr = XEXP (addr, 0);
if (GET_CODE (addr) == PLUS)
@@ -13265,8 +13284,7 @@ legitimize_pic_address (rtx orig, rtx reg)
/* This symbol must be referenced via a load from the
Global Offset Table (@GOT). */
- if (reload_in_progress)
- df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
+ set_pic_reg_ever_live ();
new_rtx = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_GOT);
new_rtx = gen_rtx_CONST (Pmode, new_rtx);
if (TARGET_64BIT)
@@ -13318,8 +13336,7 @@ legitimize_pic_address (rtx orig, rtx reg)
{
if (!TARGET_64BIT)
{
- if (reload_in_progress)
- df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
+ set_pic_reg_ever_live ();
new_rtx = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op0),
UNSPEC_GOTOFF);
new_rtx = gen_rtx_PLUS (Pmode, new_rtx, op1);
@@ -13615,8 +13632,7 @@ legitimize_tls_address (rtx x, enum tls_model model, bool for_mov)
}
else if (flag_pic)
{
- if (reload_in_progress)
- df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
+ set_pic_reg_ever_live ();
pic = pic_offset_table_rtx;
type = TARGET_ANY_GNU_TLS ? UNSPEC_GOTNTPOFF : UNSPEC_GOTTPOFF;
}
@@ -14247,6 +14263,8 @@ ix86_pic_register_p (rtx x)
if (GET_CODE (x) == VALUE && CSELIB_VAL_PTR (x))
return (pic_offset_table_rtx
&& rtx_equal_for_cselib_p (x, pic_offset_table_rtx));
+ else if (pic_offset_table_rtx)
+ return REG_P (x) && REGNO (x) == REGNO (pic_offset_table_rtx);
else
return REG_P (x) && REGNO (x) == PIC_OFFSET_TABLE_REGNUM;
}
@@ -14421,8 +14439,12 @@ ix86_delegitimize_address (rtx x)
leal (%ebx, %ecx, 4), %ecx
...
movl foo@GOTOFF(%ecx), %edx
- in which case we return (%ecx - %ebx) + foo. */
- if (pic_offset_table_rtx)
+ in which case we return (%ecx - %ebx) + foo.
+
+ Note that when pseudo_pic_reg is used we can generate it only
+ before reload_completed. */
+ if (pic_offset_table_rtx
+ && (!reload_completed || !ix86_use_pseudo_pic_reg ()))
result = gen_rtx_PLUS (Pmode, gen_rtx_MINUS (Pmode, copy_rtx (addend),
pic_offset_table_rtx),
result);
@@ -24899,7 +24921,12 @@ ix86_expand_call (rtx retval, rtx fnaddr, rtx callarg1,
&& DEFAULT_ABI != MS_ABI))
&& GET_CODE (XEXP (fnaddr, 0)) == SYMBOL_REF
&& ! SYMBOL_REF_LOCAL_P (XEXP (fnaddr, 0)))
- use_reg (&use, pic_offset_table_rtx);
+ {
+ use_reg (&use, gen_rtx_REG (Pmode, REAL_PIC_OFFSET_TABLE_REGNUM));
+ if (ix86_use_pseudo_pic_reg ())
+ emit_move_insn (gen_rtx_REG (Pmode, REAL_PIC_OFFSET_TABLE_REGNUM),
+ pic_offset_table_rtx);
+ }
}
if (TARGET_64BIT && INTVAL (callarg2) >= 0)
@@ -47413,6 +47440,10 @@ ix86_atomic_assign_expand_fenv (tree *hold, tree *clear, tree *update)
#define TARGET_FUNCTION_ARG_ADVANCE ix86_function_arg_advance
#undef TARGET_FUNCTION_ARG
#define TARGET_FUNCTION_ARG ix86_function_arg
+#undef TARGET_INIT_PIC_REG
+#define TARGET_INIT_PIC_REG ix86_init_pic_reg
+#undef TARGET_USE_PSEUDO_PIC_REG
+#define TARGET_USE_PSEUDO_PIC_REG ix86_use_pseudo_pic_reg
#undef TARGET_FUNCTION_ARG_BOUNDARY
#define TARGET_FUNCTION_ARG_BOUNDARY ix86_function_arg_boundary
#undef TARGET_PASS_BY_REFERENCE
diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h
index 63005460783..61beb6676c5 100644
--- a/gcc/config/i386/i386.h
+++ b/gcc/config/i386/i386.h
@@ -1233,12 +1233,14 @@ extern const char *host_detect_local_cpu (int argc, const char **argv);
#define REAL_PIC_OFFSET_TABLE_REGNUM BX_REG
-#define PIC_OFFSET_TABLE_REGNUM \
- ((TARGET_64BIT && (ix86_cmodel == CM_SMALL_PIC \
- || TARGET_PECOFF)) \
- || !flag_pic ? INVALID_REGNUM \
- : reload_completed ? REGNO (pic_offset_table_rtx) \
- : REAL_PIC_OFFSET_TABLE_REGNUM)
+#define PIC_OFFSET_TABLE_REGNUM \
+ ((TARGET_64BIT && (ix86_cmodel == CM_SMALL_PIC \
+ || TARGET_PECOFF)) \
+ || !flag_pic \
+ ? INVALID_REGNUM \
+ : pic_offset_table_rtx \
+ ? INVALID_REGNUM \
+ : REAL_PIC_OFFSET_TABLE_REGNUM)
#define GOT_SYMBOL_NAME "_GLOBAL_OFFSET_TABLE_"