diff options
author | J"orn Rennecke <amylaar@cygnus.co.uk> | 1998-03-02 11:54:35 +0000 |
---|---|---|
committer | Joern Rennecke <amylaar@gcc.gnu.org> | 1998-03-02 11:54:35 +0000 |
commit | fc470718aca25ebac8f4e07cbabef1da140755ae (patch) | |
tree | 9ba9228d811fc5a7f85644b346c78cc487723653 /gcc | |
parent | 948edfa70264176018542bf185e3ed1a68cf331c (diff) | |
download | gcc-fc470718aca25ebac8f4e07cbabef1da140755ae.zip gcc-fc470718aca25ebac8f4e07cbabef1da140755ae.tar.gz gcc-fc470718aca25ebac8f4e07cbabef1da140755ae.tar.bz2 |
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
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 29 | ||||
-rw-r--r-- | gcc/config/alpha/alpha.h | 10 | ||||
-rw-r--r-- | gcc/config/arc/arc.h | 7 | ||||
-rw-r--r-- | gcc/config/i386/gas.h | 14 | ||||
-rw-r--r-- | gcc/config/i386/i386.h | 4 | ||||
-rw-r--r-- | gcc/config/i386/i386.md | 2 | ||||
-rw-r--r-- | gcc/config/i386/osfrose.h | 12 | ||||
-rw-r--r-- | gcc/config/i386/svr3dbx.h | 11 | ||||
-rw-r--r-- | gcc/config/i960/i960.h | 3 | ||||
-rw-r--r-- | gcc/config/m32r/m32r.h | 7 | ||||
-rw-r--r-- | gcc/config/m68k/m68k.h | 4 | ||||
-rw-r--r-- | gcc/config/m88k/m88k.h | 9 | ||||
-rw-r--r-- | gcc/config/ns32k/encore.h | 4 | ||||
-rw-r--r-- | gcc/config/ns32k/merlin.h | 2 | ||||
-rw-r--r-- | gcc/config/ns32k/ns32k.h | 6 | ||||
-rw-r--r-- | gcc/config/ns32k/sequent.h | 2 | ||||
-rw-r--r-- | gcc/config/ns32k/tek6000.h | 2 | ||||
-rw-r--r-- | gcc/config/sparc/sparc.h | 6 | ||||
-rw-r--r-- | gcc/final.c | 487 | ||||
-rw-r--r-- | gcc/genattrtab.c | 72 | ||||
-rw-r--r-- | gcc/tm.texi | 23 |
21 files changed, 574 insertions, 142 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 1adde1d..449a76a 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,32 @@ +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. diff --git a/gcc/config/alpha/alpha.h b/gcc/config/alpha/alpha.h index 75b1f1e..4386084 100644 --- a/gcc/config/alpha/alpha.h +++ b/gcc/config/alpha/alpha.h @@ -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 diff --git a/gcc/config/arc/arc.h b/gcc/config/arc/arc.h index 181d45e..98b39e2 100644 --- a/gcc/config/arc/arc.h +++ b/gcc/config/arc/arc.h @@ -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 diff --git a/gcc/config/i386/gas.h b/gcc/config/i386/gas.h index fbfba74..50976cf 100644 --- a/gcc/config/i386/gas.h +++ b/gcc/config/i386/gas.h @@ -85,20 +85,6 @@ Boston, MA 02111-1307, USA. */ #define ASM_OUTPUT_ALIGN(FILE,LOG) \ 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 diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h index 3c9d47d..1765ce1 100644 --- a/gcc/config/i386/i386.h +++ b/gcc/config/i386/i386.h @@ -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. */ diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index a55ebc2..8db8acf 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -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; }") diff --git a/gcc/config/i386/osfrose.h b/gcc/config/i386/osfrose.h index fd4c3a8..c0c0f3f 100644 --- a/gcc/config/i386/osfrose.h +++ b/gcc/config/i386/osfrose.h @@ -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 diff --git a/gcc/config/i386/svr3dbx.h b/gcc/config/i386/svr3dbx.h index c394747..36c01cc 100644 --- a/gcc/config/i386/svr3dbx.h +++ b/gcc/config/i386/svr3dbx.h @@ -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 */ diff --git a/gcc/config/i960/i960.h b/gcc/config/i960/i960.h index 1ef3ba7..caf2530 100644 --- a/gcc/config/i960/i960.h +++ b/gcc/config/i960/i960.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. diff --git a/gcc/config/m32r/m32r.h b/gcc/config/m32r/m32r.h index d7517e9d..510bac0 100644 --- a/gcc/config/m32r/m32r.h +++ b/gcc/config/m32r/m32r.h @@ -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 diff --git a/gcc/config/m68k/m68k.h b/gcc/config/m68k/m68k.h index b3fb611..10284a3 100644 --- a/gcc/config/m68k/m68k.h +++ b/gcc/config/m68k/m68k.h @@ -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) \ { \ diff --git a/gcc/config/m88k/m88k.h b/gcc/config/m88k/m88k.h index 71a994e..b748a22 100644 --- a/gcc/config/m88k/m88k.h +++ b/gcc/config/m88k/m88k.h @@ -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 diff --git a/gcc/config/ns32k/encore.h b/gcc/config/ns32k/encore.h index 028a653..f388453 100644 --- a/gcc/config/ns32k/encore.h +++ b/gcc/config/ns32k/encore.h @@ -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. diff --git a/gcc/config/ns32k/merlin.h b/gcc/config/ns32k/merlin.h index cf5433c..d385395 100644 --- a/gcc/config/ns32k/merlin.h +++ b/gcc/config/ns32k/merlin.h @@ -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" diff --git a/gcc/config/ns32k/ns32k.h b/gcc/config/ns32k/ns32k.h index b98d72f..47a1d84 100644 --- a/gcc/config/ns32k/ns32k.h +++ b/gcc/config/ns32k/ns32k.h @@ -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, diff --git a/gcc/config/ns32k/sequent.h b/gcc/config/ns32k/sequent.h index 1165aa3..1e8c353 100644 --- a/gcc/config/ns32k/sequent.h +++ b/gcc/config/ns32k/sequent.h @@ -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" diff --git a/gcc/config/ns32k/tek6000.h b/gcc/config/ns32k/tek6000.h index 5b84bcb..01c88e3 100644 --- a/gcc/config/ns32k/tek6000.h +++ b/gcc/config/ns32k/tek6000.h @@ -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" diff --git a/gcc/config/sparc/sparc.h b/gcc/config/sparc/sparc.h index 9463629..44c0b21 100644 --- a/gcc/config/sparc/sparc.h +++ b/gcc/config/sparc/sparc.h @@ -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)) diff --git a/gcc/final.c b/gcc/final.c index 3dd1ef1..de66f9c 100644 --- a/gcc/final.c +++ b/gcc/final.c @@ -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; diff --git a/gcc/genattrtab.c b/gcc/genattrtab.c index d00644d..49a6244 100644 --- a/gcc/genattrtab.c +++ b/gcc/genattrtab.c @@ -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)); @@ -2500,6 +2501,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 @@ -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: @@ -4708,6 +4730,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 */ diff --git a/gcc/tm.texi b/gcc/tm.texi index aad6506..95ef9a6 100644 --- a/gcc/tm.texi +++ b/gcc/tm.texi @@ -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 |