[backport from gcc-4.8/trunk r195208 ] Date: Sun, 13 Jan 2013 22:37:10 +0000 From: "Joseph S dot Myers" Subject: Fix Thumb-1 jump table alignment length calculation (PR target/43961) List-Archive: Bug 43961 (a regression in 4.5 and later) is the ARM back end generating an out-of-range Thumb-1 branch because the calculation (in architecture-independent code) of the size of a jump table fails to allow for alignment. Jump table alignment should be allowed for through ADDR_VEC_ALIGN, but the ASM back end has a comment /* Jump table alignment is explicit in ASM_OUTPUT_CASE_LABEL. */ and defines ADDR_VEC_ALIGN to 0, so meaning that calculations relating to branch ranges fail to allow for the alignment. Bug 43961 has an old patch attached to define ADDR_VEC_ALIGN properly. Although that fixes the Thumb-1 issue, it introduces other problems for Thumb-2 jump tables because of an interaction between ADDR_VEC_ALIGN and CASE_VECTOR_SHORTEN_MODE. When CASE_VECTOR_SHORTEN_MODE is defined, the size of jump table entries, and so the alignment required for the jump table, can be changed in shorten_branches, but the alignment of the label before the jump table has already been computed based on the original mode, and is not then updated for the changed mode. This results in alignment being used before a Thumb-2 tbb jump table, which needs to follow the tbb instruction immediately. This patch arranges for shorten_branches to recalculate the alignments of labels before jump tables if CASE_VECTOR_SHORTEN_MODE. The recalculation logic may not match the logic for the original calculation in all cases - doing so would probably require additional information to be stored at the time of the original calculation so it is still available for the recalculation. But I believe the recalculated value based on ADDR_VEC_ALIGN should always work - and in the cases where, as for the Thumb-2 tbb case, overalignment will not work, only the recalculated value is going to be correct. (There is no testcase in this patch because this sort of thing is always extremely sensitive to slight changes in code generation between compiler versions and tends to require large, version-dependent testcases.) Tested with no regressions with cross to arm-none-linux-gnueabi (both default configuration, testing both -marm and -mthumb, and v7-A, again testing both -marm and -mthumb). OK to commit? gcc/ 2013-01-15 Joseph Myers Mikael Pettersson PR target/43961 * config/arm/arm.h (ADDR_VEC_ALIGN): Align SImode jump tables for Thumb. (ASM_OUTPUT_CASE_LABEL): Remove. (ASM_OUTPUT_BEFORE_CASE_LABEL): Define to empty. * final.c (shorten_branches): Update alignment of labels before jump tables if CASE_VECTOR_SHORTEN_MODE. --- gcc-4.7.2/gcc/config/arm/arm.h.~1~ 2012-01-10 05:14:09.000000000 +0100 +++ gcc-4.7.2/gcc/config/arm/arm.h 2013-01-20 13:55:22.114478641 +0100 @@ -2026,20 +2026,13 @@ extern int making_const_table; asm_fprintf (STREAM, "\tpop {%r}\n", REGNO); \ } while (0) -/* Jump table alignment is explicit in ASM_OUTPUT_CASE_LABEL. */ -#define ADDR_VEC_ALIGN(JUMPTABLE) 0 +#define ADDR_VEC_ALIGN(JUMPTABLE) \ + ((TARGET_THUMB && GET_MODE (PATTERN (JUMPTABLE)) == SImode) ? 2 : 0) -/* This is how to output a label which precedes a jumptable. Since - Thumb instructions are 2 bytes, we may need explicit alignment here. */ -#undef ASM_OUTPUT_CASE_LABEL -#define ASM_OUTPUT_CASE_LABEL(FILE, PREFIX, NUM, JUMPTABLE) \ - do \ - { \ - if (TARGET_THUMB && GET_MODE (PATTERN (JUMPTABLE)) == SImode) \ - ASM_OUTPUT_ALIGN (FILE, 2); \ - (*targetm.asm_out.internal_label) (FILE, PREFIX, NUM); \ - } \ - while (0) +/* Alignment for case labels comes from ADDR_VEC_ALIGN; avoid the + default alignment from elfos.h. */ +#undef ASM_OUTPUT_BEFORE_CASE_LABEL +#define ASM_OUTPUT_BEFORE_CASE_LABEL(FILE, PREFIX, NUM, TABLE) /* Empty. */ /* Make sure subsequent insns are aligned after a TBB. */ #define ASM_OUTPUT_CASE_END(FILE, NUM, JUMPTABLE) \ --- gcc-4.7.2/gcc/final.c.~1~ 2011-12-13 14:41:12.000000000 +0100 +++ gcc-4.7.2/gcc/final.c 2013-01-20 13:55:22.114478641 +0100 @@ -1184,6 +1184,29 @@ shorten_branches (rtx first ATTRIBUTE_UN if (LABEL_P (insn)) { int log = LABEL_TO_ALIGNMENT (insn); + +#ifdef CASE_VECTOR_SHORTEN_MODE + /* If the mode of a following jump table was changed, we + may need to update the alignment of this label. */ + rtx next; + bool next_is_jumptable; + + next = next_nonnote_insn (insn); + next_is_jumptable = next && JUMP_TABLE_DATA_P (next); + if ((JUMP_TABLES_IN_TEXT_SECTION + || readonly_data_section == text_section) + && next_is_jumptable) + { + int newlog = ADDR_VEC_ALIGN (next); + if (newlog != log) + { + log = newlog; + LABEL_TO_ALIGNMENT (insn) = log; + something_changed = 1; + } + } +#endif + if (log > insn_current_align) { int align = 1 << log;