This describes commands for alignment.
@table @code
-@findex LABEL_ALIGN_AFTER_BARRIER
-@item LABEL_ALIGN_AFTER_BARRIER (@var{label})
-The alignment (log base 2) to put in front of @var{label}, which follows
-a @code{BARRIER}.
+@findex JUMP_ALIGN_AFTER_BARRIER
+@item JUMP_ALIGN (@var{label})
+The alignment (log base 2) to put in front of @var{label}, which is
+a common destination of jumps and has no fallthru incomming edge.
This macro need not be defined if you don't want any special alignment
to be done at such a time. Most machine descriptions do not currently
Unless it's necessary to inspect the @var{label} parameter, it is better
to set the variable @var{align_jumps} in the target's
@code{OVERRIDE_OPTIONS}. Otherwise, you should try to honour the user's
-selection in @var{align_jumps} in a @code{LABEL_ALIGN_AFTER_BARRIER}
-implementation.
+selection in @var{align_jumps} in a @code{JUMP_ALIGN} implementation.
+
+@table @code
+@findex LABEL_ALIGN_AFTER_BARRIER
+@item LABEL_ALIGN_AFTER_BARRIER (@var{label})
+The alignment (log base 2) to put in front of @var{label}, which follows
+a @code{BARRIER}.
+
+This macro need not be defined if you don't want any special alignment
+to be done at such a time. Most machine descriptions do not currently
+define the macro.
@findex LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP
@item LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP
void
init_insn_lengths ()
{
- if (label_align)
- {
- free (label_align);
- label_align = 0;
- }
if (uid_shuid)
{
free (uid_shuid);
#endif
#ifndef LABEL_ALIGN_AFTER_BARRIER
-#define LABEL_ALIGN_AFTER_BARRIER(LABEL) align_jumps_log
+#define LABEL_ALIGN_AFTER_BARRIER(LABEL) 1
#endif
#ifndef LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP
-#define LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP (align_jumps-1)
+#define LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP 0
+#endif
+
+#ifndef JUMP_ALIGN
+#define JUMP_ALIGN(LABEL) align_jumps_log
+#endif
+
+#ifndef JUMP_ALIGN_MAX_SKIP
+#define JUMP_ALIGN_MAX_SKIP (align_jumps-1)
#endif
#ifndef ADDR_VEC_ALIGN
}
#endif /* HAVE_ATTR_length */
\f
+void
+compute_alignments ()
+{
+ int i;
+ int log, max_skip, max_log;
+
+ if (label_align)
+ {
+ free (label_align);
+ label_align = 0;
+ }
+
+ max_labelno = max_label_num ();
+ min_labelno = get_first_label_num ();
+ label_align = (struct label_alignment *) xcalloc ((max_labelno - min_labelno + 1),
+ sizeof (struct label_alignment));
+
+ /* If not optimizing or optimizing for size, don't assign any alignments. */
+ for (i = 0; i < n_basic_blocks; i++)
+ {
+ basic_block bb = BASIC_BLOCK (i);
+ rtx label = bb->head;
+ int fallthru_frequency = 0, branch_frequency = 0, has_fallthru = 0;
+ edge e;
+
+ if (GET_CODE (label) != CODE_LABEL)
+ continue;
+ max_log = LABEL_ALIGN (label);
+ max_skip = LABEL_ALIGN_MAX_SKIP;
+
+ for (e = bb->pred; e; e = e->pred_next)
+ {
+ if (e->flags & EDGE_FALLTHRU)
+ has_fallthru = 1, fallthru_frequency += EDGE_FREQUENCY (e);
+ else
+ branch_frequency += EDGE_FREQUENCY (e);
+ }
+
+ /* There are two purposes to align block with no fallthru incomming edge:
+ 1) to avoid fetch stalls when branch destination is near cache boundary
+ 2) to improve cache effciency in case the previous block is not executed
+ (so it does not need to be in the cache).
+
+ We to catch first case, we align frequently executed blocks.
+ To catch the second, we align blocks that are executed more frequently
+ than the predecesor and the predecesor is likely to not be executed
+ when function is called. */
+
+ if (!has_fallthru
+ && (branch_frequency > BB_FREQ_MAX / 10
+ || (bb->frequency > BASIC_BLOCK (i - 1)->frequency * 10
+ && (BASIC_BLOCK (i - 1)->frequency
+ <= ENTRY_BLOCK_PTR->frequency / 2))))
+ {
+ log = JUMP_ALIGN (label);
+ if (max_log < log)
+ {
+ max_log = log;
+ max_skip = JUMP_ALIGN_MAX_SKIP;
+ }
+ }
+ /* In case block is frequent and reached mostly by non-fallthru edge,
+ align it. It is most likely an first block of loop. */
+ if (has_fallthru
+ && branch_frequency + fallthru_frequency > BB_FREQ_MAX / 10
+ && branch_frequency > fallthru_frequency * 5)
+ {
+ log = LOOP_ALIGN (label);
+ if (max_log < log)
+ {
+ max_log = log;
+ max_skip = LOOP_ALIGN_MAX_SKIP;
+ }
+ }
+ LABEL_TO_ALIGNMENT (label) = max_log;
+ LABEL_TO_MAX_SKIP (label) = max_skip;
+ }
+}
+\f
/* Make a pass over all insns and compute their actual lengths by shortening
any branches of variable length if possible. */
#endif
- /* We must do some computations even when not actually shortening, in
- order to get the alignment information for the labels. */
-
- init_insn_lengths ();
-
/* Compute maximum UID and allocate label_align / uid_shuid. */
max_uid = get_max_uid ();
- max_labelno = max_label_num ();
- min_labelno = get_first_label_num ();
- label_align = (struct label_alignment *)
- xcalloc ((max_labelno - min_labelno + 1), sizeof (struct label_alignment));
-
uid_shuid = (int *) xmalloc (max_uid * sizeof *uid_shuid);
+ if (max_labelno != max_label_num ())
+ {
+ int old = max_labelno;
+ max_labelno = max_label_num ();
+ label_align = (struct label_alignment *) xrealloc
+ (label_align,
+ (max_labelno - min_labelno + 1) * sizeof (struct label_alignment));
+ memset (label_align + old + 1 - min_labelno, 0,
+ sizeof (struct label_alignment) * (max_labelno - old));
+ }
+
/* Initialize label_align and set up uid_shuid to be strictly
monotonically rising with insn order. */
/* We use max_log here to keep track of the maximum alignment we want to
else if (GET_CODE (insn) == CODE_LABEL)
{
rtx next;
+
+ /* Merge in alignments computed by compute_alignments. */
+ log = LABEL_TO_ALIGNMENT (insn);
+ if (max_log < log)
+ {
+ max_log = log;
+ max_skip = LABEL_TO_MAX_SKIP (insn);
+ }
log = LABEL_ALIGN (insn);
if (max_log < log)
break;
}
}
- /* Again, we allow NOTE_INSN_LOOP_BEG - INSN - CODE_LABEL
- sequences in order to handle reorg output efficiently. */
- else if (GET_CODE (insn) == NOTE
- && NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG)
- {
- rtx label;
- int nest = 0;
-
- /* Search for the label that starts the loop.
- Don't skip past the end of the loop, since that could
- lead to putting an alignment where it does not belong.
- However, a label after a nested (non-)loop would be OK. */
- for (label = insn; label; label = NEXT_INSN (label))
- {
- if (GET_CODE (label) == NOTE
- && NOTE_LINE_NUMBER (label) == NOTE_INSN_LOOP_BEG)
- nest++;
- else if (GET_CODE (label) == NOTE
- && NOTE_LINE_NUMBER (label) == NOTE_INSN_LOOP_END
- && --nest == 0)
- break;
- else if (GET_CODE (label) == CODE_LABEL)
- {
- log = LOOP_ALIGN (label);
- if (max_log < log)
- {
- max_log = log;
- max_skip = LOOP_ALIGN_MAX_SKIP;
- }
- break;
- }
- }
- }
- else
- continue;
}
#ifdef HAVE_ATTR_length