+2017-07-10 Georg-Johann Lay <avr@gjlay.de>
+
+ Move jump-tables out of .text again.
+
+ PR target/81075
+ * config/avr/avr.c (ASM_OUTPUT_ADDR_VEC_ELT): Remove function.
+ (ASM_OUTPUT_ADDR_VEC): New function.
+ (avr_adjust_insn_length) [JUMP_TABLE_DATA_P]: Return 0.
+ (avr_final_prescan_insn) [avr_log.insn_addresses]: Dump
+ INSN_ADDRESSes as asm comment.
+ * config/avr/avr.h (JUMP_TABLES_IN_TEXT_SECTION): Adjust comment.
+ (ASM_OUTPUT_ADDR_VEC_ELT): Remove define.
+ (ASM_OUTPUT_ADDR_VEC): Define to avr_output_addr_vec.
+ * config/avr/avr.md (*tablejump): Adjust comment.
+ * config/avr/elf.h (ASM_OUTPUT_BEFORE_CASE_LABEL): Remove.
+ * config/avr/avr-log.c (avr_log_set_avr_log) <insn_addresses>:
+ New detail.
+ * config/avr/avr-protos.h (avr_output_addr_vec_elt): Remove proto.
+ (avr_output_addr_vec): New proto.
+ (avr_log_t) <insn_addresses>: New field.
+
2017-07-09 H.J. Lu <hongjiu.lu@intel.com>
PR target/81313
rtx_cost (PATTERN (insn), VOIDmode, INSN, 0,
optimize_insn_for_speed_p()));
}
+
+ if (avr_log.insn_addresses)
+ fprintf (asm_out_file, ";; ADDR = %d\n",
+ (int) INSN_ADDRESSES (INSN_UID (insn)));
}
/* Return 0 if undefined, 1 if always true or always false. */
rtx *op = recog_data.operand;
enum attr_adjust_len adjust_len;
+ /* As we pretend jump tables in .text, fix branch offsets crossing jump
+ tables now. */
+
+ if (JUMP_TABLE_DATA_P (insn))
+ return 0;
+
/* Some complex insns don't need length adjustment and therefore
the length need not/must not be adjusted for these insns.
It is easier to state this in an insn attribute "adjust_len" than
}
-/* Worker function for `ASM_OUTPUT_ADDR_VEC_ELT'. */
+/* Worker function for `ASM_OUTPUT_ADDR_VEC'. */
+/* Emit jump tables out-of-line so that branches crossing the table
+ get shorter offsets. If we have JUMP + CALL, then put the tables
+ in a dedicated non-.text section so that CALLs get better chance to
+ be relaxed to RCALLs.
+
+ We emit the tables by hand because `function_rodata_section' does not
+ work as expected, cf. PR71151, and we do *NOT* want the table to be
+ in .rodata, hence setting JUMP_TABLES_IN_TEXT_SECTION = 0 is of limited
+ use; and setting it to 1 attributes table lengths to branch offsets...
+ Moreover, fincal.c keeps switching section before each table entry
+ which we find too fragile as to rely on section caching. */
void
-avr_output_addr_vec_elt (FILE *stream, int value)
+avr_output_addr_vec (rtx_insn *labl, rtx table)
{
- if (AVR_HAVE_JMP_CALL)
- fprintf (stream, "\t.word gs(.L%d)\n", value);
+ FILE *stream = asm_out_file;
+
+ app_disable();
+
+ // Switch to appropriate (sub)section.
+
+ if (DECL_SECTION_NAME (current_function_decl)
+ && symtab_node::get (current_function_decl)
+ && ! symtab_node::get (current_function_decl)->implicit_section)
+ {
+ // .subsection will emit the code after the function and in the
+ // section as chosen by the user.
+
+ switch_to_section (current_function_section ());
+ fprintf (stream, "\t.subsection\t1\n");
+ }
else
- fprintf (stream, "\trjmp .L%d\n", value);
+ {
+ // Since PR63223 there is no restriction where to put the table; it
+ // may even reside above 128 KiB. We put it in a section as high as
+ // possible and avoid progmem in order not to waste flash <= 64 KiB.
+
+ const char *sec_name = ".jumptables.gcc";
+
+ // The table belongs to its host function, therefore use fine
+ // grained sections so that, if that function is removed by
+ // --gc-sections, the child table(s) may also be removed. */
+
+ tree asm_name = DECL_ASSEMBLER_NAME (current_function_decl);
+ const char *fname = IDENTIFIER_POINTER (asm_name);
+ fname = targetm.strip_name_encoding (fname);
+ sec_name = ACONCAT ((sec_name, ".", fname, NULL));
+
+ fprintf (stream, "\t.section\t%s,\"%s\",@progbits\n", sec_name,
+ AVR_HAVE_JMP_CALL ? "a" : "ax");
+ }
+
+ // Output the label that preceeds the table.
+
+ ASM_OUTPUT_ALIGN (stream, 1);
+ targetm.asm_out.internal_label (stream, "L", CODE_LABEL_NUMBER (labl));
+
+ // Output the table's content.
+
+ int vlen = XVECLEN (table, 0);
+
+ for (int idx = 0; idx < vlen; idx++)
+ {
+ int value = CODE_LABEL_NUMBER (XEXP (XVECEXP (table, 0, idx), 0));
+
+ if (AVR_HAVE_JMP_CALL)
+ fprintf (stream, "\t.word gs(.L%d)\n", value);
+ else
+ fprintf (stream, "\trjmp .L%d\n", value);
+ }
+
+ // Switch back to original section. As we clobbered the section above,
+ // forget the current section before switching back.
+
+ in_section = NULL;
+ switch_to_section (current_function_section ());
}
+
+/* Implement `TARGET_CONDITIONAL_REGISTER_USAGE'. */
+
static void
avr_conditional_register_usage (void)
{
#define SUPPORTS_INIT_PRIORITY 0
+/* We pretend jump tables are in text section because otherwise,
+ final.c will switch to .rodata before jump tables and thereby
+ triggers __do_copy_data. As we implement ASM_OUTPUT_ADDR_VEC,
+ we still have full control over the jump tables themselves. */
#define JUMP_TABLES_IN_TEXT_SECTION 1
#define ASM_COMMENT_START " ; "
fprintf (STREAM, "\tpop\tr%d", REGNO); \
}
-#define ASM_OUTPUT_ADDR_VEC_ELT(STREAM, VALUE) \
- avr_output_addr_vec_elt (STREAM, VALUE)
+#define ASM_OUTPUT_ADDR_VEC(TLABEL, TDATA) \
+ avr_output_addr_vec (TLABEL, TDATA)
#define ASM_OUTPUT_ALIGN(STREAM, POWER) \
do { \