===================================================================
@@ -102,7 +102,6 @@ typedef struct case_node *case_node_ptr;
static int n_occurrences (int, const char *);
static bool tree_conflicts_with_clobbers_p (tree, HARD_REG_SET *);
-static void expand_nl_goto_receiver (void);
static bool check_operand_nalternatives (tree, tree);
static bool check_unique_operand_names (tree, tree, tree);
static char *resolve_operand_name_1 (char *, tree, tree, tree);
@@ -196,7 +195,7 @@ expand_label (tree label)
if (DECL_NONLOCAL (label))
{
- expand_nl_goto_receiver ();
+ expand_builtin_setjmp_receiver (NULL);
nonlocal_goto_handler_labels
= gen_rtx_EXPR_LIST (VOIDmode, label_r,
nonlocal_goto_handler_labels);
@@ -1552,77 +1551,6 @@ expand_return (tree retval)
}
}
-/* Emit code to restore vital registers at the beginning of a nonlocal goto
- handler. */
-static void
-expand_nl_goto_receiver (void)
-{
- rtx chain;
-
- /* Clobber the FP when we get here, so we have to make sure it's
- marked as used by this function. */
- emit_use (hard_frame_pointer_rtx);
-
- /* Mark the static chain as clobbered here so life information
- doesn't get messed up for it. */
- chain = targetm.calls.static_chain (current_function_decl, true);
- if (chain && REG_P (chain))
- emit_clobber (chain);
-
-#ifdef HAVE_nonlocal_goto
- if (! HAVE_nonlocal_goto)
-#endif
- /* First adjust our frame pointer to its actual value. It was
- previously set to the start of the virtual area corresponding to
- the stacked variables when we branched here and now needs to be
- adjusted to the actual hardware fp value.
-
- Assignments are to virtual registers are converted by
- instantiate_virtual_regs into the corresponding assignment
- to the underlying register (fp in this case) that makes
- the original assignment true.
- So the following insn will actually be
- decrementing fp by STARTING_FRAME_OFFSET. */
- emit_move_insn (virtual_stack_vars_rtx, hard_frame_pointer_rtx);
-
-#if !HARD_FRAME_POINTER_IS_ARG_POINTER
- if (fixed_regs[ARG_POINTER_REGNUM])
- {
-#ifdef ELIMINABLE_REGS
- /* If the argument pointer can be eliminated in favor of the
- frame pointer, we don't need to restore it. We assume here
- that if such an elimination is present, it can always be used.
- This is the case on all known machines; if we don't make this
- assumption, we do unnecessary saving on many machines. */
- static const struct elims {const int from, to;} elim_regs[] = ELIMINABLE_REGS;
- size_t i;
-
- for (i = 0; i < ARRAY_SIZE (elim_regs); i++)
- if (elim_regs[i].from == ARG_POINTER_REGNUM
- && elim_regs[i].to == HARD_FRAME_POINTER_REGNUM)
- break;
-
- if (i == ARRAY_SIZE (elim_regs))
-#endif
- {
- /* Now restore our arg pointer from the address at which it
- was saved in our stack frame. */
- emit_move_insn (crtl->args.internal_arg_pointer,
- copy_to_reg (get_arg_pointer_save_area ()));
- }
- }
-#endif
-
-#ifdef HAVE_nonlocal_goto_receiver
- if (HAVE_nonlocal_goto_receiver)
- emit_insn (gen_nonlocal_goto_receiver ());
-#endif
-
- /* We must not allow the code we just generated to be reordered by
- scheduling. Specifically, the update of the frame pointer must
- happen immediately, not later. */
- emit_insn (gen_blockage ());
-}
/* Emit code to save the current value of stack. */
rtx
===================================================================
@@ -885,14 +885,16 @@ expand_builtin_setjmp_setup (rtx buf_add
}
/* Construct the trailing part of a __builtin_setjmp call. This is
- also called directly by the SJLJ exception handling code. */
+ also called directly by the SJLJ exception handling code.
+ If RECEIVER_LABEL is NULL, instead the port-specific parts of a
+ nonlocal goto handler are emitted. */
void
expand_builtin_setjmp_receiver (rtx receiver_label ATTRIBUTE_UNUSED)
{
rtx chain;
- /* Clobber the FP when we get here, so we have to make sure it's
+ /* Mark the FP as used when we get here, so we have to make sure it's
marked as used by this function. */
emit_use (hard_frame_pointer_rtx);
@@ -907,12 +909,7 @@ expand_builtin_setjmp_receiver (rtx rece
#ifdef HAVE_nonlocal_goto
if (! HAVE_nonlocal_goto)
#endif
- {
- emit_move_insn (virtual_stack_vars_rtx, hard_frame_pointer_rtx);
- /* This might change the hard frame pointer in ways that aren't
- apparent to early optimization passes, so force a clobber. */
- emit_clobber (hard_frame_pointer_rtx);
- }
+ emit_move_insn (virtual_stack_vars_rtx, hard_frame_pointer_rtx);
#if !HARD_FRAME_POINTER_IS_ARG_POINTER
if (fixed_regs[ARG_POINTER_REGNUM])
@@ -938,7 +935,7 @@ expand_builtin_setjmp_receiver (rtx rece
#endif
#ifdef HAVE_builtin_setjmp_receiver
- if (HAVE_builtin_setjmp_receiver)
+ if (receiver_label != NULL && HAVE_builtin_setjmp_receiver)
emit_insn (gen_builtin_setjmp_receiver (receiver_label));
else
#endif
Oh, I almost forgot, there's a port-bug as well; the MMIX
nonlocal_goto_receiver need, in the pattern, naturally has to *refer*
to the frame-pointer for that to stay around. In built-in-setjmp.c
there's otherwise no other need: after __builtin_setjmp returns
non-zero (well, always 1), the function exits only through calls to
noreturn functions and there's no other frame-local data references
after the __builtin_setjmp call (the variable "p" is in a register).
I'll commit this together with the patch above if approved. Without
that, it has no effect on test-results. RTL dumps above are obviously
with this patch applied. :)
* config/mmix/mmix.md ("nonlocal_goto_receiver"): Refer to the
frame-pointer as an operand.
("*nonlocal_goto_receiver_expanded"): Ditto. Use
mmix_output_register_setting instead of naked output_asm_insn for
the offset from the frame-pointer to the saved rO.
* config/mmix/mmix.c (mmix_output_register_setting): Emit NEGU for
values -255..0.
* config/mmix/predicates.md ("frame_pointer_operand"): New.
* config/mmix/constraints.md ("Yf"): New.
@@ -1120,7 +1120,7 @@ DIVU %1,%1,%2\;GET %0,:rR\;NEGU %2,0,%0\
;; of "pop 0,0" until rO equals the saved value. (If it goes lower, we
;; should die with a trap.)
(define_expand "nonlocal_goto_receiver"
- [(parallel [(unspec_volatile [(const_int 0)] 1)
+ [(parallel [(unspec_volatile [(match_dup 1)] 1)
(clobber (scratch:DI))
(clobber (reg:DI MMIX_rJ_REGNUM))])
(set (reg:DI MMIX_rJ_REGNUM) (match_dup 0))]
@@ -1131,6 +1131,13 @@ DIVU %1,%1,%2\;GET %0,:rR\;NEGU %2,0,%0\
= mmix_get_hard_reg_initial_val (Pmode,
MMIX_INCOMING_RETURN_ADDRESS_REGNUM);
+ /* We need the frame-pointer to be live or the equivalent
+ expression, so refer to in in the pattern. We can't use a MEM
+ (that may contain out-of-range offsets in the final expression)
+ for fear that middle-end will legitimize it or replace the address
+ using temporary registers (which are not revived at this point). */
+ operands[1] = frame_pointer_rtx;
+
/* Mark this function as containing a landing-pad. */
cfun->machine->has_landing_pad = 1;
}")
@@ -1140,45 +1147,40 @@ DIVU %1,%1,%2\;GET %0,:rR\;NEGU %2,0,%0\
;; address and re-use them after the register stack unwind, so it's best
;; to form the address ourselves.
(define_insn "*nonlocal_goto_receiver_expanded"
- [(unspec_volatile [(const_int 0)] 1)
+ [(unspec_volatile [(match_operand:DI 1 "frame_pointer_operand" "Yf")] 1)
(clobber (match_scratch:DI 0 "=&r"))
(clobber (reg:DI MMIX_rJ_REGNUM))]
""
{
- rtx temp_reg = operands[0];
- rtx my_operands[2];
- HOST_WIDEST_INT offs;
+ rtx my_operands[3];
const char *my_template
= "GETA $255,0f\;PUT rJ,$255\;LDOU $255,%a0\n\
0:\;GET %1,rO\;CMPU %1,%1,$255\;BNP %1,1f\;POP 0,0\n1:";
- my_operands[1] = temp_reg;
+ my_operands[1] = operands[0];
+ my_operands[2] = GEN_INT (-MMIX_fp_rO_OFFSET);
- /* If we have a frame-pointer (hence unknown stack-pointer offset),
- just use the frame-pointer and the known offset. */
- if (frame_pointer_needed)
+ if (operands[1] == hard_frame_pointer_rtx)
{
- my_operands[0] = GEN_INT (-MMIX_fp_rO_OFFSET);
-
- output_asm_insn ("NEGU %1,0,%0", my_operands);
- my_operands[0] = gen_rtx_PLUS (Pmode, frame_pointer_rtx, temp_reg);
+ mmix_output_register_setting (asm_out_file, REGNO (operands[0]),
+ MMIX_fp_rO_OFFSET, 1);
+ my_operands[0]
+ = gen_rtx_PLUS (Pmode, hard_frame_pointer_rtx, operands[0]);
}
else
{
- /* We know the fp-based offset, so "eliminate" it to be sp-based. */
- offs
- = (mmix_initial_elimination_offset (MMIX_FRAME_POINTER_REGNUM,
- MMIX_STACK_POINTER_REGNUM)
- + MMIX_fp_rO_OFFSET);
+ HOST_WIDEST_INT offs = INTVAL (XEXP (operands[1], 1));
+ offs += MMIX_fp_rO_OFFSET;
- if (offs >= 0 && offs <= 255)
+ if (insn_const_int_ok_for_constraint (offs, CONSTRAINT_I))
my_operands[0]
= gen_rtx_PLUS (Pmode, stack_pointer_rtx, GEN_INT (offs));
else
{
- mmix_output_register_setting (asm_out_file, REGNO (temp_reg),
+ mmix_output_register_setting (asm_out_file, REGNO (operands[0]),
offs, 1);
- my_operands[0] = gen_rtx_PLUS (Pmode, stack_pointer_rtx, temp_reg);
+ my_operands[0]
+ = gen_rtx_PLUS (Pmode, stack_pointer_rtx, operands[0]);
}
}
@@ -2281,7 +2281,9 @@ mmix_output_register_setting (FILE *stre
if (do_begin_end)
fprintf (stream, "\t");
- if (mmix_shiftable_wyde_value ((unsigned HOST_WIDEST_INT) value))
+ if (insn_const_int_ok_for_constraint (value, CONSTRAINT_K))
+ fprintf (stream, "NEGU %s,0," HOST_WIDEST_INT_PRINT_DEC, reg_names[regno], -value);
+ else if (mmix_shiftable_wyde_value ((unsigned HOST_WIDEST_INT) value))
{
/* First, the one-insn cases. */
mmix_output_shiftvalue_op_from_str (stream, "SET",
@@ -161,3 +161,14 @@
(if_then_else (match_test "reload_in_progress || reload_completed")
(match_test "strict_memory_address_p (Pmode, op)")
(match_test "memory_address_p (Pmode, op)")))
+
+(define_predicate "frame_pointer_operand"
+ (ior
+ (and
+ (match_code "reg")
+ (match_test "op == hard_frame_pointer_rtx || op == frame_pointer_rtx"))
+ (and
+ (match_code "plus")
+ (match_code "reg" "0")
+ (match_code "const_int" "1")
+ (match_test "XEXP (op, 0) == stack_pointer_rtx"))))
@@ -110,3 +110,7 @@
(define_address_constraint "U"
"@internal"
(match_operand 0 "mmix_address_operand"))
+
+(define_constraint "Yf"
+ "@internal"
+ (match_operand 0 "frame_pointer_operand"))