From 6a32d87432882fa1e7bcfca440b080d6667792c3 Mon Sep 17 00:00:00 2001 From: Catherine Moore Date: Thu, 9 Apr 2009 15:55:59 +0000 Subject: [PATCH] 2009-04-09 Catherine Moore * config/tc-mips.c (mips_fix_24k): Declare. (check_for_24k_errata): New. (mips_cleanup): Call check_for_24k_errata. (start_noreorder): Likewise. (md_mips_end): Likewise. (s_change_sec): Likewise. (s_change_section): Likewise. (append_insn): Call check_for_24k_errata. Prevent ERET/DERET instructions from being moved into delay slots. (OPTION_FIX_24K): New. (OPTION_NO_FIX_24k) New. (md_longopts): Add "mfix-24k" and "mno-fix-24k". (md_parse_option): Handle fix-24k options. (md_show_usage): Display fix-24k options. * doc/c-mips.texi: Document. * testsuite/gas/mips/mips.exp: Run new tests. * testsuite/gas/mips/eret.s: New test. * testsuite/gas/mips/eret.d: New test output. * testsuite/gas/mips/eret.l: New test output. --- gas/ChangeLog | 23 ++++++ gas/config/tc-mips.c | 134 +++++++++++++++++++++++++++++++- gas/doc/c-mips.texi | 4 + gas/testsuite/gas/mips/eret.d | 41 ++++++++++ gas/testsuite/gas/mips/eret.l | 3 + gas/testsuite/gas/mips/eret.s | 27 +++++++ gas/testsuite/gas/mips/mips.exp | 3 + 7 files changed, 232 insertions(+), 3 deletions(-) create mode 100644 gas/testsuite/gas/mips/eret.d create mode 100644 gas/testsuite/gas/mips/eret.l create mode 100644 gas/testsuite/gas/mips/eret.s diff --git a/gas/ChangeLog b/gas/ChangeLog index 5f6380153a8..19a76972fb5 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,26 @@ +2009-04-09 Catherine Moore + + * config/tc-mips.c (mips_fix_24k): Declare. + (check_for_24k_errata): New. + (mips_cleanup): Call check_for_24k_errata. + (start_noreorder): Likewise. + (md_mips_end): Likewise. + (s_change_sec): Likewise. + (s_change_section): Likewise. + (append_insn): Call check_for_24k_errata. Prevent + ERET/DERET instructions from being moved into delay + slots. + (OPTION_FIX_24K): New. + (OPTION_NO_FIX_24k) New. + (md_longopts): Add "mfix-24k" and "mno-fix-24k". + (md_parse_option): Handle fix-24k options. + (md_show_usage): Display fix-24k options. + * doc/c-mips.texi: Document. + * testsuite/gas/mips/mips.exp: Run new tests. + * testsuite/gas/mips/eret.s: New test. + * testsuite/gas/mips/eret.d: New test output. + * testsuite/gas/mips/eret.l: New test output. + 2009-04-09 Adam Nemet * config/tc-mips.c (mips_dwarf2_addr_size): Use HAVE_64BIT_OBJECTS diff --git a/gas/config/tc-mips.c b/gas/config/tc-mips.c index 62d4e4f4d1e..5c85845a4e3 100644 --- a/gas/config/tc-mips.c +++ b/gas/config/tc-mips.c @@ -760,6 +760,9 @@ static int mips_fix_vr4120; /* ...likewise -mfix-vr4130. */ static int mips_fix_vr4130; +/* ...likewise -mfix-24k. */ +static int mips_fix_24k; + /* We don't relax branches by default, since this causes us to expand `la .l2 - .l1' if there's a branch between .l1 and .l2, because we fail to compute the offset before expanding the macro to the most @@ -1789,6 +1792,85 @@ reg_lookup (char **s, unsigned int types, unsigned int *regnop) return reg >= 0; } +#define INSN_ERET 0x42000018 +#define INSN_DERET 0x4200001f + +/* Implement the ERET/DERET Errata for MIPS 24k. + + If an ERET/DERET is encountered in a noreorder block, + warn if the ERET/DERET is followed by a branch instruction. + Also warn if the ERET/DERET is the last instruction in the + noreorder block. + + IF an ERET/DERET is in a reorder block and is followed by a + branch instruction, insert a nop. */ + +static void +check_for_24k_errata (struct mips_cl_insn *insn, int eret_ndx) +{ + bfd_boolean next_insn_is_branch = FALSE; + + /* eret_ndx will be -1 for the last instruction in a section + and the ERET/DERET will be in insn, not history. */ + if (insn + && eret_ndx == -1 + && (insn->insn_opcode == INSN_ERET + || insn->insn_opcode == INSN_DERET) + && insn->noreorder_p) + { + as_warn (_("ERET and DERET must be followed by a NOP on the 24K.")); + return; + } + + if (history[eret_ndx].insn_opcode != INSN_ERET + && history[eret_ndx].insn_opcode != INSN_DERET) + return; + + if (!insn) + { + if (history[eret_ndx].noreorder_p) + as_warn (_("ERET and DERET must be followed by a NOP on the 24K.")); + return; + } + + next_insn_is_branch = ((insn->insn_opcode == INSN_ERET) + || (insn->insn_opcode == INSN_DERET) + || (insn->insn_mo->pinfo + & (INSN_UNCOND_BRANCH_DELAY + | INSN_COND_BRANCH_DELAY + | INSN_COND_BRANCH_LIKELY))); + + if (next_insn_is_branch && history[eret_ndx].noreorder_p) + { + as_warn (_("ERET and DERET must be followed by a NOP on the 24K.")); + return; + } + + /* Emit nop if the next instruction is a branch. */ + if (next_insn_is_branch) + { + long nop_where, br_where; + struct frag *nop_frag, *br_frag; + struct mips_cl_insn br_insn, nop_insn; + + emit_nop (); + + nop_insn = history[eret_ndx - 1]; + nop_frag = history[eret_ndx - 1].frag; + nop_where = history[eret_ndx - 1].where; + + br_insn = history[eret_ndx]; + br_frag = history[eret_ndx].frag; + br_where = history[eret_ndx].where; + + move_insn (&nop_insn, br_frag, br_where); + move_insn (&br_insn, nop_frag, nop_where); + + history[eret_ndx-1] = br_insn; + history[eret_ndx] = nop_insn; + } +} + /* Return TRUE if opcode MO is valid on the currently selected ISA and architecture. If EXPANSIONP is TRUE then this check is done while expanding a macro. Use is_opcode_valid_16 for MIPS16 opcodes. */ @@ -2074,6 +2156,9 @@ md_begin (void) void md_mips_end (void) { + if (mips_fix_24k) + check_for_24k_errata ((struct mips_cl_insn *) &history[0], -1); + if (! ECOFF_DEBUGGING) md_obj_end (); } @@ -2705,6 +2790,7 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr, bfd_reloc_code_real_type *reloc_type) { unsigned long prev_pinfo, pinfo; + int hndx_24k = 0; relax_stateT prev_insn_frag_type = 0; bfd_boolean relaxed_branch = FALSE; segment_info_type *si = seg_info (now_seg); @@ -3238,7 +3324,11 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr, || (mips_opts.mips16 && history[0].fixp[0]) /* If the previous instruction is a sync, sync.l, or sync.p, we can not swap. */ - || (prev_pinfo & INSN_SYNC)) + || (prev_pinfo & INSN_SYNC) + /* If the previous instruction is an ERET or + DERET, avoid the swap. */ + || (history[0].insn_opcode == INSN_ERET) + || (history[0].insn_opcode == INSN_DERET)) { if (mips_opts.mips16 && (pinfo & INSN_UNCOND_BRANCH_DELAY) @@ -3258,6 +3348,8 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr, slot, and bump the destination address. */ insert_into_history (0, 1, ip); emit_nop (); + if (mips_fix_24k) + hndx_24k++; } if (mips_relax.sequence) @@ -3297,7 +3389,14 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr, /* If that was an unconditional branch, forget the previous insn information. */ if (pinfo & INSN_UNCOND_BRANCH_DELAY) - mips_no_prev_insn (); + { + /* Check for eret/deret before clearing history. */ + if (mips_fix_24k) + check_for_24k_errata ( + (struct mips_cl_insn *) &history[hndx_24k], + hndx_24k+1); + mips_no_prev_insn (); + } } else if (pinfo & INSN_COND_BRANCH_LIKELY) { @@ -3307,6 +3406,8 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr, the next instruction. */ insert_into_history (0, 1, ip); emit_nop (); + if (mips_fix_24k) + hndx_24k++; } else insert_into_history (0, 1, ip); @@ -3314,6 +3415,10 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr, else insert_into_history (0, 1, ip); + if (mips_fix_24k) + check_for_24k_errata ((struct mips_cl_insn *) &history[hndx_24k], + hndx_24k+1); + /* We just output an insn, so the next one doesn't have a label. */ mips_clear_insn_labels (); } @@ -3400,6 +3505,9 @@ start_noreorder (void) static void end_noreorder (void) { + if (mips_fix_24k) + check_for_24k_errata (NULL, 0); + mips_opts.noreorder--; if (mips_opts.noreorder == 0 && prev_nop_frag != NULL) { @@ -11175,7 +11283,9 @@ enum options OPTION_M3900, OPTION_NO_M3900, OPTION_M7000_HILO_FIX, - OPTION_MNO_7000_HILO_FIX, + OPTION_MNO_7000_HILO_FIX, + OPTION_FIX_24K, + OPTION_NO_FIX_24K, OPTION_FIX_VR4120, OPTION_NO_FIX_VR4120, OPTION_FIX_VR4130, @@ -11268,6 +11378,8 @@ struct option md_longopts[] = {"mno-fix-vr4120", no_argument, NULL, OPTION_NO_FIX_VR4120}, {"mfix-vr4130", no_argument, NULL, OPTION_FIX_VR4130}, {"mno-fix-vr4130", no_argument, NULL, OPTION_NO_FIX_VR4130}, + {"mfix-24k", no_argument, NULL, OPTION_FIX_24K}, + {"mno-fix-24k", no_argument, NULL, OPTION_NO_FIX_24K}, /* Miscellaneous options. */ {"trap", no_argument, NULL, OPTION_TRAP}, @@ -11521,6 +11633,14 @@ md_parse_option (int c, char *arg) mips_opts.ase_smartmips = 0; break; + case OPTION_FIX_24K: + mips_fix_24k = 1; + break; + + case OPTION_NO_FIX_24K: + mips_fix_24k = 0; + break; + case OPTION_FIX_VR4120: mips_fix_vr4120 = 1; break; @@ -12468,6 +12588,10 @@ s_change_sec (int sec) #endif mips_emit_delays (); + + if (mips_fix_24k) + check_for_24k_errata ((struct mips_cl_insn *) &history[0], -1); + switch (sec) { case 't': @@ -12526,6 +12650,9 @@ s_change_section (int ignore ATTRIBUTE_UNUSED) if (!IS_ELF) return; + if (mips_fix_24k) + check_for_24k_errata ((struct mips_cl_insn *) &history[0], -1); + section_name = input_line_pointer; c = get_symbol_end (); if (c) @@ -15457,6 +15584,7 @@ MIPS options:\n\ fprintf (stream, _("\ -mfix-vr4120 work around certain VR4120 errata\n\ -mfix-vr4130 work around VR4130 mflo/mfhi errata\n\ +-mfix-24k insert a nop after ERET and DERET instructions\n\ -mgp32 use 32-bit GPRs, regardless of the chosen ISA\n\ -mfp32 use 32-bit FPRs, regardless of the chosen ISA\n\ -msym32 assume all symbols have 32-bit values\n\ diff --git a/gas/doc/c-mips.texi b/gas/doc/c-mips.texi index 91bd82229ac..695176b3ffd 100644 --- a/gas/doc/c-mips.texi +++ b/gas/doc/c-mips.texi @@ -182,6 +182,10 @@ all problems in hand-written assembler code. @itemx -no-mfix-vr4130 Insert nops to work around the VR4130 @samp{mflo}/@samp{mfhi} errata. +@item -mfix-24k +@itemx -no-mfix-24k +Insert nops to work around the 24K @samp{eret}/@samp{deret} errata. + @item -m4010 @itemx -no-m4010 Generate code for the LSI @sc{r4010} chip. This tells the assembler to diff --git a/gas/testsuite/gas/mips/eret.d b/gas/testsuite/gas/mips/eret.d new file mode 100644 index 00000000000..1c0124a2481 --- /dev/null +++ b/gas/testsuite/gas/mips/eret.d @@ -0,0 +1,41 @@ +#objdump: -d +#name: MIPS eret disassembly +#as: -mfix-24k -march=24kc --no-warn + +.*\.o: file format .*mips.* + +Disassembly of section \.text: + +00000000 <\.text>: + 0: 240c0000 li t4,0 + 4: 42000018 eret + 8: 00000000 nop + c: 10000003 b 0x1c + 10: 00000000 nop + 14: 240a0003 li t2,3 + 18: 42000018 eret + 1c: 24040000 li a0,0 + 20: 4200001f deret + 24: 00000000 nop + 28: 116afffa beq t3,t2,0x14 + 2c: 00000000 nop + 30: 4200001f deret + 34: 00000000 nop + 38: 42000018 eret + 3c: 00000000 nop + 40: 42000018 eret + 44: 00000000 nop + 48: 1000fff4 b 0x1c + 4c: 00000000 nop + 50: 240c0004 li t4,4 + 54: 4200001f deret + 58: 240c0003 li t4,3 + 5c: 42000018 eret + 60: 10000005 b 0x78 + 64: 240c0003 li t4,3 + 68: 42000018 eret + 6c: 00000000 nop + 70: 10000001 b 0x78 + 74: 240c0003 li t4,3 + 78: 240c0003 li t4,3 + 7c: 42000018 eret diff --git a/gas/testsuite/gas/mips/eret.l b/gas/testsuite/gas/mips/eret.l new file mode 100644 index 00000000000..327dd95252b --- /dev/null +++ b/gas/testsuite/gas/mips/eret.l @@ -0,0 +1,3 @@ +.*\.s: Assembler messages: +.*\.s:20: Warning: ERET and DERET must be followed by a NOP on the 24K\. +.*\.s:27: Warning: ERET and DERET must be followed by a NOP on the 24K\. diff --git a/gas/testsuite/gas/mips/eret.s b/gas/testsuite/gas/mips/eret.s new file mode 100644 index 00000000000..081d01ef921 --- /dev/null +++ b/gas/testsuite/gas/mips/eret.s @@ -0,0 +1,27 @@ + .text + li $t4, 0 + eret + b 2f +1: li $t2, 3 + eret +2: li $a0, 0 + deret + beq $t3,$t2,1b + deret + eret + eret + b 2b + + .set noreorder + li $t4, 4 + deret + li $t4, 3 + eret + b 1f + li $t4, 3 + eret + nop + b 1f + li $t4, 3 +1: li $t4, 3 + eret diff --git a/gas/testsuite/gas/mips/mips.exp b/gas/testsuite/gas/mips/mips.exp index b213aba53f1..627232f43d7 100644 --- a/gas/testsuite/gas/mips/mips.exp +++ b/gas/testsuite/gas/mips/mips.exp @@ -436,6 +436,9 @@ if { [istarget mips*-*-vxworks*] } { } else { run_dump_test "jal" } + run_dump_test "eret" + run_list_test "eret" "-mfix-24k -march=24kc" "MIPS eret warnings" + if $elf { run_dump_test "jal-svr4pic" } if $elf { run_dump_test "jal-xgot" } run_list_test_arches "jal-range" "-32" [mips_arch_list_matching mips1] -- 2.30.2