aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2015-05-20 10:56:28 +0930
committerAlan Modra <amodra@gcc.gnu.org>2015-05-20 10:56:28 +0930
commit0f0fd745255adf8b2904b0acaf1c3b66ec93ddb2 (patch)
tree25d754bde890f2750c3489f49713ea0123e09339 /gcc
parent8a03f86937467dcfe401b4f369307faf2593e97a (diff)
downloadgcc-0f0fd745255adf8b2904b0acaf1c3b66ec93ddb2.zip
gcc-0f0fd745255adf8b2904b0acaf1c3b66ec93ddb2.tar.gz
gcc-0f0fd745255adf8b2904b0acaf1c3b66ec93ddb2.tar.bz2
rs6000-common.c (TARGET_SUPPORTS_SPLIT_STACK): Define.
gcc/ * common/config/rs6000/rs6000-common.c (TARGET_SUPPORTS_SPLIT_STACK): Define. (rs6000_supports_split_stack): New function. * gcc/config/rs6000/rs6000.c (machine_function): Add split_stack_arg_pointer. (TARGET_EXTRA_LIVE_ON_ENTRY, TARGET_INTERNAL_ARG_POINTER): Define. (setup_incoming_varargs): Use crtl->args.internal_arg_pointer rather than virtual_incoming_args_rtx. (rs6000_va_start): Likewise. (split_stack_arg_pointer_used_p): New function. (rs6000_emit_prologue): Set up arg pointer for -fsplit-stack. (morestack_ref): New var. (gen_add3_const, rs6000_expand_split_stack_prologue, rs6000_internal_arg_pointer, rs6000_live_on_entry, rs6000_split_stack_space_check): New functions. (rs6000_elf_file_end): Call file_end_indicate_split_stack. * gcc/config/rs6000/rs6000.md (UNSPEC_STACK_CHECK): Define. (UNSPECV_SPLIT_STACK_RETURN): Define. (split_stack_prologue, load_split_stack_limit, load_split_stack_limit_di, load_split_stack_limit_si, split_stack_return, split_stack_space_check): New expands and insns. * gcc/config/rs6000/rs6000-protos.h (rs6000_expand_split_stack_prologue): Declare. (rs6000_split_stack_space_check): Declare. libgcc/ * config/rs6000/morestack.S: New. * config/rs6000/t-stack-rs6000: New. * config.host (powerpc*-*-linux*): Add t-stack and t-stack-rs6000 to tmake_file. * generic-morestack.c: Don't build for powerpc 32-bit. From-SVN: r223426
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog27
-rw-r--r--gcc/common/config/rs6000/rs6000-common.c28
-rw-r--r--gcc/config/rs6000/rs6000-protos.h2
-rw-r--r--gcc/config/rs6000/rs6000.c264
-rw-r--r--gcc/config/rs6000/rs6000.md68
5 files changed, 387 insertions, 2 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 56b028d..471291c 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,32 @@
2015-05-20 Alan Modra <amodra@gmail.com>
+ * common/config/rs6000/rs6000-common.c (TARGET_SUPPORTS_SPLIT_STACK):
+ Define.
+ (rs6000_supports_split_stack): New function.
+ * gcc/config/rs6000/rs6000.c (machine_function): Add
+ split_stack_arg_pointer.
+ (TARGET_EXTRA_LIVE_ON_ENTRY, TARGET_INTERNAL_ARG_POINTER): Define.
+ (setup_incoming_varargs): Use crtl->args.internal_arg_pointer
+ rather than virtual_incoming_args_rtx.
+ (rs6000_va_start): Likewise.
+ (split_stack_arg_pointer_used_p): New function.
+ (rs6000_emit_prologue): Set up arg pointer for -fsplit-stack.
+ (morestack_ref): New var.
+ (gen_add3_const, rs6000_expand_split_stack_prologue,
+ rs6000_internal_arg_pointer, rs6000_live_on_entry,
+ rs6000_split_stack_space_check): New functions.
+ (rs6000_elf_file_end): Call file_end_indicate_split_stack.
+ * gcc/config/rs6000/rs6000.md (UNSPEC_STACK_CHECK): Define.
+ (UNSPECV_SPLIT_STACK_RETURN): Define.
+ (split_stack_prologue, load_split_stack_limit,
+ load_split_stack_limit_di, load_split_stack_limit_si,
+ split_stack_return, split_stack_space_check): New expands and insns.
+ * gcc/config/rs6000/rs6000-protos.h
+ (rs6000_expand_split_stack_prologue): Declare.
+ (rs6000_split_stack_space_check): Declare.
+
+2015-05-20 Alan Modra <amodra@gmail.com>
+
* config/rs6000/rs6000.c (struct rs6000_stack): Correct comments.
(rs6000_stack_info): Don't zero offsets when not saving registers.
(debug_stack_info): Adjust to omit printing unused offsets,
diff --git a/gcc/common/config/rs6000/rs6000-common.c b/gcc/common/config/rs6000/rs6000-common.c
index e0e158f..891bc55 100644
--- a/gcc/common/config/rs6000/rs6000-common.c
+++ b/gcc/common/config/rs6000/rs6000-common.c
@@ -288,6 +288,31 @@ rs6000_handle_option (struct gcc_options *opts, struct gcc_options *opts_set,
return true;
}
+/* -fsplit-stack uses a field in the TCB, available with glibc-2.19.
+ We also allow 2.18 because alignment padding guarantees that the
+ space is available there too. */
+
+static bool
+rs6000_supports_split_stack (bool report,
+ struct gcc_options *opts ATTRIBUTE_UNUSED)
+{
+#ifndef TARGET_GLIBC_MAJOR
+#define TARGET_GLIBC_MAJOR 0
+#endif
+#ifndef TARGET_GLIBC_MINOR
+#define TARGET_GLIBC_MINOR 0
+#endif
+ /* Note: Can't test DEFAULT_ABI here, it isn't set until later. */
+ if (TARGET_GLIBC_MAJOR * 1000 + TARGET_GLIBC_MINOR >= 2018
+ && TARGET_64BIT
+ && TARGET_ELF)
+ return true;
+
+ if (report)
+ error ("%<-fsplit-stack%> currently only supported on PowerPC64 GNU/Linux with glibc-2.18 or later");
+ return false;
+}
+
#undef TARGET_HANDLE_OPTION
#define TARGET_HANDLE_OPTION rs6000_handle_option
@@ -300,4 +325,7 @@ rs6000_handle_option (struct gcc_options *opts, struct gcc_options *opts_set,
#undef TARGET_OPTION_OPTIMIZATION_TABLE
#define TARGET_OPTION_OPTIMIZATION_TABLE rs6000_option_optimization_table
+#undef TARGET_SUPPORTS_SPLIT_STACK
+#define TARGET_SUPPORTS_SPLIT_STACK rs6000_supports_split_stack
+
struct gcc_targetm_common targetm_common = TARGETM_COMMON_INITIALIZER;
diff --git a/gcc/config/rs6000/rs6000-protos.h b/gcc/config/rs6000/rs6000-protos.h
index 739f1c6..bd1ede1 100644
--- a/gcc/config/rs6000/rs6000-protos.h
+++ b/gcc/config/rs6000/rs6000-protos.h
@@ -191,6 +191,8 @@ extern void rs6000_emit_prologue (void);
extern void rs6000_emit_load_toc_table (int);
extern unsigned int rs6000_dbx_register_number (unsigned int, unsigned int);
extern void rs6000_emit_epilogue (int);
+extern void rs6000_expand_split_stack_prologue (void);
+extern void rs6000_split_stack_space_check (rtx, rtx);
extern void rs6000_emit_eh_reg_restore (rtx, rtx);
extern const char * output_isel (rtx *);
extern void rs6000_call_aix (rtx, rtx, rtx, rtx);
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index 92ebd82..8947849 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -187,6 +187,8 @@ typedef struct GTY(()) machine_function
64-bits wide and is allocated early enough so that the offset
does not overflow the 16-bit load/store offset field. */
rtx sdmode_stack_slot;
+ /* Alternative internal arg pointer for -fsplit-stack. */
+ rtx split_stack_arg_pointer;
/* Flag if r2 setup is needed with ELFv2 ABI. */
bool r2_setup_needed;
} machine_function;
@@ -1190,6 +1192,7 @@ static bool rs6000_debug_cannot_change_mode_class (machine_mode,
machine_mode,
enum reg_class);
static bool rs6000_save_toc_in_prologue_p (void);
+static rtx rs6000_internal_arg_pointer (void);
rtx (*rs6000_legitimize_reload_address_ptr) (rtx, machine_mode, int, int,
int, int *)
@@ -1411,6 +1414,12 @@ static const struct attribute_spec rs6000_attribute_table[] =
#undef TARGET_SET_UP_BY_PROLOGUE
#define TARGET_SET_UP_BY_PROLOGUE rs6000_set_up_by_prologue
+#undef TARGET_EXTRA_LIVE_ON_ENTRY
+#define TARGET_EXTRA_LIVE_ON_ENTRY rs6000_live_on_entry
+
+#undef TARGET_INTERNAL_ARG_POINTER
+#define TARGET_INTERNAL_ARG_POINTER rs6000_internal_arg_pointer
+
#undef TARGET_HAVE_TLS
#define TARGET_HAVE_TLS HAVE_AS_TLS
@@ -11150,7 +11159,7 @@ setup_incoming_varargs (cumulative_args_t cum, machine_mode mode,
else
{
first_reg_offset = next_cum.words;
- save_area = virtual_incoming_args_rtx;
+ save_area = crtl->args.internal_arg_pointer;
if (targetm.calls.must_pass_in_stack (mode, type))
first_reg_offset += rs6000_arg_size (TYPE_MODE (type), type);
@@ -11344,7 +11353,7 @@ rs6000_va_start (tree valist, rtx nextarg)
}
/* Find the overflow area. */
- t = make_tree (TREE_TYPE (ovf), virtual_incoming_args_rtx);
+ t = make_tree (TREE_TYPE (ovf), crtl->args.internal_arg_pointer);
if (words != 0)
t = fold_build_pointer_plus_hwi (t, words * MIN_UNITS_PER_WORD);
t = build2 (MODIFY_EXPR, TREE_TYPE (ovf), ovf, t);
@@ -23424,6 +23433,48 @@ rs6000_reg_live_or_pic_offset_p (int reg)
|| (DEFAULT_ABI == ABI_DARWIN && flag_pic))));
}
+/* Return whether the split-stack arg pointer (r12) is used. */
+
+static bool
+split_stack_arg_pointer_used_p (void)
+{
+ /* If the pseudo holding the arg pointer is no longer a pseudo,
+ then the arg pointer is used. */
+ if (cfun->machine->split_stack_arg_pointer != NULL_RTX
+ && (!REG_P (cfun->machine->split_stack_arg_pointer)
+ || (REGNO (cfun->machine->split_stack_arg_pointer)
+ < FIRST_PSEUDO_REGISTER)))
+ return true;
+
+ /* Unfortunately we also need to do some code scanning, since
+ r12 may have been substituted for the pseudo. */
+ rtx_insn *insn;
+ basic_block bb = ENTRY_BLOCK_PTR_FOR_FN (cfun);
+ FOR_BB_INSNS (bb, insn)
+ if (NONDEBUG_INSN_P (insn))
+ {
+ /* A call destroys r12. */
+ if (CALL_P (insn))
+ return false;
+
+ df_ref use;
+ FOR_EACH_INSN_USE (use, insn)
+ {
+ rtx x = DF_REF_REG (use);
+ if (REG_P (x) && REGNO (x) == 12)
+ return true;
+ }
+ df_ref def;
+ FOR_EACH_INSN_DEF (def, insn)
+ {
+ rtx x = DF_REF_REG (def);
+ if (REG_P (x) && REGNO (x) == 12)
+ return false;
+ }
+ }
+ return bitmap_bit_p (DF_LR_OUT (bb), 12);
+}
+
/* Emit function prologue as insns. */
void
@@ -24375,6 +24426,40 @@ rs6000_emit_prologue (void)
rtx reg = gen_rtx_REG (reg_mode, TOC_REGNUM);
emit_insn (gen_frame_store (reg, sp_reg_rtx, RS6000_TOC_SAVE_SLOT));
}
+
+ if (flag_split_stack && split_stack_arg_pointer_used_p ())
+ {
+ /* Set up the arg pointer (r12) for -fsplit-stack code. If
+ __morestack was called, it left the arg pointer to the old
+ stack in r29. Otherwise, the arg pointer is the top of the
+ current frame. */
+ if (frame_off != 0 || REGNO (frame_reg_rtx) != 12)
+ {
+ rtx r12 = gen_rtx_REG (Pmode, 12);
+ if (frame_off == 0)
+ emit_move_insn (r12, frame_reg_rtx);
+ else
+ emit_insn (gen_add3_insn (r12, frame_reg_rtx, GEN_INT (frame_off)));
+ }
+ if (info->push_p)
+ {
+ rtx r12 = gen_rtx_REG (Pmode, 12);
+ rtx r29 = gen_rtx_REG (Pmode, 29);
+ rtx cr7 = gen_rtx_REG (CCUNSmode, CR7_REGNO);
+ rtx not_more = gen_label_rtx ();
+ rtx jump;
+
+ jump = gen_rtx_IF_THEN_ELSE (VOIDmode,
+ gen_rtx_GEU (VOIDmode, cr7, const0_rtx),
+ gen_rtx_LABEL_REF (VOIDmode, not_more),
+ pc_rtx);
+ jump = emit_jump_insn (gen_rtx_SET (pc_rtx, jump));
+ JUMP_LABEL (jump) = not_more;
+ LABEL_NUSES (not_more) += 1;
+ emit_move_insn (r12, r29);
+ emit_label (not_more);
+ }
+ }
}
/* Output .extern statements for the save/restore routines we use. */
@@ -25802,6 +25887,178 @@ rs6000_output_function_epilogue (FILE *file,
fputs ("\t.align 2\n", file);
}
}
+
+/* -fsplit-stack support. */
+
+/* A SYMBOL_REF for __morestack. */
+static GTY(()) rtx morestack_ref;
+
+static rtx
+gen_add3_const (rtx rt, rtx ra, long c)
+{
+ if (TARGET_64BIT)
+ return gen_adddi3 (rt, ra, GEN_INT (c));
+ else
+ return gen_addsi3 (rt, ra, GEN_INT (c));
+}
+
+/* Emit -fsplit-stack prologue, which goes before the regular function
+ prologue (at local entry point in the case of ELFv2). */
+
+void
+rs6000_expand_split_stack_prologue (void)
+{
+ rs6000_stack_t *info = rs6000_stack_info ();
+ unsigned HOST_WIDE_INT allocate;
+ long alloc_hi, alloc_lo;
+ rtx r0, r1, r12, lr, ok_label, compare, jump, call_fusage;
+ rtx_insn *insn;
+
+ gcc_assert (flag_split_stack && reload_completed);
+
+ if (!info->push_p)
+ return;
+
+ allocate = info->total_size;
+ if (allocate > (unsigned HOST_WIDE_INT) 1 << 31)
+ {
+ sorry ("Stack frame larger than 2G is not supported for -fsplit-stack");
+ return;
+ }
+ if (morestack_ref == NULL_RTX)
+ {
+ morestack_ref = gen_rtx_SYMBOL_REF (Pmode, "__morestack");
+ SYMBOL_REF_FLAGS (morestack_ref) |= (SYMBOL_FLAG_LOCAL
+ | SYMBOL_FLAG_FUNCTION);
+ }
+
+ r0 = gen_rtx_REG (Pmode, 0);
+ r1 = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM);
+ r12 = gen_rtx_REG (Pmode, 12);
+ emit_insn (gen_load_split_stack_limit (r0));
+ /* Always emit two insns here to calculate the requested stack,
+ so that the linker can edit them when adjusting size for calling
+ non-split-stack code. */
+ alloc_hi = (-allocate + 0x8000) & ~0xffffL;
+ alloc_lo = -allocate - alloc_hi;
+ if (alloc_hi != 0)
+ {
+ emit_insn (gen_add3_const (r12, r1, alloc_hi));
+ if (alloc_lo != 0)
+ emit_insn (gen_add3_const (r12, r12, alloc_lo));
+ else
+ emit_insn (gen_nop ());
+ }
+ else
+ {
+ emit_insn (gen_add3_const (r12, r1, alloc_lo));
+ emit_insn (gen_nop ());
+ }
+
+ compare = gen_rtx_REG (CCUNSmode, CR7_REGNO);
+ emit_insn (gen_rtx_SET (compare, gen_rtx_COMPARE (CCUNSmode, r12, r0)));
+ ok_label = gen_label_rtx ();
+ jump = gen_rtx_IF_THEN_ELSE (VOIDmode,
+ gen_rtx_GEU (VOIDmode, compare, const0_rtx),
+ gen_rtx_LABEL_REF (VOIDmode, ok_label),
+ pc_rtx);
+ jump = emit_jump_insn (gen_rtx_SET (pc_rtx, jump));
+ JUMP_LABEL (jump) = ok_label;
+ /* Mark the jump as very likely to be taken. */
+ add_int_reg_note (jump, REG_BR_PROB,
+ REG_BR_PROB_BASE - REG_BR_PROB_BASE / 100);
+
+ lr = gen_rtx_REG (Pmode, LR_REGNO);
+ insn = emit_move_insn (r0, lr);
+ RTX_FRAME_RELATED_P (insn) = 1;
+ insn = emit_insn (gen_frame_store (r0, r1, info->lr_save_offset));
+ RTX_FRAME_RELATED_P (insn) = 1;
+
+ insn = emit_call_insn (gen_call (gen_rtx_MEM (SImode, morestack_ref),
+ const0_rtx, const0_rtx));
+ call_fusage = NULL_RTX;
+ use_reg (&call_fusage, r12);
+ add_function_usage_to (insn, call_fusage);
+ emit_insn (gen_frame_load (r0, r1, info->lr_save_offset));
+ insn = emit_move_insn (lr, r0);
+ add_reg_note (insn, REG_CFA_RESTORE, lr);
+ RTX_FRAME_RELATED_P (insn) = 1;
+ emit_insn (gen_split_stack_return ());
+
+ emit_label (ok_label);
+ LABEL_NUSES (ok_label) = 1;
+}
+
+/* Return the internal arg pointer used for function incoming
+ arguments. When -fsplit-stack, the arg pointer is r12 so we need
+ to copy it to a pseudo in order for it to be preserved over calls
+ and suchlike. We'd really like to use a pseudo here for the
+ internal arg pointer but data-flow analysis is not prepared to
+ accept pseudos as live at the beginning of a function. */
+
+static rtx
+rs6000_internal_arg_pointer (void)
+{
+ if (flag_split_stack)
+ {
+ if (cfun->machine->split_stack_arg_pointer == NULL_RTX)
+ {
+ rtx pat;
+
+ cfun->machine->split_stack_arg_pointer = gen_reg_rtx (Pmode);
+ REG_POINTER (cfun->machine->split_stack_arg_pointer) = 1;
+
+ /* Put the pseudo initialization right after the note at the
+ beginning of the function. */
+ pat = gen_rtx_SET (cfun->machine->split_stack_arg_pointer,
+ gen_rtx_REG (Pmode, 12));
+ push_topmost_sequence ();
+ emit_insn_after (pat, get_insns ());
+ pop_topmost_sequence ();
+ }
+ return plus_constant (Pmode, cfun->machine->split_stack_arg_pointer,
+ FIRST_PARM_OFFSET (current_function_decl));
+ }
+ return virtual_incoming_args_rtx;
+}
+
+/* We may have to tell the dataflow pass that the split stack prologue
+ is initializing a register. */
+
+static void
+rs6000_live_on_entry (bitmap regs)
+{
+ if (flag_split_stack)
+ bitmap_set_bit (regs, 12);
+}
+
+/* Emit -fsplit-stack dynamic stack allocation space check. */
+
+void
+rs6000_split_stack_space_check (rtx size, rtx label)
+{
+ rtx sp = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM);
+ rtx limit = gen_reg_rtx (Pmode);
+ rtx requested = gen_reg_rtx (Pmode);
+ rtx cmp = gen_reg_rtx (CCUNSmode);
+ rtx jump;
+
+ emit_insn (gen_load_split_stack_limit (limit));
+ if (CONST_INT_P (size))
+ emit_insn (gen_add3_insn (requested, sp, GEN_INT (-INTVAL (size))));
+ else
+ {
+ size = force_reg (Pmode, size);
+ emit_move_insn (requested, gen_rtx_MINUS (Pmode, sp, size));
+ }
+ emit_insn (gen_rtx_SET (cmp, gen_rtx_COMPARE (CCUNSmode, requested, limit)));
+ jump = gen_rtx_IF_THEN_ELSE (VOIDmode,
+ gen_rtx_GEU (VOIDmode, cmp, const0_rtx),
+ gen_rtx_LABEL_REF (VOIDmode, label),
+ pc_rtx);
+ jump = emit_jump_insn (gen_rtx_SET (pc_rtx, jump));
+ JUMP_LABEL (jump) = label;
+}
/* A C compound statement that outputs the assembler code for a thunk
function, used to implement C++ virtual function calls with
@@ -29810,6 +30067,9 @@ rs6000_elf_file_end (void)
if (TARGET_32BIT || DEFAULT_ABI == ABI_ELFv2)
file_end_indicate_exec_stack ();
#endif
+
+ if (flag_split_stack)
+ file_end_indicate_split_stack ();
}
#endif
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index e156e14..5d3e04b 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -140,6 +140,7 @@
UNSPEC_PACK_128BIT
UNSPEC_LSQ
UNSPEC_FUSION_GPR
+ UNSPEC_STACK_CHECK
])
;;
@@ -157,6 +158,7 @@
UNSPECV_NLGR ; non-local goto receiver
UNSPECV_MFFS ; Move from FPSCR
UNSPECV_MTFSF ; Move to FPSCR Fields
+ UNSPECV_SPLIT_STACK_RETURN ; A camouflaged return
])
@@ -12345,6 +12347,72 @@
}"
[(set_attr "type" "load")])
+;; Handle -fsplit-stack.
+
+(define_expand "split_stack_prologue"
+ [(const_int 0)]
+ ""
+{
+ rs6000_expand_split_stack_prologue ();
+ DONE;
+})
+
+(define_expand "load_split_stack_limit"
+ [(set (match_operand 0)
+ (unspec [(const_int 0)] UNSPEC_STACK_CHECK))]
+ ""
+{
+ emit_insn (gen_rtx_SET (operands[0],
+ gen_rtx_UNSPEC (Pmode,
+ gen_rtvec (1, const0_rtx),
+ UNSPEC_STACK_CHECK)));
+ DONE;
+})
+
+(define_insn "load_split_stack_limit_di"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
+ (unspec:DI [(const_int 0)] UNSPEC_STACK_CHECK))]
+ "TARGET_64BIT"
+ "ld %0,-0x7040(13)"
+ [(set_attr "type" "load")
+ (set_attr "update" "no")
+ (set_attr "indexed" "no")])
+
+(define_insn "load_split_stack_limit_si"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (unspec:SI [(const_int 0)] UNSPEC_STACK_CHECK))]
+ "!TARGET_64BIT"
+ "lwz %0,-0x7020(2)"
+ [(set_attr "type" "load")
+ (set_attr "update" "no")
+ (set_attr "indexed" "no")])
+
+;; A return instruction which the middle-end doesn't see.
+(define_insn "split_stack_return"
+ [(unspec_volatile [(const_int 0)] UNSPECV_SPLIT_STACK_RETURN)]
+ ""
+ "blr"
+ [(set_attr "type" "jmpreg")])
+
+;; If there are operand 0 bytes available on the stack, jump to
+;; operand 1.
+(define_expand "split_stack_space_check"
+ [(set (match_dup 2)
+ (unspec [(const_int 0)] UNSPEC_STACK_CHECK))
+ (set (match_dup 3)
+ (minus (reg STACK_POINTER_REGNUM)
+ (match_operand 0)))
+ (set (match_dup 4) (compare:CCUNS (match_dup 3) (match_dup 2)))
+ (set (pc) (if_then_else
+ (geu (match_dup 4) (const_int 0))
+ (label_ref (match_operand 1))
+ (pc)))]
+ ""
+{
+ rs6000_split_stack_space_check (operands[0], operands[1]);
+ DONE;
+})
+
(define_insn "bpermd_<mode>"
[(set (match_operand:P 0 "gpc_reg_operand" "=r")
(unspec:P [(match_operand:P 1 "gpc_reg_operand" "r")