summaryrefslogtreecommitdiff
path: root/gcc/config/i386/i386.c
diff options
context:
space:
mode:
authorbstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4>2010-10-06 08:59:14 +0000
committerbstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4>2010-10-06 08:59:14 +0000
commit5a162b7ae6b7d344af6a033e922bc5e0e77eb6aa (patch)
tree56aca246b6ab6aeda938b1018391b7f1c5d7df72 /gcc/config/i386/i386.c
parentf68b5712b23021c39d8c91b2c98130266b9504a3 (diff)
downloadgcc-5a162b7ae6b7d344af6a033e922bc5e0e77eb6aa.tar.gz
2010-10-06 Basile Starynkevitch <basile@starynkevitch.net>
MELT branch merged with trunk rev 165014 git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/melt-branch@165017 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/config/i386/i386.c')
-rw-r--r--gcc/config/i386/i386.c482
1 files changed, 423 insertions, 59 deletions
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index 627d8d20ea0..7fe654a3586 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -1898,7 +1898,6 @@ int x86_prefetch_sse;
static int ix86_regparm;
/* -mstackrealign option */
-extern int ix86_force_align_arg_pointer;
static const char ix86_force_align_arg_pointer_string[]
= "force_align_arg_pointer";
@@ -1989,6 +1988,8 @@ static void ix86_add_new_builtins (int);
static rtx ix86_expand_vec_perm_builtin (tree);
static tree ix86_canonical_va_list_type (tree);
static void predict_jump (int);
+static unsigned int split_stack_prologue_scratch_regno (void);
+static bool i386_asm_output_addr_const_extra (FILE *, rtx);
enum ix86_function_specific_strings
{
@@ -2630,6 +2631,7 @@ ix86_target_string (int isa, int flags, const char *arch, const char *tune,
{ "-msseregparm", MASK_SSEREGPARM },
{ "-mstack-arg-probe", MASK_STACK_PROBE },
{ "-mtls-direct-seg-refs", MASK_TLS_DIRECT_SEG_REFS },
+ { "-mvect8-ret-in-mem", MASK_VECT8_RETURNS },
{ "-m8bit-idiv", MASK_USE_8BIT_IDIV },
};
@@ -3649,7 +3651,7 @@ ix86_option_override_internal (bool main_args_p)
/* If using typedef char *va_list, signal that __builtin_va_start (&ap, 0)
can be optimized to ap = __builtin_next_arg (0). */
- if (!TARGET_64BIT)
+ if (!TARGET_64BIT && !flag_split_stack)
targetm.expand_builtin_va_start = NULL;
if (TARGET_64BIT)
@@ -3800,7 +3802,7 @@ ix86_function_specific_save (struct cl_target_option *ptr)
ptr->tune_defaulted = ix86_tune_defaulted;
ptr->arch_specified = ix86_arch_specified;
ptr->ix86_isa_flags_explicit = ix86_isa_flags_explicit;
- ptr->target_flags_explicit = target_flags_explicit;
+ ptr->ix86_target_flags_explicit = target_flags_explicit;
/* The fields are char but the variables are not; make sure the
values fit in the fields. */
@@ -3829,7 +3831,7 @@ ix86_function_specific_restore (struct cl_target_option *ptr)
ix86_tune_defaulted = ptr->tune_defaulted;
ix86_arch_specified = ptr->arch_specified;
ix86_isa_flags_explicit = ptr->ix86_isa_flags_explicit;
- target_flags_explicit = ptr->target_flags_explicit;
+ target_flags_explicit = ptr->ix86_target_flags_explicit;
/* Recreate the arch feature tests if the arch changed */
if (old_arch != ix86_arch)
@@ -3857,7 +3859,7 @@ ix86_function_specific_print (FILE *file, int indent,
struct cl_target_option *ptr)
{
char *target_string
- = ix86_target_string (ptr->ix86_isa_flags, ptr->target_flags,
+ = ix86_target_string (ptr->x_ix86_isa_flags, ptr->x_target_flags,
NULL, NULL, NULL, false);
fprintf (file, "%*sarch = %d (%s)\n",
@@ -4114,8 +4116,8 @@ ix86_valid_target_attribute_tree (tree args)
ix86_option_override_internal, and then save the options away.
The string options are are attribute options, and will be undone
when we copy the save structure. */
- if (ix86_isa_flags != def->ix86_isa_flags
- || target_flags != def->target_flags
+ if (ix86_isa_flags != def->x_ix86_isa_flags
+ || target_flags != def->x_target_flags
|| option_strings[IX86_FUNCTION_SPECIFIC_ARCH]
|| option_strings[IX86_FUNCTION_SPECIFIC_TUNE]
|| option_strings[IX86_FUNCTION_SPECIFIC_FPMATH])
@@ -4178,11 +4180,12 @@ ix86_valid_target_attribute_p (tree fndecl,
/* If the function changed the optimization levels as well as setting target
options, start with the optimizations specified. */
if (func_optimize && func_optimize != old_optimize)
- cl_optimization_restore (TREE_OPTIMIZATION (func_optimize));
+ cl_optimization_restore (&global_options,
+ TREE_OPTIMIZATION (func_optimize));
/* The target attributes may also change some optimization flags, so update
the optimization options if necessary. */
- cl_target_option_save (&cur_target);
+ cl_target_option_save (&cur_target, &global_options);
new_target = ix86_valid_target_attribute_tree (args);
new_optimize = build_optimization_node ();
@@ -4197,10 +4200,11 @@ ix86_valid_target_attribute_p (tree fndecl,
DECL_FUNCTION_SPECIFIC_OPTIMIZATION (fndecl) = new_optimize;
}
- cl_target_option_restore (&cur_target);
+ cl_target_option_restore (&global_options, &cur_target);
if (old_optimize != new_optimize)
- cl_optimization_restore (TREE_OPTIMIZATION (old_optimize));
+ cl_optimization_restore (&global_options,
+ TREE_OPTIMIZATION (old_optimize));
return ret;
}
@@ -4232,12 +4236,12 @@ ix86_can_inline_p (tree caller, tree callee)
/* Callee's isa options should a subset of the caller's, i.e. a SSE4 function
can inline a SSE2 function but a SSE2 function can't inline a SSE4
function. */
- if ((caller_opts->ix86_isa_flags & callee_opts->ix86_isa_flags)
- != callee_opts->ix86_isa_flags)
+ if ((caller_opts->x_ix86_isa_flags & callee_opts->x_ix86_isa_flags)
+ != callee_opts->x_ix86_isa_flags)
ret = false;
/* See if we have the same non-isa options. */
- else if (caller_opts->target_flags != callee_opts->target_flags)
+ else if (caller_opts->x_target_flags != callee_opts->x_target_flags)
ret = false;
/* See if arch, tune, etc. are the same. */
@@ -4289,7 +4293,8 @@ ix86_set_current_function (tree fndecl)
else if (new_tree)
{
- cl_target_option_restore (TREE_TARGET_OPTION (new_tree));
+ cl_target_option_restore (&global_options,
+ TREE_TARGET_OPTION (new_tree));
target_reinit ();
}
@@ -4298,7 +4303,7 @@ ix86_set_current_function (tree fndecl)
struct cl_target_option *def
= TREE_TARGET_OPTION (target_option_current_node);
- cl_target_option_restore (def);
+ cl_target_option_restore (&global_options, def);
target_reinit ();
}
}
@@ -4890,6 +4895,10 @@ ix86_function_regparm (const_tree type, const_tree decl)
if (local_regparm == 3 && DECL_STATIC_CHAIN (decl))
local_regparm = 2;
+ /* In 32-bit mode save a register for the split stack. */
+ if (!TARGET_64BIT && local_regparm == 3 && flag_split_stack)
+ local_regparm = 2;
+
/* Each fixed register usage increases register pressure,
so less registers should be used for argument passing.
This functionality can be overriden by an explicit
@@ -6843,9 +6852,9 @@ return_in_memory_32 (const_tree type, enum machine_mode mode)
return false;
/* MMX/3dNow values are returned in MM0,
- except when it doesn't exits. */
+ except when it doesn't exits or the ABI prescribes otherwise. */
if (size == 8)
- return !TARGET_MMX;
+ return !TARGET_MMX || TARGET_VECT8_RETURNS;
/* SSE values are returned in XMM0, except when it doesn't exist. */
if (size == 16)
@@ -6909,43 +6918,6 @@ ix86_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
#endif
}
-/* Return false iff TYPE is returned in memory. This version is used
- on Solaris 2. It is similar to the generic ix86_return_in_memory,
- but differs notably in that when MMX is available, 8-byte vectors
- are returned in memory, rather than in MMX registers. */
-
-bool
-ix86_solaris_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
-{
- int size;
- enum machine_mode mode = type_natural_mode (type, NULL);
-
- if (TARGET_64BIT)
- return return_in_memory_64 (type, mode);
-
- if (mode == BLKmode)
- return 1;
-
- size = int_size_in_bytes (type);
-
- if (VECTOR_MODE_P (mode))
- {
- /* Return in memory only if MMX registers *are* available. This
- seems backwards, but it is consistent with the existing
- Solaris x86 ABI. */
- if (size == 8)
- return TARGET_MMX;
- if (size == 16)
- return !TARGET_SSE;
- }
- else if (mode == TImode)
- return !TARGET_SSE;
- else if (mode == XFmode)
- return 0;
-
- return size > 12;
-}
-
/* When returning SSE vector types, we have a choice of either
(1) being abi incompatible with a -march switch, or
(2) generating an error.
@@ -7248,10 +7220,56 @@ ix86_va_start (tree valist, rtx nextarg)
tree gpr, fpr, ovf, sav, t;
tree type;
+ rtx ovf_rtx;
+
+ if (flag_split_stack
+ && cfun->machine->split_stack_varargs_pointer == NULL_RTX)
+ {
+ unsigned int scratch_regno;
+
+ /* When we are splitting the stack, we can't refer to the stack
+ arguments using internal_arg_pointer, because they may be on
+ the old stack. The split stack prologue will arrange to
+ leave a pointer to the old stack arguments in a scratch
+ register, which we here copy to a pseudo-register. The split
+ stack prologue can't set the pseudo-register directly because
+ it (the prologue) runs before any registers have been saved. */
+
+ scratch_regno = split_stack_prologue_scratch_regno ();
+ if (scratch_regno != INVALID_REGNUM)
+ {
+ rtx reg, seq;
+
+ reg = gen_reg_rtx (Pmode);
+ cfun->machine->split_stack_varargs_pointer = reg;
+
+ start_sequence ();
+ emit_move_insn (reg, gen_rtx_REG (Pmode, scratch_regno));
+ seq = get_insns ();
+ end_sequence ();
+
+ push_topmost_sequence ();
+ emit_insn_after (seq, entry_of_function ());
+ pop_topmost_sequence ();
+ }
+ }
+
/* Only 64bit target needs something special. */
if (!TARGET_64BIT || is_va_list_char_pointer (TREE_TYPE (valist)))
{
- std_expand_builtin_va_start (valist, nextarg);
+ if (cfun->machine->split_stack_varargs_pointer == NULL_RTX)
+ std_expand_builtin_va_start (valist, nextarg);
+ else
+ {
+ rtx va_r, next;
+
+ va_r = expand_expr (valist, NULL_RTX, VOIDmode, EXPAND_WRITE);
+ next = expand_binop (ptr_mode, add_optab,
+ cfun->machine->split_stack_varargs_pointer,
+ crtl->args.arg_offset_rtx,
+ NULL_RTX, 0, OPTAB_LIB_WIDEN);
+ convert_move (va_r, next, 0);
+ }
return;
}
@@ -7297,7 +7315,11 @@ ix86_va_start (tree valist, rtx nextarg)
/* Find the overflow area. */
type = TREE_TYPE (ovf);
- t = make_tree (type, crtl->args.internal_arg_pointer);
+ if (cfun->machine->split_stack_varargs_pointer == NULL_RTX)
+ ovf_rtx = crtl->args.internal_arg_pointer;
+ else
+ ovf_rtx = cfun->machine->split_stack_varargs_pointer;
+ t = make_tree (type, ovf_rtx);
if (words != 0)
t = build2 (POINTER_PLUS_EXPR, type, t,
size_int (words * UNITS_PER_WORD));
@@ -7502,6 +7524,8 @@ ix86_gimplify_va_arg (tree valist, tree type, gimple_seq *pre_p,
tree dest_addr, dest;
int cur_size = GET_MODE_SIZE (mode);
+ gcc_assert (prev_size <= INTVAL (XEXP (slot, 1)));
+ prev_size = INTVAL (XEXP (slot, 1));
if (prev_size + cur_size > size)
{
cur_size = size - prev_size;
@@ -7534,7 +7558,7 @@ ix86_gimplify_va_arg (tree valist, tree type, gimple_seq *pre_p,
dest_addr = fold_convert (daddr_type, addr);
dest_addr = fold_build2 (POINTER_PLUS_EXPR, daddr_type, dest_addr,
- size_int (INTVAL (XEXP (slot, 1))));
+ size_int (prev_size));
if (cur_size == GET_MODE_SIZE (mode))
{
src = build_va_arg_indirect_ref (src_addr);
@@ -8042,6 +8066,9 @@ ix86_code_end (void)
set_cfun (NULL);
current_function_decl = NULL;
}
+
+ if (flag_split_stack)
+ file_end_indicate_split_stack ();
}
/* Emit code for the SET_GOT patterns. */
@@ -8344,6 +8371,37 @@ ix86_builtin_setjmp_frame_value (void)
return stack_realign_fp ? hard_frame_pointer_rtx : virtual_stack_vars_rtx;
}
+/* On the x86 -fsplit-stack and -fstack-protector both use the same
+ field in the TCB, so they can not be used together. */
+
+static bool
+ix86_supports_split_stack (bool report ATTRIBUTE_UNUSED)
+{
+ bool ret = true;
+
+#ifndef TARGET_THREAD_SPLIT_STACK_OFFSET
+ if (report)
+ error ("%<-fsplit-stack%> currently only supported on GNU/Linux");
+ ret = false;
+#else
+ if (!HAVE_GAS_CFI_PERSONALITY_DIRECTIVE)
+ {
+ if (report)
+ error ("%<-fsplit-stack%> requires "
+ "assembler support for CFI directives");
+ ret = false;
+ }
+#endif
+
+ return ret;
+}
+
+/* When using -fsplit-stack, the allocation routines set a field in
+ the TCB to the bottom of the stack plus this much space, measured
+ in bytes. */
+
+#define SPLIT_STACK_AVAILABLE 256
+
/* Fill structure ix86_frame about frame of currently computed function. */
static void
@@ -10334,6 +10392,277 @@ ix86_output_function_epilogue (FILE *file ATTRIBUTE_UNUSED,
#endif
}
+
+/* Return a scratch register to use in the split stack prologue. The
+ split stack prologue is used for -fsplit-stack. It is the first
+ instructions in the function, even before the regular prologue.
+ The scratch register can be any caller-saved register which is not
+ used for parameters or for the static chain. */
+
+static unsigned int
+split_stack_prologue_scratch_regno (void)
+{
+ if (TARGET_64BIT)
+ return R11_REG;
+ else
+ {
+ bool is_fastcall;
+ int regparm;
+
+ is_fastcall = (lookup_attribute ("fastcall",
+ TYPE_ATTRIBUTES (TREE_TYPE (cfun->decl)))
+ != NULL);
+ regparm = ix86_function_regparm (TREE_TYPE (cfun->decl), cfun->decl);
+
+ if (is_fastcall)
+ {
+ if (DECL_STATIC_CHAIN (cfun->decl))
+ {
+ sorry ("-fsplit-stack does not support fastcall with "
+ "nested function");
+ return INVALID_REGNUM;
+ }
+ return AX_REG;
+ }
+ else if (regparm < 3)
+ {
+ if (!DECL_STATIC_CHAIN (cfun->decl))
+ return CX_REG;
+ else
+ {
+ if (regparm >= 2)
+ {
+ sorry ("-fsplit-stack does not support 2 register "
+ " parameters for a nested function");
+ return INVALID_REGNUM;
+ }
+ return DX_REG;
+ }
+ }
+ else
+ {
+ /* FIXME: We could make this work by pushing a register
+ around the addition and comparison. */
+ sorry ("-fsplit-stack does not support 3 register parameters");
+ return INVALID_REGNUM;
+ }
+ }
+}
+
+/* A SYMBOL_REF for the function which allocates new stackspace for
+ -fsplit-stack. */
+
+static GTY(()) rtx split_stack_fn;
+
+/* Handle -fsplit-stack. These are the first instructions in the
+ function, even before the regular prologue. */
+
+void
+ix86_expand_split_stack_prologue (void)
+{
+ struct ix86_frame frame;
+ HOST_WIDE_INT allocate;
+ int args_size;
+ rtx label, limit, current, jump_insn, allocate_rtx, call_insn, call_fusage;
+ rtx scratch_reg = NULL_RTX;
+ rtx varargs_label = NULL_RTX;
+
+ gcc_assert (flag_split_stack && reload_completed);
+
+ ix86_finalize_stack_realign_flags ();
+ ix86_compute_frame_layout (&frame);
+ allocate = frame.stack_pointer_offset - INCOMING_FRAME_SP_OFFSET;
+
+ /* This is the label we will branch to if we have enough stack
+ space. We expect the basic block reordering pass to reverse this
+ branch if optimizing, so that we branch in the unlikely case. */
+ label = gen_label_rtx ();
+
+ /* We need to compare the stack pointer minus the frame size with
+ the stack boundary in the TCB. The stack boundary always gives
+ us SPLIT_STACK_AVAILABLE bytes, so if we need less than that we
+ can compare directly. Otherwise we need to do an addition. */
+
+ limit = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx),
+ UNSPEC_STACK_CHECK);
+ limit = gen_rtx_CONST (Pmode, limit);
+ limit = gen_rtx_MEM (Pmode, limit);
+ if (allocate < SPLIT_STACK_AVAILABLE)
+ current = stack_pointer_rtx;
+ else
+ {
+ unsigned int scratch_regno;
+ rtx offset;
+
+ /* We need a scratch register to hold the stack pointer minus
+ the required frame size. Since this is the very start of the
+ function, the scratch register can be any caller-saved
+ register which is not used for parameters. */
+ offset = GEN_INT (- allocate);
+ scratch_regno = split_stack_prologue_scratch_regno ();
+ if (scratch_regno == INVALID_REGNUM)
+ return;
+ scratch_reg = gen_rtx_REG (Pmode, scratch_regno);
+ if (!TARGET_64BIT || x86_64_immediate_operand (offset, Pmode))
+ {
+ /* We don't use ix86_gen_add3 in this case because it will
+ want to split to lea, but when not optimizing the insn
+ will not be split after this point. */
+ emit_insn (gen_rtx_SET (VOIDmode, scratch_reg,
+ gen_rtx_PLUS (Pmode, stack_pointer_rtx,
+ offset)));
+ }
+ else
+ {
+ emit_move_insn (scratch_reg, offset);
+ emit_insn (gen_adddi3 (scratch_reg, scratch_reg,
+ stack_pointer_rtx));
+ }
+ current = scratch_reg;
+ }
+
+ ix86_expand_branch (GEU, current, limit, label);
+ jump_insn = get_last_insn ();
+ JUMP_LABEL (jump_insn) = label;
+
+ /* Mark the jump as very likely to be taken. */
+ add_reg_note (jump_insn, REG_BR_PROB,
+ GEN_INT (REG_BR_PROB_BASE - REG_BR_PROB_BASE / 100));
+
+ /* Get more stack space. We pass in the desired stack space and the
+ size of the arguments to copy to the new stack. In 32-bit mode
+ we push the parameters; __morestack will return on a new stack
+ anyhow. In 64-bit mode we pass the parameters in r10 and
+ r11. */
+ allocate_rtx = GEN_INT (allocate);
+ args_size = crtl->args.size >= 0 ? crtl->args.size : 0;
+ call_fusage = NULL_RTX;
+ if (TARGET_64BIT)
+ {
+ rtx reg;
+
+ reg = gen_rtx_REG (Pmode, R10_REG);
+
+ /* If this function uses a static chain, it will be in %r10.
+ Preserve it across the call to __morestack. */
+ if (DECL_STATIC_CHAIN (cfun->decl))
+ {
+ rtx rax;
+
+ rax = gen_rtx_REG (Pmode, AX_REG);
+ emit_move_insn (rax, reg);
+ use_reg (&call_fusage, rax);
+ }
+
+ emit_move_insn (reg, allocate_rtx);
+ use_reg (&call_fusage, reg);
+ reg = gen_rtx_REG (Pmode, R11_REG);
+ emit_move_insn (reg, GEN_INT (args_size));
+ use_reg (&call_fusage, reg);
+ }
+ else
+ {
+ emit_insn (gen_push (GEN_INT (args_size)));
+ emit_insn (gen_push (allocate_rtx));
+ }
+ if (split_stack_fn == NULL_RTX)
+ split_stack_fn = gen_rtx_SYMBOL_REF (Pmode, "__morestack");
+ call_insn = ix86_expand_call (NULL_RTX, gen_rtx_MEM (QImode, split_stack_fn),
+ GEN_INT (UNITS_PER_WORD), constm1_rtx,
+ NULL_RTX, 0);
+ add_function_usage_to (call_insn, call_fusage);
+
+ /* In order to make call/return prediction work right, we now need
+ to execute a return instruction. See
+ libgcc/config/i386/morestack.S for the details on how this works.
+
+ For flow purposes gcc must not see this as a return
+ instruction--we need control flow to continue at the subsequent
+ label. Therefore, we use an unspec. */
+ gcc_assert (crtl->args.pops_args < 65536);
+ emit_insn (gen_split_stack_return (GEN_INT (crtl->args.pops_args)));
+
+ /* If we are in 64-bit mode and this function uses a static chain,
+ we saved %r10 in %rax before calling _morestack. */
+ if (TARGET_64BIT && DECL_STATIC_CHAIN (cfun->decl))
+ emit_move_insn (gen_rtx_REG (Pmode, R10_REG),
+ gen_rtx_REG (Pmode, AX_REG));
+
+ /* If this function calls va_start, we need to store a pointer to
+ the arguments on the old stack, because they may not have been
+ all copied to the new stack. At this point the old stack can be
+ found at the frame pointer value used by __morestack, because
+ __morestack has set that up before calling back to us. Here we
+ store that pointer in a scratch register, and in
+ ix86_expand_prologue we store the scratch register in a stack
+ slot. */
+ if (cfun->machine->split_stack_varargs_pointer != NULL_RTX)
+ {
+ unsigned int scratch_regno;
+ rtx frame_reg;
+ int words;
+
+ scratch_regno = split_stack_prologue_scratch_regno ();
+ scratch_reg = gen_rtx_REG (Pmode, scratch_regno);
+ frame_reg = gen_rtx_REG (Pmode, BP_REG);
+
+ /* 64-bit:
+ fp -> old fp value
+ return address within this function
+ return address of caller of this function
+ stack arguments
+ So we add three words to get to the stack arguments.
+
+ 32-bit:
+ fp -> old fp value
+ return address within this function
+ first argument to __morestack
+ second argument to __morestack
+ return address of caller of this function
+ stack arguments
+ So we add five words to get to the stack arguments.
+ */
+ words = TARGET_64BIT ? 3 : 5;
+ emit_insn (gen_rtx_SET (VOIDmode, scratch_reg,
+ gen_rtx_PLUS (Pmode, frame_reg,
+ GEN_INT (words * UNITS_PER_WORD))));
+
+ varargs_label = gen_label_rtx ();
+ emit_jump_insn (gen_jump (varargs_label));
+ JUMP_LABEL (get_last_insn ()) = varargs_label;
+
+ emit_barrier ();
+ }
+
+ emit_label (label);
+ LABEL_NUSES (label) = 1;
+
+ /* If this function calls va_start, we now have to set the scratch
+ register for the case where we do not call __morestack. In this
+ case we need to set it based on the stack pointer. */
+ if (cfun->machine->split_stack_varargs_pointer != NULL_RTX)
+ {
+ emit_insn (gen_rtx_SET (VOIDmode, scratch_reg,
+ gen_rtx_PLUS (Pmode, stack_pointer_rtx,
+ GEN_INT (UNITS_PER_WORD))));
+
+ emit_label (varargs_label);
+ LABEL_NUSES (varargs_label) = 1;
+ }
+}
+
+/* We may have to tell the dataflow pass that the split stack prologue
+ is initializing a scratch register. */
+
+static void
+ix86_live_on_entry (bitmap regs)
+{
+ if (cfun->machine->split_stack_varargs_pointer != NULL_RTX)
+ {
+ gcc_assert (flag_split_stack);
+ bitmap_set_bit (regs, split_stack_prologue_scratch_regno ());
+ }
+}
/* Extract the parts of an RTL expression that is a valid memory address
for an instruction. Return 0 if the structure of the address is
@@ -10979,6 +11308,10 @@ ix86_legitimate_address_p (enum machine_mode mode ATTRIBUTE_UNUSED,
case UNSPEC_DTPOFF:
break;
+ case UNSPEC_STACK_CHECK:
+ gcc_assert (flag_split_stack);
+ break;
+
default:
/* Invalid address unspec. */
return false;
@@ -11870,6 +12203,13 @@ output_pic_addr_const (FILE *file, rtx x, int code)
break;
case UNSPEC:
+ if (XINT (x, 1) == UNSPEC_STACK_CHECK)
+ {
+ bool f = i386_asm_output_addr_const_extra (file, x);
+ gcc_assert (f);
+ break;
+ }
+
gcc_assert (XVECLEN (x, 0) == 1);
output_pic_addr_const (file, XVECEXP (x, 0, 0), code);
switch (XINT (x, 1))
@@ -13273,6 +13613,22 @@ i386_asm_output_addr_const_extra (FILE *file, rtx x)
break;
#endif
+ case UNSPEC_STACK_CHECK:
+ {
+ int offset;
+
+ gcc_assert (flag_split_stack);
+
+#ifdef TARGET_THREAD_SPLIT_STACK_OFFSET
+ offset = TARGET_THREAD_SPLIT_STACK_OFFSET;
+#else
+ gcc_unreachable ();
+#endif
+
+ fprintf (file, "%s:%d", TARGET_64BIT ? "%fs" : "%gs", offset);
+ }
+ break;
+
default:
return false;
}
@@ -20359,7 +20715,7 @@ construct_plt_address (rtx symbol)
return tmp;
}
-void
+rtx
ix86_expand_call (rtx retval, rtx fnaddr, rtx callarg1,
rtx callarg2,
rtx pop, int sibcall)
@@ -20450,6 +20806,8 @@ ix86_expand_call (rtx retval, rtx fnaddr, rtx callarg1,
call = emit_call_insn (call);
if (use)
CALL_INSN_FUNCTION_USAGE (call) = use;
+
+ return call;
}
@@ -32856,6 +33214,9 @@ ix86_units_per_simd_word (enum machine_mode mode)
#undef TARGET_STACK_PROTECT_FAIL
#define TARGET_STACK_PROTECT_FAIL ix86_stack_protect_fail
+#undef TARGET_SUPPORTS_SPLIT_STACK
+#define TARGET_SUPPORTS_SPLIT_STACK ix86_supports_split_stack
+
#undef TARGET_FUNCTION_VALUE
#define TARGET_FUNCTION_VALUE ix86_function_value
@@ -32914,6 +33275,9 @@ ix86_units_per_simd_word (enum machine_mode mode)
#undef TARGET_CAN_ELIMINATE
#define TARGET_CAN_ELIMINATE ix86_can_eliminate
+#undef TARGET_EXTRA_LIVE_ON_ENTRY
+#define TARGET_EXTRA_LIVE_ON_ENTRY ix86_live_on_entry
+
#undef TARGET_ASM_CODE_END
#define TARGET_ASM_CODE_END ix86_code_end