Commit fc470718 by J"orn Rennecke Committed by Joern Rennecke

final.c (insn_last_address, [...]): New variables.

	* final.c (insn_last_address, insn_current_align, uid_align):
	New variables.
	(in_align_chain, align_fuzz, align_shrink_fuzz): New functions.
	(insn_current_reference_address): Likewise.
	(shorten_branches, final_scan_insn): Implement LABEL_ALIGN,
	LABEL_ALIGN_AFTER_BARRIER and LOOP_ALIGN target macros.
	(label_to_alignment): New function.
	* genattrtab.c (write_test_expr): If one of LABEL_ALIGN,
	LABEL_ALIGN_AFTER_BARRIER or LOOP_ALIGN is defined, call
	insn_current_reference_address instead of insn_current_address.
	(or_attr_value, write_length_unit_log): New functions.
	(main): Call write_length_unit_log.
	(write_const_num_delay_slots): Output extra '\n'.
	* alpha.h (ASM_OUTPUT_LOOP_ALIGN, ASM_OUTPUT_ALIGN_CODE):
	replace with:
	(LOOP_ALIGN, ALIGN_LABEL_AFTER_BARRIER).
	* i386.h, i386/osfrose.h, i386/svr3dbx.h, m68k.h, sparc.h: Likewise.
	* arc.h, m32r.h (ASM_OUTPUT_LOOP_ALIGN): replace with:
	(LOOP_ALIGN).
	* i960.h, m88k.h: (ASM_OUTPUT_ALIGN_CODE): Replace with:
	(LABEL_ALIGN_AFTER_BARRIER).
	* ns32k/encore.h, ns32k/merlin.h, ns32k.h, ns32k/sequent.h: Likewise.
	* ns32k/tek6000.h: Likewise.
	* i386/gas.h (ASM_OUTPUT_LOOP_ALIGN, ASM_OUTPUT_ALIGN_CODE): Delete.
	* i386.md (casesi+1): Use ASM_OUTPUT_ALIGN instead of
	ASM_OUTPUT_ALIGN_CODE.

From-SVN: r18357
parent 948edfa7
Mon Mar 2 19:51:27 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
* final.c (insn_last_address, insn_current_align, uid_align):
New variables.
(in_align_chain, align_fuzz, align_shrink_fuzz): New functions.
(insn_current_reference_address): Likewise.
(shorten_branches, final_scan_insn): Implement LABEL_ALIGN,
LABEL_ALIGN_AFTER_BARRIER and LOOP_ALIGN target macros.
(label_to_alignment): New function.
* genattrtab.c (write_test_expr): If one of LABEL_ALIGN,
LABEL_ALIGN_AFTER_BARRIER or LOOP_ALIGN is defined, call
insn_current_reference_address instead of insn_current_address.
(or_attr_value, write_length_unit_log): New functions.
(main): Call write_length_unit_log.
(write_const_num_delay_slots): Output extra '\n'.
* alpha.h (ASM_OUTPUT_LOOP_ALIGN, ASM_OUTPUT_ALIGN_CODE):
replace with:
(LOOP_ALIGN, ALIGN_LABEL_AFTER_BARRIER).
* i386.h, i386/osfrose.h, i386/svr3dbx.h, m68k.h, sparc.h: Likewise.
* arc.h, m32r.h (ASM_OUTPUT_LOOP_ALIGN): replace with:
(LOOP_ALIGN).
* i960.h, m88k.h: (ASM_OUTPUT_ALIGN_CODE): Replace with:
(LABEL_ALIGN_AFTER_BARRIER).
* ns32k/encore.h, ns32k/merlin.h, ns32k.h, ns32k/sequent.h: Likewise.
* ns32k/tek6000.h: Likewise.
* i386/gas.h (ASM_OUTPUT_LOOP_ALIGN, ASM_OUTPUT_ALIGN_CODE): Delete.
* i386.md (casesi+1): Use ASM_OUTPUT_ALIGN instead of
ASM_OUTPUT_ALIGN_CODE.
Mon Mar 2 01:05:50 PST 1998 Jeff Law (law@cygnus.com)
* version.c: Bump for snapshot.
......
......@@ -387,9 +387,8 @@ extern void override_options ();
/* Aligning past 2**3 wastes insn cache lines, and doesn't buy much
issue-wise on average anyway. */
#define ASM_OUTPUT_LOOP_ALIGN(FILE) \
if (optimize > 0 && write_symbols != SDB_DEBUG) \
ASM_OUTPUT_ALIGN (FILE, 3)
#define LOOP_ALIGN(LABEL) \
(optimize > 0 && write_symbols != SDB_DEBUG ? 3 : 0)
/* This is how to align an instruction for optimal branching.
On Alpha we'll get better performance by aligning on a quadword
......@@ -397,9 +396,8 @@ extern void override_options ();
/* Aligning past 2**3 wastes insn cache lines, and doesn't buy much
issue-wise on average anyway. */
#define ASM_OUTPUT_ALIGN_CODE(FILE) \
if (optimize > 0 && write_symbols != SDB_DEBUG) \
ASM_OUTPUT_ALIGN ((FILE), 3)
#define ALIGN_LABEL_AFTER_BARRIER(FILE) \
(optimize > 0 && write_symbols != SDB_DEBUG ? 3 : 0)
/* No data type wants to be aligned rounder than this. */
#define BIGGEST_ALIGNMENT 64
......
......@@ -1504,12 +1504,11 @@ do { \
fprintf (FILE, ")\n"); \
} while (0)
/* A C expression to output text to align the location counter in the way
that is desirable at the beginning of a loop. */
/* The desired alignment for the location counter at the beginning
of a loop. */
/* On the ARC, align loops to 32 byte boundaries (cache line size)
if -malign-loops. */
#define ASM_OUTPUT_LOOP_ALIGN(FILE) \
do { if (TARGET_ALIGN_LOOPS) ASM_OUTPUT_SKIP (FILE, 5); } while (0)
#define LOOP_ALIGN(LABEL) (TARGET_ALIGN_LOOPS ? 5 : 0)
/* This is how to output an assembler line
that says to advance the location counter
......
......@@ -86,20 +86,6 @@ Boston, MA 02111-1307, USA. */
if ((LOG)!=0) fprintf ((FILE), "\t.balign %d\n", 1<<(LOG))
#endif
/* Align labels, etc. at 4-byte boundaries.
For the 486, align to 16-byte boundary for sake of cache. */
#undef ASM_OUTPUT_ALIGN_CODE
#define ASM_OUTPUT_ALIGN_CODE(FILE) \
fprintf ((FILE), "\t.align %d,0x90\n", i386_align_jumps)
/* Align start of loop at 4-byte boundary. */
#undef ASM_OUTPUT_LOOP_ALIGN
#define ASM_OUTPUT_LOOP_ALIGN(FILE) \
fprintf ((FILE), "\t.align %d,0x90\n", i386_align_loops)
/* A C statement or statements which output an assembler instruction
opcode to the stdio stream STREAM. The macro-operand PTR is a
variable of type `char *' which points to the opcode name in its
......
......@@ -446,12 +446,12 @@ extern int ix86_arch;
#define MAX_CODE_ALIGN 6 /* 64 byte alignment */
/* Align loop starts for optimal branching. */
#define ASM_OUTPUT_LOOP_ALIGN(FILE) ASM_OUTPUT_ALIGN (FILE, i386_align_loops)
#define LOOP_ALIGN(LABEL) (i386_align_loops)
/* This is how to align an instruction for optimal branching.
On i486 we'll get better performance by aligning on a
cache line (i.e. 16 byte) boundary. */
#define ASM_OUTPUT_ALIGN_CODE(FILE) ASM_OUTPUT_ALIGN ((FILE), i386_align_jumps)
#define LABEL_ALIGN_AFTER_BARRIER(LABEL) (i386_align_jumps)
/* Standard register usage. */
......
......@@ -6193,7 +6193,7 @@ byte_xor_operation:
output_asm_insn (AS2 (mov%L2,%3,%2), xops);
output_asm_insn (\"sub%L2 %l1@GOTOFF(%3,%0,4),%2\", xops);
output_asm_insn (AS1 (jmp,%*%2), xops);
ASM_OUTPUT_ALIGN_CODE (asm_out_file);
ASM_OUTPUT_ALIGN (asm_out_file, i386_align_jumps);
RET;
}")
......
......@@ -404,10 +404,9 @@ while (0)
alignment to be done at such a time. Most machine descriptions do
not currently define the macro. */
#undef ASM_OUTPUT_ALIGN_CODE
#define ASM_OUTPUT_ALIGN_CODE(STREAM) \
fprintf (STREAM, "\t.align\t%d\n", \
(!TARGET_LARGE_ALIGN && i386_align_jumps > 2) ? 2 : i386_align_jumps)
#undef LABEL_ALIGN_AFTER_BARRIER
#define LABEL_ALIGN_AFTER_BARRIER(LABEL) \
((!TARGET_LARGE_ALIGN && i386_align_jumps > 2) ? 2 : i386_align_jumps)
/* A C expression to output text to align the location counter in the
way that is desirable at the beginning of a loop.
......@@ -416,9 +415,8 @@ while (0)
alignment to be done at such a time. Most machine descriptions do
not currently define the macro. */
#undef ASM_OUTPUT_LOOP_ALIGN
#define ASM_OUTPUT_LOOP_ALIGN(STREAM) \
fprintf (STREAM, "\t.align\t%d\n", i386_align_loops)
#undef LOOP_ALIGN
#define LOOP_ALIGN(LABEL) (i386_align_loops)
/* A C statement to output to the stdio stream STREAM an assembler
command to advance the location counter to a multiple of 2 to the
......
......@@ -46,16 +46,13 @@ Boston, MA 02111-1307, USA. */
/* Align labels, etc. at 4-byte boundaries.
For the 486, align to 16-byte boundary for sake of cache. */
#undef ASM_OUTPUT_ALIGN_CODE
#define ASM_OUTPUT_ALIGN_CODE(FILE) \
fprintf ((FILE), "\t.align %d,0x90\n", \
1 << i386_align_jumps)
#undef LABEL_ALIGN_AFTER_BARRIER
#define LABEL_ALIGN_AFTER_BARRIER(LABEL) (i386_align_jumps)
/* Align start of loop at 4-byte boundary. */
#undef ASM_OUTPUT_LOOP_ALIGN
#define ASM_OUTPUT_LOOP_ALIGN(FILE) \
fprintf ((FILE), "\t.align %d,0x90\n", 1 << i386_align_loops);
#undef LOOP_ALIGN
#define LOOP_ALIGN(LABEL) (i386_align_loops)
/* Additional overrides needed for dbx-in-coff gas, mostly taken from pbb.h */
......
......@@ -1407,8 +1407,7 @@ extern struct rtx_def *gen_compare_reg ();
/* Align code to 8 byte boundary if TARGET_CODE_ALIGN is true. */
#define ASM_OUTPUT_ALIGN_CODE(FILE) \
{ if (TARGET_CODE_ALIGN) fputs("\t.align 3\n",FILE); }
#define LABEL_ALIGN_AFTER_BARRIER(LABEL) (TARGET_CODE_ALIGN ? 3 : 0)
/* Store in OUTPUT a string (made with alloca) containing
an assembler-name for a local static variable named NAME.
......
......@@ -1673,12 +1673,11 @@ do { \
fprintf (FILE, ")\n"); \
} while (0)
/* A C expression to output text to align the location counter in the way
that is desirable at the beginning of a loop. */
/* The desired alignment for the location counter at the beginning
of a loop. */
/* On the M32R, align loops to 32 byte boundaries (cache line size)
if -malign-loops. */
#define ASM_OUTPUT_LOOP_ALIGN(FILE) \
do { if (TARGET_ALIGN_LOOPS) ASM_OUTPUT_ALIGN (FILE, 5); } while (0)
#define LOOP_ALIGN(LABEL) (TARGET_ALIGN_LOOPS ? 5 : 0)
/* This is how to output an assembler line
that says to advance the location counter
......
......@@ -294,10 +294,10 @@ extern int target_flags;
#define MAX_CODE_ALIGN 2 /* 4 byte alignment */
/* Align loop starts for optimal branching. */
#define ASM_OUTPUT_LOOP_ALIGN(FILE) ASM_OUTPUT_ALIGN ((FILE), m68k_align_loops)
#define LOOP_ALIGN(LABEL) (m68k_align_loops)
/* This is how to align an instruction for optimal branching. */
#define ASM_OUTPUT_ALIGN_CODE(FILE) ASM_OUTPUT_ALIGN ((FILE), m68k_align_jumps)
#define LABEL_ALIGN_AFTER_BARRIER(LABEL) (m68k_align_jumps)
#define SELECT_RTX_SECTION(MODE, X) \
{ \
......
......@@ -198,13 +198,13 @@ extern char * reg_names[];
Redefined in sysv4.h, and luna.h. */
#define VERSION_INFO1 "m88k, "
#ifndef VERSION_INFO2
#define VERSION_INFO2 "$Revision: 1.3 $"
#define VERSION_INFO2 "$Revision: 1.4 $"
#endif
#ifndef VERSION_STRING
#define VERSION_STRING version_string
#ifdef __STDC__
#define TM_RCS_ID "@(#)" __FILE__ " $Revision: 1.3 $ " __DATE__
#define TM_RCS_ID "@(#)" __FILE__ " $Revision: 1.4 $ " __DATE__
#else
#define TM_RCS_ID "$What: <@(#) m88k.h,v 1.1.1.2.2.2> $"
#endif /* __STDC__ */
......@@ -2212,9 +2212,8 @@ do { \
/* On the m88100, align the text address to half a cache boundary when it
can only be reached by jumping. Pack code tightly when compiling
crtstuff.c. */
#define ASM_OUTPUT_ALIGN_CODE(FILE) \
ASM_OUTPUT_ALIGN (FILE, \
(TARGET_88100 && !flag_inhibit_size_directive ? 3 : 2))
#define LABEL_ALIGN_AFTER_BARRIER(LABEL) \
(TARGET_88100 && !flag_inhibit_size_directive ? 3 : 2)
/* Override svr[34].h. */
#undef ASM_OUTPUT_SKIP
......
......@@ -79,8 +79,8 @@ output_file_directive ((FILE), main_input_filename)
/* The Encore assembler doesn't seem to accept the usual second argument
and warns that .align may not work in the text section if optimization
is on. */
#undef ASM_OUTPUT_ALIGN_CODE
#define ASM_OUTPUT_ALIGN_CODE(FILE)
#undef LABEL_ALIGN_AFTER_BARRIER
#define LABEL_ALIGN_AFTER_BARRIER(LABEL) 0
/*
* Internal labels are prefixed with a period.
......
......@@ -53,7 +53,7 @@ Boston, MA 02111-1307, USA. */
/* This is how to align the code that follows an unconditional branch.
Don't define it, since it confuses the assembler (we hear). */
#undef ASM_OUTPUT_ALIGN_CODE
#undef LABEL_ALIGN_AFTER_BARRIER
/* Assembler pseudo-op for shared data segment. */
#define SHARED_SECTION_ASM_OP ".shdata"
......
......@@ -1383,11 +1383,9 @@ do { \
#define ASM_GENERATE_INTERNAL_LABEL(LABEL,PREFIX,NUM) \
sprintf (LABEL, "*%s%d", PREFIX, NUM)
/* This is how to align the code that follows an unconditional branch.
Note that 0xa2 is a no-op. */
/* This is how to align the code that follows an unconditional branch. */
#define ASM_OUTPUT_ALIGN_CODE(FILE) \
fprintf (FILE, "\t.align 2,0xa2\n")
#define LABEL_ALIGN_AFTER_BARRIER(LABEL) (2)
/* This is how to output an element of a case-vector that is absolute.
(The ns32k does not use such vectors,
......
......@@ -54,7 +54,7 @@ Boston, MA 02111-1307, USA. */
/* This is how to align the code that follows an unconditional branch.
Don't define it, since it confuses the assembler (we hear). */
#undef ASM_OUTPUT_ALIGN_CODE
#undef LABEL_ALIGN_AFTER_BARRIER
/* Assembler pseudo-op for shared data segment. */
#define SHARED_SECTION_ASM_OP ".shdata"
......
......@@ -106,7 +106,7 @@ Boston, MA 02111-1307, USA. */
/* This is how to align the code that follows an unconditional branch.
Don't define it, since it confuses the assembler (we hear). */
#undef ASM_OUTPUT_ALIGN_CODE
#undef LABEL_ALIGN_AFTER_BARRIER
/* Assembler pseudo-op for shared data segment. */
#define SHARED_SECTION_ASM_OP ".shdata"
......
......@@ -2991,11 +2991,9 @@ do { \
if ((LOG) != 0) \
fprintf (FILE, "\t.align %d\n", (1<<(LOG)))
#define ASM_OUTPUT_ALIGN_CODE(FILE) \
ASM_OUTPUT_ALIGN (FILE, sparc_align_jumps)
#define LABEL_ALIGN_AFTER_BARRIER(LABEL) (sparc_align_jumps)
#define ASM_OUTPUT_LOOP_ALIGN(FILE) \
ASM_OUTPUT_ALIGN (FILE, sparc_align_loops)
#define LOOP_ALIGN(LABEL) (sparc_align_loops)
#define ASM_OUTPUT_SKIP(FILE,SIZE) \
fprintf (FILE, "\t.skip %u\n", (SIZE))
......
......@@ -153,6 +153,8 @@ static int count_basic_blocks;
/* Number of instrumented arcs when profile_arc_flag is set. */
extern int count_instrumented_arcs;
extern int length_unit_log; /* This is defined in insn-attrtab.c. */
/* Nonzero while outputting an `asm' with operands.
This means that inconsistencies are the user's fault, so don't abort.
The precise value is the insn being output, to pass to error_for_asm. */
......@@ -628,6 +630,12 @@ int *insn_addresses;
/* Address of insn being processed. Used by `insn_current_length'. */
int insn_current_address;
/* Address of insn being processed in previous iteration. */
int insn_last_address;
/* konwn invariant alignment of insn being processed. */
int insn_current_align;
/* Indicate that branch shortening hasn't yet been done. */
void
......@@ -666,16 +674,8 @@ get_attr_length (insn)
body = PATTERN (insn);
if (GET_CODE (body) == ADDR_VEC || GET_CODE (body) == ADDR_DIFF_VEC)
{
/* This only takes room if jump tables go into the text section. */
#if !defined(READONLY_DATA_SECTION) || defined(JUMP_TABLES_IN_TEXT_SECTION)
length = (XVECLEN (body, GET_CODE (body) == ADDR_DIFF_VEC)
* GET_MODE_SIZE (GET_MODE (body)));
/* Be pessimistic and assume worst-case alignment. */
length += (GET_MODE_SIZE (GET_MODE (body)) - 1);
#else
return 0;
#endif
/* Alignment is machine-dependent and should be handled by
ADDR_VEC_ALIGN. */
}
else
length = insn_default_length (insn);
......@@ -708,6 +708,205 @@ get_attr_length (insn)
#endif /* not HAVE_ATTR_length */
}
/* Code to handle alignment inside shorten_branches. */
/* Here is an explanation how the algorithm in align_fuzz can give
proper results:
Call a sequence of instructions beginning with alignment point X
and continuing until the next alignment point `block X'. When `X'
is used in an expression, it means the alignment value of the
alignment point.
Call the distance between the start of the first insn of block X, and
the end of the last insn of block X `IX', for the `inner size of X'.
This is clearly the sum of the instruction lengths.
Likewise with the next alignment-delimited block following X, which we
shall call block Y.
Call the distance between the start of the first insn of block X, and
the start of the first insn of block Y `OX', for the `outer size of X'.
The estimated padding is then OX - IX.
OX can be safely estimated as
if (X >= Y)
OX = round_up(IX, Y)
else
OX = round_up(IX, X) + Y - X
Clearly est(IX) >= real(IX), because that only depends on the
instruction lengths, and those being overestimated is a given.
Clearly round_up(foo, Z) >= round_up(bar, Z) if foo >= bar, so
we needn't worry about that when thinking about OX.
When X >= Y, the alignment provided by Y adds no uncertainty factor
for branch ranges starting before X, so we can just round what we have.
But when X < Y, we don't know anything about the, so to speak,
`middle bits', so we have to assume the worst when aligning up from an
address mod X to one mod Y, which is Y - X. */
#ifndef LABEL_ALIGN
#define LABEL_ALIGN(LABEL) 0
#endif
#ifndef LOOP_ALIGN
#define LOOP_ALIGN(LABEL) 0
#endif
#ifndef LABEL_ALIGN_AFTER_BARRIER
#define LABEL_ALIGN_AFTER_BARRIER(LABEL) 0
#endif
#ifndef ADDR_VEC_ALIGN
int
final_addr_vec_align (addr_vec)
rtx addr_vec;
{
int align = exact_log2 (GET_MODE_SIZE (GET_MODE (PATTERN (addr_vec))));
if (align > BIGGEST_ALIGNMENT / BITS_PER_UNIT)
align = BIGGEST_ALIGNMENT / BITS_PER_UNIT;
return align;
}
#define ADDR_VEC_ALIGN(ADDR_VEC) final_addr_vec_align (ADDR_VEC)
#endif
#ifndef INSN_LENGTH_ALIGNMENT
#define INSN_LENGTH_ALIGNMENT(INSN) length_unit_log
#endif
/* For any insn, uid_align[INSN_UID (insn)] gives the next following
alignment insn that increases the known alignment, or NULL_RTX if
there is no such insn.
For any alignment obtained this way, we can again index uid_align with
its uid to obtain the next following align that in turn increases the
alignment, till we reach NULL_RTX; the sequence obtained this way
for each insn we'll call the alignment chain of this insn in the following
comments. */
rtx *uid_align;
int *uid_shuid;
short *label_align; /* sh.c needs this to calculate constant tables. */
#define INSN_SHUID(INSN) (uid_shuid[INSN_UID (INSN)])
static int min_labelno;
#define LABEL_TO_ALIGNMENT(LABEL) \
(label_align[CODE_LABEL_NUMBER (LABEL) - min_labelno])
/* For the benefit of port specific code do this also as a function. */
int
label_to_alignment (label)
rtx label;
{
return LABEL_TO_ALIGNMENT (label);
}
#ifdef HAVE_ATTR_length
/* The differences in addresses
between a branch and its target might grow or shrink depending on
the alignment the start insn of the range (the branch for a forward
branch or the label for a backward branch) starts out on; if these
differences are used naively, they can even oscillate infinitely.
We therefore want to compute a 'worst case' address difference that
is independent of the alignment the start insn of the range end
up on, and that is at least as large as the actual difference.
The function align_fuzz calculates the amount we have to add to the
naively computed difference, by traversing the part of the alignment
chain of the start insn of the range that is in front of the end insn
of the range, and considering for each alignment the maximum amount
that it might contribute to a size increase.
For casesi tables, we also want to know worst case minimum amounts of
address difference, in case a machine description wants to introduce
some common offset that is added to all offsets in a table.
For this purpose, align_fuzz with a growth argument of 0 comuptes the
appropriate adjustment. */
/* Compute the maximum delta by which the difference of the addresses of
START and END might grow / shrink due to a different address for start
which changes the size of alignment insns between START and END.
KNOWN_ALIGN_LOG is the alignment known for START.
GROWTH should be ~0 if the objective is to compute potential code size
increase, and 0 if the objective is to compute potential shrink.
The return value is undefined for any other value of GROWTH. */
int align_fuzz (start, end, known_align_log, growth)
rtx start, end;
int known_align_log;
unsigned growth;
{
int uid = INSN_UID (start);
rtx align_label;
int known_align = 1 << known_align_log;
int end_shuid = INSN_SHUID (end);
int fuzz = 0;
for (align_label = uid_align[uid]; align_label; align_label = uid_align[uid])
{
int align_addr, new_align;
uid = INSN_UID (align_label);
align_addr = insn_addresses[uid] - insn_lengths[uid];
if (uid_shuid[uid] > end_shuid)
break;
known_align_log = LABEL_TO_ALIGNMENT (align_label);
new_align = 1 << known_align_log;
if (new_align < known_align)
continue;
fuzz += (-align_addr ^ growth) & (new_align - known_align);
known_align = new_align;
}
return fuzz;
}
/* Compute a worst-case reference address of a branch so that it
can be safely used in the presence of aligned labels. Since the
size of the branch itself is unknown, the size of the branch is
not included in the range. I.e. for a forward branch, the reference
address is the end address of the branch as known from the previous
branch shortening pass, minus a value to account for possible size
increase due to alignment. For a backward branch, it is the start
address of the branch as known from the current pass, plus a value
to account for possible size increase due to alignment.
NB.: Therefore, the maximum offset allowed for backward branches needs
to exclude the branch size. */
int
insn_current_reference_address (branch)
rtx branch;
{
rtx dest;
rtx seq = NEXT_INSN (PREV_INSN (branch));
int seq_uid = INSN_UID (seq);
if (GET_CODE (branch) != JUMP_INSN)
/* This can happen for example on the PA; the objective is to know the
offset to address something in front of the start of the function.
Thus, we can treat it like a backward branch.
We assume here that FUNCTION_BOUNDARY / BITS_PER_UNIT is larger than
any alignment we'd encounter, so we skip the call to align_fuzz. */
return insn_current_address;
dest = JUMP_LABEL (branch);
if (INSN_SHUID (branch) < INSN_SHUID (dest))
{
/* Forward branch. */
return (insn_last_address + insn_lengths[seq_uid]
- align_fuzz (branch, dest, length_unit_log, ~0));
}
else
{
/* Backward branch. */
return (insn_current_address
+ align_fuzz (dest, branch, length_unit_log, ~0));
}
}
#endif /* HAVE_ATTR_length */
/* Make a pass over all insns and compute their actual lengths by shortening
any branches of variable length if possible. */
......@@ -717,34 +916,188 @@ get_attr_length (insn)
#define FIRST_INSN_ADDRESS 0
#endif
/* shorten_branches might be called multiple times: for example, the SH
port splits out-of-range conditional branches in MACHINE_DEPENDENT_REORG.
In order to do this, it needs proper length information, which it obtains
by calling shorten_branches. This cannot be collapsed with
shorten_branches itself into a single pass unless we also want to intergate
reorg.c, since the branch splitting exposes new instructions with delay
slots. */
void
shorten_branches (first)
rtx first;
{
#ifdef HAVE_ATTR_length
rtx insn;
int max_uid;
int i;
int max_labelno;
int max_log;
#ifdef HAVE_ATTR_length
#define MAX_CODE_ALIGN 16
rtx seq;
int something_changed = 1;
int max_uid = 0;
char *varying_length;
rtx body;
int uid;
rtx align_tab[MAX_CODE_ALIGN];
/* In order to make sure that all instructions have valid length info,
we must split them before we compute the address/length info. */
for (insn = NEXT_INSN (first); insn; insn = NEXT_INSN (insn))
if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
insn = try_split (PATTERN (insn), insn, 1);
{
rtx old = insn;
insn = try_split (PATTERN (old), old, 1);
/* When not optimizing, the old insn will be still left around
with only the 'deleted' bit set. Transform it into a note
to avoid confusion of subsequent processing. */
if (INSN_DELETED_P (old))
{
PUT_CODE (old , NOTE);
NOTE_LINE_NUMBER (old) = NOTE_INSN_DELETED;
NOTE_SOURCE_FILE (old) = 0;
}
}
#endif
/* Compute maximum UID and allocate arrays. */
for (insn = first; insn; insn = NEXT_INSN (insn))
if (INSN_UID (insn) > max_uid)
max_uid = INSN_UID (insn);
/* We must do some computations even when not actually shortening, in
order to get the alignment information for the labels. */
/* 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 ();
if (label_align)
free (label_align);
label_align
= (short*) xmalloc ((max_labelno - min_labelno + 1) * sizeof (short));
bzero (label_align, (max_labelno - min_labelno + 1) * sizeof (short));
if (uid_shuid)
free (uid_shuid);
uid_shuid = (int *) xmalloc (max_uid * sizeof *uid_shuid);
/* Initialize label_align and set up uid_shuid to be strictly
monotonically rising with insn order. */
for (max_log = 0, insn = get_insns (), i = 1; insn; insn = NEXT_INSN (insn))
{
int log;
INSN_SHUID (insn) = i++;
if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
max_log = 0;
else if (GET_CODE (insn) == CODE_LABEL)
{
rtx next;
log = LABEL_ALIGN (insn);
if (max_log < log)
max_log = log;
next = NEXT_INSN (insn);
/* ADDR_VECs only take room if read-only data goes into the text section. */
#if !defined(READONLY_DATA_SECTION) || defined(JUMP_TABLES_IN_TEXT_SECTION)
if (next && GET_CODE (next) == JUMP_INSN)
{
rtx nextbody = PATTERN (next);
if (GET_CODE (nextbody) == ADDR_VEC
|| GET_CODE (nextbody) == ADDR_DIFF_VEC)
{
log = ADDR_VEC_ALIGN (next);
if (max_log < log)
max_log = log;
}
}
#endif
LABEL_TO_ALIGNMENT (insn) = max_log;
max_log = 0;
}
else if (GET_CODE (insn) == BARRIER)
{
rtx label;
for (label = insn; label && GET_RTX_CLASS (GET_CODE (label)) != 'i';
label = NEXT_INSN (label))
if (GET_CODE (label) == CODE_LABEL)
{
log = LABEL_ALIGN_AFTER_BARRIER (insn);
if (max_log < log)
max_log = log;
break;
}
}
else if (GET_CODE (insn) == NOTE
&& NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG)
{
rtx label;
for (label = insn; label && GET_RTX_CLASS (GET_CODE (label)) != 'i';
label = NEXT_INSN (label))
if (GET_CODE (label) == CODE_LABEL)
{
log = LOOP_ALIGN (insn);
if (max_log < log)
max_log = log;
break;
}
}
else
continue;
}
#ifdef HAVE_ATTR_length
/* Allocate the rest of the arrays. */
if (insn_lengths)
free (insn_lengths);
insn_lengths = (short *) xmalloc (max_uid * sizeof (short));
if (insn_addresses)
free (insn_addresses);
insn_addresses = (int *) xmalloc (max_uid * sizeof (int));
if (uid_align)
free (uid_align);
uid_align = (rtx *) xmalloc (max_uid * sizeof *uid_align);
varying_length = (char *) xmalloc (max_uid * sizeof (char));
bzero (varying_length, max_uid);
/* Initialize uid_align. We scan instructions
from end to start, and keep in align_tab[n] the last seen insn
that does an alignment of at least n+1, i.e. the successor
in the alignment chain for an insn that does / has a known
alignment of n. */
bzero ((char *) uid_align, max_uid * sizeof *uid_align);
for (i = MAX_CODE_ALIGN; --i >= 0; )
align_tab[i] = NULL_RTX;
seq = get_last_insn ();
for (insn_current_address = 0; seq; seq = PREV_INSN (seq))
{
int uid = INSN_UID (seq);
int log;
int length_align;
log = (GET_CODE (seq) == CODE_LABEL ? LABEL_TO_ALIGNMENT (seq) : 0);
uid_align[uid] = align_tab[0];
insn_addresses[uid] = --insn_current_address;
if (log)
{
/* Found an alignment label. */
uid_align[uid] = align_tab[log];
for (i = log - 1; i >= 0; i--)
align_tab[i] = seq;
}
if (GET_CODE (seq) != INSN || GET_CODE (PATTERN (seq)) != SEQUENCE)
insn = seq;
else
{
insn = XVECEXP (PATTERN (seq), 0, 0);
uid = INSN_UID (insn);
}
}
max_uid++;
insn_lengths = (short *) oballoc (max_uid * sizeof (short));
insn_addresses = (int *) oballoc (max_uid * sizeof (int));
varying_length = (char *) oballoc (max_uid * sizeof (char));
/* Compute initial lengths, addresses, and varying flags for each insn. */
for (insn_current_address = FIRST_INSN_ADDRESS, insn = first;
......@@ -752,9 +1105,22 @@ shorten_branches (first)
insn_current_address += insn_lengths[uid], insn = NEXT_INSN (insn))
{
uid = INSN_UID (insn);
insn_addresses[uid] = insn_current_address;
insn_lengths[uid] = 0;
varying_length[uid] = 0;
if (GET_CODE (insn) == CODE_LABEL)
{
int log = LABEL_TO_ALIGNMENT (insn);
if (log)
{
int align = 1 << log;
int new_address = insn_current_address + align - 1 & -align;
insn_lengths[uid] = new_address - insn_current_address;
insn_current_address = new_address;
}
}
insn_addresses[uid] = insn_current_address;
if (GET_CODE (insn) == NOTE || GET_CODE (insn) == BARRIER
|| GET_CODE (insn) == CODE_LABEL)
......@@ -764,25 +1130,7 @@ shorten_branches (first)
body = PATTERN (insn);
if (GET_CODE (body) == ADDR_VEC || GET_CODE (body) == ADDR_DIFF_VEC)
{
/* This only takes room if read-only data goes into the text
section. */
#if !defined(READONLY_DATA_SECTION) || defined(JUMP_TABLES_IN_TEXT_SECTION)
int unitsize = GET_MODE_SIZE (GET_MODE (body));
insn_lengths[uid] = (XVECLEN (body, GET_CODE (body) == ADDR_DIFF_VEC)
* GET_MODE_SIZE (GET_MODE (body)));
/* We don't know what address the ADDR_VEC/ADDR_DIFF_VEC will end
up at after branch shortening. As a result, it is impossible
to determine how much padding we need at this point. Therefore,
assume worst possible alignment. */
insn_lengths[uid] += unitsize - 1;
#else
;
#endif
}
; /* This should be handled by LABEL_ALIGN. */
else if (asm_noperands (body) >= 0)
insn_lengths[uid] = asm_insn_count (body) * insn_default_length (insn);
else if (GET_CODE (body) == SEQUENCE)
......@@ -842,6 +1190,7 @@ shorten_branches (first)
while (something_changed)
{
something_changed = 0;
insn_current_align = MAX_CODE_ALIGN - 1;
for (insn_current_address = FIRST_INSN_ADDRESS, insn = first;
insn != 0;
insn = NEXT_INSN (insn))
......@@ -852,9 +1201,34 @@ shorten_branches (first)
int tmp_length;
#endif
#endif
int length_align;
uid = INSN_UID (insn);
if (GET_CODE (insn) == CODE_LABEL)
{
int log = LABEL_TO_ALIGNMENT (insn);
if (log > insn_current_align)
{
int align = 1 << log;
int new_address= insn_current_address + align - 1 & -align;
insn_lengths[uid] = new_address - insn_current_address;
insn_current_align = log;
insn_current_address = new_address;
}
else
insn_lengths[uid] = 0;
insn_addresses[uid] = insn_current_address;
continue;
}
length_align = INSN_LENGTH_ALIGNMENT (insn);
if (length_align < insn_current_align)
insn_current_align = length_align;
insn_last_address = insn_addresses[uid];
insn_addresses[uid] = insn_current_address;
if (! varying_length[uid])
{
insn_current_address += insn_lengths[uid];
......@@ -915,6 +1289,9 @@ shorten_branches (first)
if (!optimize)
break;
}
free (varying_length);
#endif /* HAVE_ATTR_length */
}
......@@ -1413,17 +1790,8 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
/* Align the beginning of a loop, for higher speed
on certain machines. */
if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG && optimize > 0)
{
#ifdef ASM_OUTPUT_LOOP_ALIGN
rtx next = next_nonnote_insn (insn);
if (next && GET_CODE (next) == CODE_LABEL)
{
ASM_OUTPUT_LOOP_ALIGN (asm_out_file);
}
#endif
break;
}
if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG)
break; /* This used to depend on optimize, but that was bogus. */
if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END)
break;
......@@ -1633,13 +2001,6 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
break;
case BARRIER:
#ifdef ASM_OUTPUT_ALIGN_CODE
/* Don't litter the assembler output with needless alignments. A
BARRIER will be placed at the end of every function if HAVE_epilogue
is true. */
if (NEXT_INSN (insn))
ASM_OUTPUT_ALIGN_CODE (file);
#endif
#if defined (DWARF2_UNWIND_INFO) && !defined (ACCUMULATE_OUTGOING_ARGS)
/* If we push arguments, we need to check all insns for stack
adjustments. */
......@@ -1649,6 +2010,12 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
break;
case CODE_LABEL:
{
int align = LABEL_TO_ALIGNMENT (insn);
if (align && NEXT_INSN (insn))
ASM_OUTPUT_ALIGN (file, align);
}
CC_STATUS_INIT;
if (prescan > 0)
break;
......
......@@ -448,6 +448,7 @@ static void gen_delay PROTO((rtx));
static void gen_unit PROTO((rtx));
static void write_test_expr PROTO((rtx, int));
static int max_attr_value PROTO((rtx));
static int or_attr_value PROTO((rtx));
static void walk_attr_value PROTO((rtx));
static void write_attr_get PROTO((struct attr_desc *));
static rtx eliminate_known_true PROTO((rtx, rtx, int, int));
......@@ -2501,6 +2502,26 @@ max_fn (exp)
return make_numeric_value (max_attr_value (exp));
}
static void
write_length_unit_log ()
{
struct attr_desc *length_attr = find_attr ("length", 0);
struct attr_value *av;
struct insn_ent *ie;
unsigned int length_unit_log, length_or;
if (length_attr == 0)
return;
length_or = or_attr_value (length_attr->default_val->value);
for (av = length_attr->first_value; av; av = av->next)
for (ie = av->first_insn; ie; ie = ie->next)
length_or |= or_attr_value (av->value);
length_or = ~length_or;
for (length_unit_log = 0; length_or & 1; length_or >>= 1)
length_unit_log++;
printf ("int length_unit_log = %u;\n", length_unit_log);
}
/* Take a COND expression and see if any of the conditions in it can be
simplified. If any are known true or known false for the particular insn
code, the COND can be further simplified.
......@@ -4639,12 +4660,13 @@ write_test_expr (exp, flags)
XINT (exp, 0), XINT (exp, 0), XINT (exp, 0));
break;
/* The address of the current insn. It would be more consistent with
other usage to make this the address of the NEXT insn, but this gets
too confusing because of the ambiguity regarding the length of the
current insn. */
case PC:
printf ("insn_current_address");
/* The address of the current insn. We implement this actually as the
address of the current insn for backward branches, but the last
address of the next insn for forward branches, and both with
adjustments that account for the worst-case possible stretching of
intervening alignments between this insn and its destination. */
printf("insn_current_reference_address (insn)");
break;
case CONST_STRING:
......@@ -4709,6 +4731,42 @@ max_attr_value (exp)
return current_max;
}
/* Given an attribute value, return the result of ORing together all
CONST_STRING arguments encountered. It is assumed that they are
all numeric. */
static int
or_attr_value (exp)
rtx exp;
{
int current_or = 0;
int i;
if (GET_CODE (exp) == CONST_STRING)
return atoi (XSTR (exp, 0));
else if (GET_CODE (exp) == COND)
{
for (i = 0; i < XVECLEN (exp, 0); i += 2)
{
current_or |= or_attr_value (XVECEXP (exp, 0, i + 1));
}
current_or |= or_attr_value (XEXP (exp, 1));
}
else if (GET_CODE (exp) == IF_THEN_ELSE)
{
current_or = or_attr_value (XEXP (exp, 1));
current_or |= or_attr_value (XEXP (exp, 2));
}
else
abort ();
return current_or;
}
/* Scan an attribute value, possibly a conditional, and record what actions
will be required to do any conditional tests in it.
......@@ -5795,7 +5853,7 @@ write_const_num_delay_slots ()
printf (" default:\n");
printf (" return 1;\n");
printf (" }\n}\n");
printf (" }\n}\n\n");
}
}
......@@ -5982,6 +6040,8 @@ from the machine description file `md'. */\n\n");
/* Write out constant delay slot info */
write_const_num_delay_slots ();
write_length_unit_log ();
fflush (stdout);
exit (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
/* NOTREACHED */
......
......@@ -6154,25 +6154,30 @@ instead of inline unwinders and __unwind_function in the non-setjmp case.
This describes commands for alignment.
@table @code
@findex ASM_OUTPUT_ALIGN_CODE
@item ASM_OUTPUT_ALIGN_CODE (@var{file})
A C expression to output text to align the location counter in the way
that is desirable at a point in the code that is reached only by
jumping.
@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 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 ASM_OUTPUT_LOOP_ALIGN
@item ASM_OUTPUT_LOOP_ALIGN (@var{file})
A C expression to output text to align the location counter in the way
that is desirable at the beginning of a loop.
@findex LOOP_ALIGN
@item LOOP_ALIGN (@var{label})
The alignment (log base 2) to put in front of @var{label}, which follows
a NOTE_INSN_LOOP_BEG note.
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
@item LABEL_ALIGN (@var{label})
The alignment (log base 2) to put in front of @var{label}.
If LABEL_ALIGN_AFTER_BARRIER / LOOP_ALIGN specify a different alignment,
the maximum of the specified values is used.
@findex ASM_OUTPUT_SKIP
@item ASM_OUTPUT_SKIP (@var{stream}, @var{nbytes})
A C statement to output to the stdio stream @var{stream} an assembler
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment