* flags.h: (current_function_has_computed_jump): Declare.
* flow.c: (basic_block_computed_jump_target): Define.
(flow_analysis): Allocate it. Set current_function_has_computed_jump
to 0.
(find_basic_blocks): Set current_function_has_computed_jump and
elements of basic_block_computed_jump_target to 1 as appropriate.
* function.c: (current_function_has_computed_jump): Define.
* global.c (global_conflicts): Don't allocate pseudos into stack regs
at the start of a block that is reachable by a computed jump.
* reg-stack.c (stack_reg_life_analysis): If must restart, do so
immediately.
(subst_stack_regs): Undo change from Sep 4 1997.
(uses_reg_or_mem): Now unused, deleted.
* stupid.c (stupid_life_analysis): Compute
current_function_has_computed_jump.
(stupid_find_reg): Don't allocate stack regs if the function has a
computed goto.
* haifa-sched.c (is_cfg_nonregular): Delete code to determine if
the current function has a computed jump. Use the global value
instead.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@18860
138bc75d-0d04-0410-961f-
82ee72b054a4
+Sat Mar 28 01:06:12 1998 Bernd Schmidt <crux@pool.informatik.rwth-aachen.de>
+ Jeffrey A Law (law@cygnus.com)
+
+ * basic-block.h (basic_block_computed_jump_target): Declare.
+ * flags.h: (current_function_has_computed_jump): Declare.
+ * flow.c: (basic_block_computed_jump_target): Define.
+ (flow_analysis): Allocate it. Set current_function_has_computed_jump
+ to 0.
+ (find_basic_blocks): Set current_function_has_computed_jump and
+ elements of basic_block_computed_jump_target to 1 as appropriate.
+ * function.c: (current_function_has_computed_jump): Define.
+ * global.c (global_conflicts): Don't allocate pseudos into stack regs
+ at the start of a block that is reachable by a computed jump.
+ * reg-stack.c (stack_reg_life_analysis): If must restart, do so
+ immediately.
+ (subst_stack_regs): Undo change from Sep 4 1997.
+ (uses_reg_or_mem): Now unused, deleted.
+ * stupid.c (stupid_life_analysis): Compute
+ current_function_has_computed_jump.
+ (stupid_find_reg): Don't allocate stack regs if the function has a
+ computed goto.
+ * haifa-sched.c (is_cfg_nonregular): Delete code to determine if
+ the current function has a computed jump. Use the global value
+ instead.
+
Sat Mar 28 00:21:37 1998 Jeffrey A Law (law@cygnus.com)
* i386/freebsd.h (CPP_PREDEFINES): Remove __386BSD__.
extern rtx *basic_block_end;
+/* Index by basic block number, determine whether the block can be reached
+ through a computed jump. */
+
+extern char *basic_block_computed_jump_target;
+
/* Index by basic block number, get address of regset
describing the registers live at the start of that block. */
extern int current_function_has_nonlocal_goto;
+/* Nonzero if this function has a computed goto.
+
+ It is computed during find_basic_blocks or during stupid life
+ analysis. */
+
+extern int current_function_has_computed_jump;
+
/* Nonzero if GCC must add code to check memory access (used by Checker). */
extern int flag_check_memory_usage;
rtx *basic_block_end;
+/* Element N indicates whether basic block N can be reached through a
+ computed jump. */
+
+char *basic_block_computed_jump_target;
+
/* Element N is a regset describing the registers live
at the start of basic block N.
This info lasts until we finish compiling the function. */
basic_block_head = (rtx *) xmalloc (n_basic_blocks * sizeof (rtx));
basic_block_end = (rtx *) xmalloc (n_basic_blocks * sizeof (rtx));
basic_block_drops_in = (char *) xmalloc (n_basic_blocks);
+ basic_block_computed_jump_target = (char *) oballoc (n_basic_blocks);
basic_block_loop_depth = (short *) xmalloc (n_basic_blocks * sizeof (short));
uid_block_number
= (int *) xmalloc ((max_uid_for_flow + 1) * sizeof (int));
block_live_static = block_live;
bzero (block_live, n_basic_blocks);
bzero (block_marked, n_basic_blocks);
+ bzero (basic_block_computed_jump_target, n_basic_blocks);
bzero (active_eh_handler, (max_uid_for_flow + 1) * sizeof (rtx));
+ current_function_has_computed_jump = 0;
/* Initialize with just block 0 reachable and no blocks marked. */
if (n_basic_blocks > 0)
and forced_labels list. */
if (computed_jump_p (insn))
{
+ current_function_has_computed_jump = 1;
for (x = label_value_list; x; x = XEXP (x, 1))
- mark_label_ref (gen_rtx_LABEL_REF (VOIDmode,
- XEXP (x, 0)),
- insn, 0);
+ {
+ int b = BLOCK_NUM (XEXP (x, 0));
+ basic_block_computed_jump_target[b] = 1;
+ mark_label_ref (gen_rtx_LABEL_REF (VOIDmode,
+ XEXP (x, 0)),
+ insn, 0);
+ }
for (x = forced_labels; x; x = XEXP (x, 1))
- mark_label_ref (gen_rtx_LABEL_REF (VOIDmode,
- XEXP (x, 0)),
- insn, 0);
- }
+ {
+ int b = BLOCK_NUM (XEXP (x, 0));
+ basic_block_computed_jump_target[b] = 1;
+ mark_label_ref (gen_rtx_LABEL_REF (VOIDmode,
+ XEXP (x, 0)),
+ insn, 0);
+ }
+ }
/* If this is a CALL_INSN, then mark it as reaching
the active EH handler for this CALL_INSN. If
int current_function_has_nonlocal_goto;
+/* Nonzero if this function has a computed goto.
+
+ It is computed during find_basic_blocks or during stupid life
+ analysis. */
+
+int current_function_has_computed_jump;
+
/* Nonzero if function being compiled contains nested functions. */
int current_function_contains_functions;
allocno now live, and with each hard reg now live. */
record_conflicts (block_start_allocnos, ax);
+
+#ifdef STACK_REGS
+ /* Pseudos can't go in stack regs at the start of a basic block
+ that can be reached through a computed goto, since reg-stack
+ can't handle computed gotos. */
+ if (basic_block_computed_jump_target[b])
+ for (ax = FIRST_STACK_REG; ax <= LAST_STACK_REG; ax++)
+ record_one_conflict (ax);
+#endif
}
insn = basic_block_head[b];
if (forced_labels)
return 1;
+ /* If this function has a computed jump, then we consider the cfg
+ not well structured. */
+ if (current_function_has_computed_jump)
+ return 1;
+
/* If we have exception handlers, then we consider the cfg not well
structured. ?!? We should be able to handle this now that flow.c
computes an accurate cfg for EH. */
break;
}
- /* If this function has a computed jump, then we consider the cfg
- not well structured. */
- for (b = 0; b < n_basic_blocks; b++)
- {
- for (insn = basic_block_head[b];; insn = NEXT_INSN (insn))
- {
- if (computed_jump_p (insn))
- return 1;
-
- if (insn == basic_block_end[b])
- break;
- }
- }
-
/* All the tests passed. Consider the cfg well structured. */
return 0;
}
static void get_asm_operand_lengths PROTO((rtx, int, int *, int *));
static void record_reg_life PROTO((rtx, int, stack));
static void find_blocks PROTO((rtx));
-static int uses_reg_or_mem PROTO((rtx));
static rtx stack_result PROTO((tree));
static void stack_reg_life_analysis PROTO((rtx, HARD_REG_SET *));
static void replace_reg PROTO((rtx *, int));
}
}
-/* Return 1 if X contain a REG or MEM that is not in the constant pool. */
-
-static int
-uses_reg_or_mem (x)
- rtx x;
-{
- enum rtx_code code = GET_CODE (x);
- int i, j;
- char *fmt;
-
- if (code == REG
- || (code == MEM
- && ! (GET_CODE (XEXP (x, 0)) == SYMBOL_REF
- && CONSTANT_POOL_ADDRESS_P (XEXP (x, 0)))))
- return 1;
-
- fmt = GET_RTX_FORMAT (code);
- for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
- {
- if (fmt[i] == 'e'
- && uses_reg_or_mem (XEXP (x, i)))
- return 1;
-
- if (fmt[i] == 'E')
- for (j = 0; j < XVECLEN (x, i); j++)
- if (uses_reg_or_mem (XVECEXP (x, i, j)))
- return 1;
- }
-
- return 0;
-}
-
/* If current function returns its result in an fp stack register,
return the REG. Otherwise, return 0. */
block = jump_block;
must_restart = 1;
+ break;
win:
;
{
register rtx *note_link, note;
register int i;
- rtx head, jump, pat, cipat;
int n_operands;
if (GET_CODE (insn) == CALL_INSN)
if (GET_CODE (insn) == NOTE)
return;
- /* If we are reached by a computed goto which sets this same stack register,
- then pop this stack register, but maintain regstack. */
-
- pat = single_set (insn);
- if (pat != 0
- && INSN_UID (insn) <= max_uid
- && GET_CODE (block_begin[BLOCK_NUM(insn)]) == CODE_LABEL
- && GET_CODE (pat) == SET && STACK_REG_P (SET_DEST (pat)))
- for (head = block_begin[BLOCK_NUM(insn)], jump = LABEL_REFS (head);
- jump != head;
- jump = LABEL_NEXTREF (jump))
- {
- cipat = single_set (CONTAINING_INSN (jump));
- if (cipat != 0
- && GET_CODE (cipat) == SET
- && SET_DEST (cipat) == pc_rtx
- && uses_reg_or_mem (SET_SRC (cipat))
- && INSN_UID (CONTAINING_INSN (jump)) <= max_uid)
- {
- int from_block = BLOCK_NUM (CONTAINING_INSN (jump));
- if (TEST_HARD_REG_BIT (block_out_reg_set[from_block],
- REGNO (SET_DEST (pat))))
- {
- struct stack_def old;
- bcopy (regstack->reg, old.reg, sizeof (old.reg));
- emit_pop_insn (insn, regstack, SET_DEST (pat), emit_insn_before);
- regstack->top += 1;
- bcopy (old.reg, regstack->reg, sizeof (old.reg));
- SET_HARD_REG_BIT (regstack->reg_set, REGNO (SET_DEST (pat)));
- }
- }
- }
-
/* If there is a REG_UNUSED note on a stack register on this insn,
the indicated reg must be popped. The REG_UNUSED note is removed,
since the form of the newly emitted pop insn references the reg,
register rtx last, insn;
int max_uid, max_suid;
+ current_function_has_computed_jump = 0;
+
bzero (regs_ever_live, sizeof regs_ever_live);
regs_live = (char *) alloca (nregs);
be live if it's also used to pass arguments. */
stupid_mark_refs (CALL_INSN_FUNCTION_USAGE (insn), insn);
}
+ if (GET_CODE (insn) == JUMP_INSN && computed_jump_p (insn))
+ current_function_has_computed_jump = 1;
}
/* Now decide the order in which to allocate the pseudo registers. */
for (ins = born_insn; ins < dead_insn; ins++)
IOR_HARD_REG_SET (used, after_insn_hard_regs[ins]);
+#ifdef STACK_REGS
+ if (current_function_has_computed_jump)
+ for (i = FIRST_STACK_REG; i <= LAST_STACK_REG; i++)
+ SET_HARD_REG_BIT (used, i);
+#endif
+
IOR_COMPL_HARD_REG_SET (used, reg_class_contents[(int) class]);
#ifdef CLASS_CANNOT_CHANGE_SIZE