/* Calculate branch probabilities, and basic block execution counts.
- Copyright (C) 1990, 91, 92, 93, 94, 96, 1997 Free Software Foundation, Inc.
+ Copyright (C) 1990, 91-94, 96, 97, 1998 Free Software Foundation, Inc.
Contributed by James E. Wilson, UC Berkeley/Cygnus Support;
based on some ideas from Dain Samples of UC Berkeley.
Further mangling by Bob Manson, Cygnus Support.
achieve this, see Dain Sample's UC Berkeley thesis. */
#include "config.h"
-#include <stdio.h>
+#include "system.h"
#include "rtl.h"
#include "flags.h"
#include "insn-flags.h"
#include "tree.h"
#include "output.h"
#include "gcov-io.h"
+#include "toplev.h"
extern char * xmalloc ();
-extern void free ();
/* One of these is dynamically created whenever we identify an arc in the
function. */
int num_instr_arcs = 0;
rtx insn;
- int neg_one = -1;
- int zero = 0;
- int inverted;
- rtx note;
-
/* Instrument the program start. */
/* Handle block 0 specially, since it will always be instrumented,
but it doesn't have a valid first_insn or branch_insn. We must
__write_long (delimiter, bb_file, 4);
}
\f
+/* Return TRUE if this insn must be a tablejump entry insn. This works for
+ the MIPS port, but may give false negatives for some targets. */
+
+int
+tablejump_entry_p (insn, label)
+ rtx insn, label;
+{
+ rtx next = next_active_insn (insn);
+ enum rtx_code code = GET_CODE (PATTERN (next));
+
+ if (code != ADDR_DIFF_VEC && code != ADDR_VEC)
+ return 0;
+
+ if (PREV_INSN (next) == XEXP (label, 0))
+ return 1;
+
+ return 0;
+}
+
/* Instrument and/or analyze program behavior based on program flow graph.
In either case, this function builds a flow graph for the function being
compiled. The flow graph is stored in BB_GRAPH.
FILE *dump_file;
{
int i, num_blocks;
- int dest;
- rtx insn;
struct adj_list *arcptr;
int num_arcs, changes, passes;
int total, prob;
register int i;
int fall_through = 0;
struct adj_list *arcptr;
- int dest;
+ int dest = 0;
/* Block 0 always falls through to block 1. */
num_arcs = 0;
bb_graph[i].first_insn = insn;
}
else if (code == NOTE)
- ;
+ {;}
if (code == CALL_INSN)
{
We have to handle tablejumps and returns specially anyways, so
we don't check the JUMP_LABEL at all here. */
+ /* ??? This code should be rewritten. We need a more elegant way
+ to find the LABEL_REF. We need a more elegant way to
+ differentiate tablejump entries from computed gotos.
+ We should perhaps reuse code from flow to compute the CFG
+ instead of trying to compute it here.
+
+ We can't use current_function_has_computed_jump, because that
+ is calculated later by flow. We can't use computed_jump_p,
+ because that returns true for tablejump entry insns for some
+ targets, e.g. HPPA and MIPS. */
+
if (GET_CODE (pattern) == PARALLEL)
{
- /* This assumes that PARALLEL jumps are tablejump entry
- jumps. */
+ /* This assumes that PARALLEL jumps with a USE are
+ tablejump entry jumps. The same assumption can be found
+ in computed_jump_p. */
/* Make an arc from this jump to the label of the
jump table. This will instrument the number of
times the switch statement is executed. */
tablejump = pattern;
else if (GET_CODE (pattern) == RETURN)
dest = num_blocks - 1;
+ else if (GET_CODE (pattern) != SET)
+ abort ();
else if ((tem = SET_SRC (pattern))
&& GET_CODE (tem) == LABEL_REF)
dest = label_to_bb[CODE_LABEL_NUMBER (XEXP (tem, 0))];
+ /* Recognize HPPA table jump entry. This code is similar to
+ the code above in the PARALLEL case. */
+ else if (GET_CODE (tem) == PLUS
+ && GET_CODE (XEXP (tem, 0)) == MEM
+ && GET_CODE (XEXP (XEXP (tem, 0), 0)) == PLUS
+ && GET_CODE (XEXP (XEXP (XEXP (tem, 0), 0), 0)) == PC
+ && GET_CODE (XEXP (tem, 1)) == LABEL_REF
+ && tablejump_entry_p (insn, XEXP (tem, 1)))
+ dest = label_to_bb[CODE_LABEL_NUMBER (XEXP (XEXP (tem, 1), 0))];
+ /* Recognize the MIPS table jump entry. */
+ else if (GET_CODE (tem) == PLUS
+ && GET_CODE (XEXP (tem, 0)) == REG
+ && GET_CODE (XEXP (tem, 1)) == LABEL_REF
+ && tablejump_entry_p (insn, XEXP (tem, 1)))
+ dest = label_to_bb[CODE_LABEL_NUMBER (XEXP (XEXP (tem, 1), 0))];
else
{
rtx label_ref;
- /* Must be an IF_THEN_ELSE branch. */
+ /* Must be an IF_THEN_ELSE branch. If it isn't, assume it
+ is a computed goto, which aren't supported yet. */
if (GET_CODE (tem) != IF_THEN_ELSE)
- abort ();
+ fatal ("-fprofile-arcs does not support computed gotos");
if (XEXP (tem, 1) != pc_rtx)
label_ref = XEXP (tem, 1);
else
/* Reset flag_inline_functions to its original value. */
flag_inline_functions = save_flag_inline_functions;
- fflush (asm_out_file);
+ if (! quiet_flag)
+ fflush (asm_out_file);
current_function_decl = NULL_TREE;
assemble_constructor (IDENTIFIER_POINTER (DECL_NAME (fndecl)));