X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gas%2Fconfig%2Ftc-mips.c;h=562da649332bd3cc477242f19c762f80a4149b4f;hb=0674ee5dada21c8deec690ca66d5b2870f13ea49;hp=5768f186b07afc1d8a824c17de48e52457672ba1;hpb=8484fb75874eb9ef35710ac6579433f062ddba18;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/config/tc-mips.c b/gas/config/tc-mips.c index 5768f186b0..562da64933 100644 --- a/gas/config/tc-mips.c +++ b/gas/config/tc-mips.c @@ -1153,13 +1153,14 @@ static int mips_relax_branch; code found in the opcode file for this relocation, the register selected as the assembler temporary, whether in the 32-bit instruction mode, whether the branch is unconditional, whether it is - compact, whether it stores the link address implicitly in $ra, - whether relaxation of out-of-range 32-bit branches to a sequence of + compact, whether there is no delay-slot instruction available to fill + in, whether it stores the link address implicitly in $ra, whether + relaxation of out-of-range 32-bit branches to a sequence of instructions is enabled, and whether the displacement of a branch is too large to fit as an immediate argument of a 16-bit and a 32-bit branch, respectively. */ #define RELAX_MICROMIPS_ENCODE(type, at, insn32, \ - uncond, compact, link, \ + uncond, compact, link, nods, \ relax32, toofar16, toofar32) \ (0x40000000 \ | ((type) & 0xff) \ @@ -1168,9 +1169,10 @@ static int mips_relax_branch; | ((uncond) ? 0x4000 : 0) \ | ((compact) ? 0x8000 : 0) \ | ((link) ? 0x10000 : 0) \ - | ((relax32) ? 0x20000 : 0) \ - | ((toofar16) ? 0x40000 : 0) \ - | ((toofar32) ? 0x80000 : 0)) + | ((nods) ? 0x20000 : 0) \ + | ((relax32) ? 0x40000 : 0) \ + | ((toofar16) ? 0x80000 : 0) \ + | ((toofar32) ? 0x100000 : 0)) #define RELAX_MICROMIPS_P(i) (((i) & 0xc0000000) == 0x40000000) #define RELAX_MICROMIPS_TYPE(i) ((i) & 0xff) #define RELAX_MICROMIPS_AT(i) (((i) >> 8) & 0x1f) @@ -1178,14 +1180,15 @@ static int mips_relax_branch; #define RELAX_MICROMIPS_UNCOND(i) (((i) & 0x4000) != 0) #define RELAX_MICROMIPS_COMPACT(i) (((i) & 0x8000) != 0) #define RELAX_MICROMIPS_LINK(i) (((i) & 0x10000) != 0) -#define RELAX_MICROMIPS_RELAX32(i) (((i) & 0x20000) != 0) +#define RELAX_MICROMIPS_NODS(i) (((i) & 0x20000) != 0) +#define RELAX_MICROMIPS_RELAX32(i) (((i) & 0x40000) != 0) -#define RELAX_MICROMIPS_TOOFAR16(i) (((i) & 0x40000) != 0) -#define RELAX_MICROMIPS_MARK_TOOFAR16(i) ((i) | 0x40000) -#define RELAX_MICROMIPS_CLEAR_TOOFAR16(i) ((i) & ~0x40000) -#define RELAX_MICROMIPS_TOOFAR32(i) (((i) & 0x80000) != 0) -#define RELAX_MICROMIPS_MARK_TOOFAR32(i) ((i) | 0x80000) -#define RELAX_MICROMIPS_CLEAR_TOOFAR32(i) ((i) & ~0x80000) +#define RELAX_MICROMIPS_TOOFAR16(i) (((i) & 0x80000) != 0) +#define RELAX_MICROMIPS_MARK_TOOFAR16(i) ((i) | 0x80000) +#define RELAX_MICROMIPS_CLEAR_TOOFAR16(i) ((i) & ~0x80000) +#define RELAX_MICROMIPS_TOOFAR32(i) (((i) & 0x100000) != 0) +#define RELAX_MICROMIPS_MARK_TOOFAR32(i) ((i) | 0x100000) +#define RELAX_MICROMIPS_CLEAR_TOOFAR32(i) ((i) & ~0x100000) /* Sign-extend 16-bit value X. */ #define SEXT_16BIT(X) ((((X) + 0x8000) & 0xffff) - 0x8000) @@ -2108,7 +2111,7 @@ mips_lookup_ase (const char *name) static inline unsigned int micromips_insn_length (const struct mips_opcode *mo) { - return (mo->mask >> 16) == 0 ? 2 : 4; + return mips_opcode_32bit_p (mo) ? 4 : 2; } /* Return the length of MIPS16 instruction OPCODE. */ @@ -3214,7 +3217,7 @@ is_opcode_valid (const struct mips_opcode *mo) int fp_s, fp_d; unsigned int i; - if (ISA_HAS_64BIT_REGS (mips_opts.isa)) + if (ISA_HAS_64BIT_REGS (isa)) for (i = 0; i < ARRAY_SIZE (mips_ases); i++) if ((ase & mips_ases[i].flags) == mips_ases[i].flags) ase |= mips_ases[i].flags64; @@ -3255,7 +3258,8 @@ is_opcode_valid_16 (const struct mips_opcode *mo) } /* Return TRUE if the size of the microMIPS opcode MO matches one - explicitly requested. Always TRUE in the standard MIPS mode. */ + explicitly requested. Always TRUE in the standard MIPS mode. + Use is_size_valid_16 for MIPS16 opcodes. */ static bfd_boolean is_size_valid (const struct mips_opcode *mo) @@ -3277,6 +3281,23 @@ is_size_valid (const struct mips_opcode *mo) return forced_insn_length == micromips_insn_length (mo); } +/* Return TRUE if the size of the MIPS16 opcode MO matches one + explicitly requested. */ + +static bfd_boolean +is_size_valid_16 (const struct mips_opcode *mo) +{ + if (!forced_insn_length) + return TRUE; + if (mo->pinfo == INSN_MACRO) + return FALSE; + if (forced_insn_length == 2 && mips_opcode_32bit_p (mo)) + return FALSE; + if (forced_insn_length == 4 && (mo->pinfo2 & INSN2_SHORT_ONLY)) + return FALSE; + return TRUE; +} + /* Return TRUE if the microMIPS opcode MO is valid for the delay slot of the preceding instruction. Always TRUE in the standard MIPS mode. @@ -3353,7 +3374,7 @@ validate_mips_insn (const struct mips_opcode *opcode, default: if (!decode_operand) - operand = decode_mips16_operand (*s, FALSE); + operand = decode_mips16_operand (*s, mips_opcode_32bit_p (opcode)); else operand = decode_operand (s); if (!operand && opcode->pinfo != INSN_MACRO) @@ -3411,18 +3432,9 @@ static int validate_mips16_insn (const struct mips_opcode *opcode, struct mips_operand_array *operands) { - if (opcode->args[0] == 'a' || opcode->args[0] == 'i') - { - /* In this case OPCODE defines the first 16 bits in a 32-bit jump - instruction. Use TMP to describe the full instruction. */ - struct mips_opcode tmp; + unsigned long insn_bits = mips_opcode_32bit_p (opcode) ? 0xffffffff : 0xffff; - tmp = *opcode; - tmp.match <<= 16; - tmp.mask <<= 16; - return validate_mips_insn (&tmp, 0xffffffff, 0, operands); - } - return validate_mips_insn (opcode, 0xffff, 0, operands); + return validate_mips_insn (opcode, insn_bits, 0, operands); } /* The microMIPS version of validate_mips_insn. */ @@ -4708,7 +4720,7 @@ struct mips_arg_info unsigned int last_op_int; /* If true, match routines should assume that no later instruction - alternative matches and should therefore be as accomodating as + alternative matches and should therefore be as accommodating as possible. Match routines should not report errors if something is only invalid for !LAX_MATCH. */ bfd_boolean lax_match; @@ -6830,23 +6842,33 @@ get_append_method (struct mips_cl_insn *ip, expressionS *address_expr, && gpr_read_mask (ip) != 0) return APPEND_ADD_COMPACT; + if (mips_opts.micromips + && ((ip->insn_opcode & 0xffe0) == 0x4580 + || (!forced_insn_length + && ((ip->insn_opcode & 0xfc00) == 0xcc00 + || (ip->insn_opcode & 0xdc00) == 0x8c00)) + || (ip->insn_opcode & 0xdfe00000) == 0x94000000 + || (ip->insn_opcode & 0xdc1f0000) == 0x94000000)) + return APPEND_ADD_COMPACT; + return APPEND_ADD_WITH_NOP; } return APPEND_ADD; } -/* IP is a MIPS16 instruction whose opcode we have just changed. - Point IP->insn_mo to the new opcode's definition. */ +/* IP is an instruction whose opcode we have just changed, END points + to the end of the opcode table processed. Point IP->insn_mo to the + new opcode's definition. */ static void -find_altered_mips16_opcode (struct mips_cl_insn *ip) +find_altered_opcode (struct mips_cl_insn *ip, const struct mips_opcode *end) { - const struct mips_opcode *mo, *end; + const struct mips_opcode *mo; - end = &mips16_opcodes[bfd_mips16_num_opcodes]; for (mo = ip->insn_mo; mo < end; mo++) - if ((ip->insn_opcode & mo->mask) == mo->match) + if (mo->pinfo != INSN_MACRO + && (ip->insn_opcode & mo->mask) == mo->match) { ip->insn_mo = mo; return; @@ -6854,6 +6876,24 @@ find_altered_mips16_opcode (struct mips_cl_insn *ip) abort (); } +/* IP is a MIPS16 instruction whose opcode we have just changed. + Point IP->insn_mo to the new opcode's definition. */ + +static void +find_altered_mips16_opcode (struct mips_cl_insn *ip) +{ + find_altered_opcode (ip, &mips16_opcodes[bfd_mips16_num_opcodes]); +} + +/* IP is a microMIPS instruction whose opcode we have just changed. + Point IP->insn_mo to the new opcode's definition. */ + +static void +find_altered_micromips_opcode (struct mips_cl_insn *ip) +{ + find_altered_opcode (ip, µmips_opcodes[bfd_micromips_num_opcodes]); +} + /* For microMIPS macros, we need to generate a local number label as the target of branches. */ #define MICROMIPS_LABEL_CHAR '\037' @@ -7042,8 +7082,14 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr, prev_pinfo2 = history[0].insn_mo->pinfo2; pinfo = ip->insn_mo->pinfo; + /* Don't raise alarm about `nods' frags as they'll fill in the right + kind of nop in relaxation if required. */ if (mips_opts.micromips && !expansionp + && !(history[0].frag + && history[0].frag->fr_type == rs_machine_dependent + && RELAX_MICROMIPS_P (history[0].frag->fr_subtype) + && RELAX_MICROMIPS_NODS (history[0].frag->fr_subtype)) && (((prev_pinfo2 & INSN2_BRANCH_DELAY_16BIT) != 0 && micromips_insn_length (ip->insn_mo) != 2) || ((prev_pinfo2 & INSN2_BRANCH_DELAY_32BIT) != 0 @@ -7293,21 +7339,26 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr, 16-bit/32-bit instructions. */ && !forced_insn_length) { - bfd_boolean relax16 = *reloc_type > BFD_RELOC_UNUSED; + bfd_boolean relax16 = (method != APPEND_ADD_COMPACT + && *reloc_type > BFD_RELOC_UNUSED); int type = relax16 ? *reloc_type - BFD_RELOC_UNUSED : 0; int uncond = uncond_branch_p (ip) ? -1 : 0; - int compact = compact_branch_p (ip); + int compact = compact_branch_p (ip) || method == APPEND_ADD_COMPACT; + int nods = method == APPEND_ADD_WITH_NOP; int al = pinfo & INSN_WRITE_GPR_31; - int length32; + int length32 = nods ? 8 : 4; gas_assert (address_expr != NULL); gas_assert (!mips_relax.sequence); relaxed_branch = TRUE; - length32 = relaxed_micromips_32bit_branch_length (NULL, NULL, uncond); - add_relaxed_insn (ip, relax32 ? length32 : 4, relax16 ? 2 : 4, + if (nods) + method = APPEND_ADD; + if (relax32) + length32 = relaxed_micromips_32bit_branch_length (NULL, NULL, uncond); + add_relaxed_insn (ip, length32, relax16 ? 2 : 4, RELAX_MICROMIPS_ENCODE (type, AT, mips_opts.insn32, - uncond, compact, al, + uncond, compact, al, nods, relax32, 0, 0), address_expr->X_add_symbol, address_expr->X_add_number); @@ -7315,9 +7366,23 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr, } else if (mips_opts.mips16 && *reloc_type > BFD_RELOC_UNUSED) { + bfd_boolean require_unextended; + bfd_boolean require_extended; symbolS *symbol; offsetT offset; + if (forced_insn_length != 0) + { + require_unextended = forced_insn_length == 2; + require_extended = forced_insn_length == 4; + } + else + { + require_unextended = (mips_opts.noautoextend + && !mips_opcode_32bit_p (ip->insn_mo)); + require_extended = 0; + } + /* We need to set up a variant frag. */ gas_assert (address_expr != NULL); /* Pass any `O_symbol' expression unchanged as an `expr_section' @@ -7336,7 +7401,7 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr, add_relaxed_insn (ip, 4, 0, RELAX_MIPS16_ENCODE (*reloc_type - BFD_RELOC_UNUSED, - forced_insn_length == 2, forced_insn_length == 4, + require_unextended, require_extended, delayed_branch_p (&history[0]), history[0].mips16_absolute_jump_p), symbol, offset); @@ -7512,9 +7577,50 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr, case APPEND_ADD_COMPACT: /* Convert MIPS16 jr/jalr into a "compact" jump. */ - gas_assert (mips_opts.mips16); - ip->insn_opcode |= 0x0080; - find_altered_mips16_opcode (ip); + if (mips_opts.mips16) + { + ip->insn_opcode |= 0x0080; + find_altered_mips16_opcode (ip); + } + /* Convert microMIPS instructions. */ + else if (mips_opts.micromips) + { + /* jr16->jrc */ + if ((ip->insn_opcode & 0xffe0) == 0x4580) + ip->insn_opcode |= 0x0020; + /* b16->bc */ + else if ((ip->insn_opcode & 0xfc00) == 0xcc00) + ip->insn_opcode = 0x40e00000; + /* beqz16->beqzc, bnez16->bnezc */ + else if ((ip->insn_opcode & 0xdc00) == 0x8c00) + { + unsigned long regno; + + regno = ip->insn_opcode >> MICROMIPSOP_SH_MD; + regno &= MICROMIPSOP_MASK_MD; + regno = micromips_to_32_reg_d_map[regno]; + ip->insn_opcode = (((ip->insn_opcode << 9) & 0x00400000) + | (regno << MICROMIPSOP_SH_RS) + | 0x40a00000) ^ 0x00400000; + } + /* beqz->beqzc, bnez->bnezc */ + else if ((ip->insn_opcode & 0xdfe00000) == 0x94000000) + ip->insn_opcode = ((ip->insn_opcode & 0x001f0000) + | ((ip->insn_opcode >> 7) & 0x00400000) + | 0x40a00000) ^ 0x00400000; + /* beq $0->beqzc, bne $0->bnezc */ + else if ((ip->insn_opcode & 0xdc1f0000) == 0x94000000) + ip->insn_opcode = (((ip->insn_opcode >> + (MICROMIPSOP_SH_RT - MICROMIPSOP_SH_RS)) + & (MICROMIPSOP_MASK_RS << MICROMIPSOP_SH_RS)) + | ((ip->insn_opcode >> 7) & 0x00400000) + | 0x40a00000) ^ 0x00400000; + else + abort (); + find_altered_micromips_opcode (ip); + } + else + abort (); install_insn (ip); insert_into_history (0, 1, ip); break; @@ -7956,9 +8062,17 @@ match_mips16_insn (struct mips_cl_insn *insn, const struct mips_opcode *opcode, const char *args; const struct mips_operand *operand; const struct mips_operand *ext_operand; + int required_insn_length; struct mips_arg_info arg; int relax_char; + if (forced_insn_length) + required_insn_length = forced_insn_length; + else if (mips_opts.noautoextend && !mips_opcode_32bit_p (opcode)) + required_insn_length = 2; + else + required_insn_length = 0; + create_insn (insn, opcode); imm_expr.X_op = O_absent; offset_expr.X_op = O_absent; @@ -8014,13 +8128,13 @@ match_mips16_insn (struct mips_cl_insn *insn, const struct mips_opcode *opcode, &value)) { mips16_immed (NULL, 0, relax_char, *offset_reloc, value, - forced_insn_length, &insn->insn_opcode); + required_insn_length, &insn->insn_opcode); offset_expr.X_op = O_absent; *offset_reloc = BFD_RELOC_UNUSED; } else if (relax_char && *offset_reloc != BFD_RELOC_UNUSED) { - if (forced_insn_length == 2) + if (required_insn_length == 2) set_insn_error (0, _("invalid unextended operand value")); forced_insn_length = 4; insn->insn_opcode |= MIPS16_EXTEND; @@ -8067,22 +8181,14 @@ match_mips16_insn (struct mips_cl_insn *insn, const struct mips_opcode *opcode, case 'a': case 'i': *offset_reloc = BFD_RELOC_MIPS16_JMP; - insn->insn_opcode <<= 16; break; } - operand = decode_mips16_operand (c, FALSE); + operand = decode_mips16_operand (c, mips_opcode_32bit_p (opcode)); if (!operand) abort (); - /* '6' is a special case. It is used for BREAK and SDBBP, - whose operands are only meaningful to the software that decodes - them. This means that there is no architectural reason why - they cannot be prefixed by EXTEND, but in practice, - exception handlers will only look at the instruction - itself. We therefore allow '6' to be extended when - disassembling but not when assembling. */ - if (operand->type != OP_PCREL && c != '6') + if (operand->type != OP_PCREL) { ext_operand = decode_mips16_operand (c, TRUE); if (operand != ext_operand) @@ -8232,11 +8338,13 @@ match_mips16_insns (struct mips_cl_insn *insn, const struct mips_opcode *first, { const struct mips_opcode *opcode; bfd_boolean seen_valid_for_isa; + bfd_boolean seen_valid_for_size; /* Search for a match, ignoring alternatives that don't satisfy the current ISA. There are no separate entries for extended forms so we deal with forced_length later. */ seen_valid_for_isa = FALSE; + seen_valid_for_size = FALSE; opcode = first; do { @@ -8244,8 +8352,12 @@ match_mips16_insns (struct mips_cl_insn *insn, const struct mips_opcode *first, if (is_opcode_valid_16 (opcode)) { seen_valid_for_isa = TRUE; - if (match_mips16_insn (insn, opcode, tokens)) - return TRUE; + if (is_size_valid_16 (opcode)) + { + seen_valid_for_size = TRUE; + if (match_mips16_insn (insn, opcode, tokens)) + return TRUE; + } } ++opcode; } @@ -8260,6 +8372,19 @@ match_mips16_insns (struct mips_cl_insn *insn, const struct mips_opcode *first, return TRUE; } + /* Handle the case where we didn't try to match an instruction because + all the alternatives were of the wrong size. */ + if (!seen_valid_for_size) + { + if (forced_insn_length == 2) + set_insn_error + (0, _("unrecognized unextended version of MIPS16 opcode")); + else + set_insn_error + (0, _("unrecognized extended version of MIPS16 opcode")); + return TRUE; + } + return FALSE; } @@ -8274,19 +8399,25 @@ macro_start (void) memset (&mips_macro_warning.insns, 0, sizeof (mips_macro_warning.insns)); mips_macro_warning.delay_slot_p = (mips_opts.noreorder && delayed_branch_p (&history[0])); - switch (history[0].insn_mo->pinfo2 - & (INSN2_BRANCH_DELAY_32BIT | INSN2_BRANCH_DELAY_16BIT)) - { - case INSN2_BRANCH_DELAY_32BIT: - mips_macro_warning.delay_slot_length = 4; - break; - case INSN2_BRANCH_DELAY_16BIT: - mips_macro_warning.delay_slot_length = 2; - break; - default: - mips_macro_warning.delay_slot_length = 0; - break; - } + if (history[0].frag + && history[0].frag->fr_type == rs_machine_dependent + && RELAX_MICROMIPS_P (history[0].frag->fr_subtype) + && RELAX_MICROMIPS_NODS (history[0].frag->fr_subtype)) + mips_macro_warning.delay_slot_length = 0; + else + switch (history[0].insn_mo->pinfo2 + & (INSN2_BRANCH_DELAY_32BIT | INSN2_BRANCH_DELAY_16BIT)) + { + case INSN2_BRANCH_DELAY_32BIT: + mips_macro_warning.delay_slot_length = 4; + break; + case INSN2_BRANCH_DELAY_16BIT: + mips_macro_warning.delay_slot_length = 2; + break; + default: + mips_macro_warning.delay_slot_length = 0; + break; + } mips_macro_warning.first_frag = NULL; } @@ -8634,7 +8765,6 @@ mips16_macro_build (expressionS *ep, const char *name, const char *fmt, break; case '<': - case '>': case '4': case '5': case 'H': @@ -9696,7 +9826,7 @@ small_offset_p (unsigned int range, unsigned int align, unsigned int offbits) * optimizing code generation. * One interesting optimization is when several store macros appear * consecutively that would load AT with the upper half of the same address. - * The ensuing load upper instructions are ommited. This implies some kind + * The ensuing load upper instructions are omitted. This implies some kind * of global optimization. We currently only optimize within a single macro. * For many of the load and store macros if the address is specified as a * constant expression in the first 64k of memory (ie ld $2,0x4000c) we @@ -9759,6 +9889,7 @@ macro (struct mips_cl_insn *ip, char *str) { case M_DABS: dbl = 1; + /* Fall through. */ case M_ABS: /* bgez $a0,1f move v0,$a0 @@ -9908,6 +10039,7 @@ macro (struct mips_cl_insn *ip, char *str) case M_BGEL: likely = 1; + /* Fall through. */ case M_BGE: if (op[1] == 0) macro_build_branch_rs (likely ? M_BGEZL : M_BGEZ, &offset_expr, op[0]); @@ -9933,6 +10065,7 @@ macro (struct mips_cl_insn *ip, char *str) case M_BGTL_I: likely = 1; + /* Fall through. */ case M_BGT_I: /* Check for > max integer. */ if (imm_expr.X_add_number >= GPR_SMAX) @@ -9979,6 +10112,7 @@ macro (struct mips_cl_insn *ip, char *str) case M_BGEUL: likely = 1; + /* Fall through. */ case M_BGEU: if (op[1] == 0) goto do_true; @@ -9996,6 +10130,7 @@ macro (struct mips_cl_insn *ip, char *str) case M_BGTUL_I: likely = 1; + /* Fall through. */ case M_BGTU_I: if (op[0] == 0 || (GPR_SIZE == 32 @@ -10023,6 +10158,7 @@ macro (struct mips_cl_insn *ip, char *str) case M_BGTL: likely = 1; + /* Fall through. */ case M_BGT: if (op[1] == 0) macro_build_branch_rs (likely ? M_BGTZL : M_BGTZ, &offset_expr, op[0]); @@ -10039,6 +10175,7 @@ macro (struct mips_cl_insn *ip, char *str) case M_BGTUL: likely = 1; + /* Fall through. */ case M_BGTU: if (op[1] == 0) macro_build_branch_rsrt (likely ? M_BNEL : M_BNE, @@ -10056,6 +10193,7 @@ macro (struct mips_cl_insn *ip, char *str) case M_BLEL: likely = 1; + /* Fall through. */ case M_BLE: if (op[1] == 0) macro_build_branch_rs (likely ? M_BLEZL : M_BLEZ, &offset_expr, op[0]); @@ -10072,6 +10210,7 @@ macro (struct mips_cl_insn *ip, char *str) case M_BLEL_I: likely = 1; + /* Fall through. */ case M_BLE_I: if (imm_expr.X_add_number >= GPR_SMAX) goto do_true; @@ -10096,6 +10235,7 @@ macro (struct mips_cl_insn *ip, char *str) case M_BLEUL: likely = 1; + /* Fall through. */ case M_BLEU: if (op[1] == 0) macro_build_branch_rsrt (likely ? M_BEQL : M_BEQ, @@ -10113,6 +10253,7 @@ macro (struct mips_cl_insn *ip, char *str) case M_BLEUL_I: likely = 1; + /* Fall through. */ case M_BLEU_I: if (op[0] == 0 || (GPR_SIZE == 32 @@ -10140,6 +10281,7 @@ macro (struct mips_cl_insn *ip, char *str) case M_BLTL: likely = 1; + /* Fall through. */ case M_BLT: if (op[1] == 0) macro_build_branch_rs (likely ? M_BLTZL : M_BLTZ, &offset_expr, op[0]); @@ -10156,6 +10298,7 @@ macro (struct mips_cl_insn *ip, char *str) case M_BLTUL: likely = 1; + /* Fall through. */ case M_BLTU: if (op[1] == 0) goto do_false; @@ -10173,11 +10316,13 @@ macro (struct mips_cl_insn *ip, char *str) case M_DDIV_3: dbl = 1; + /* Fall through. */ case M_DIV_3: s = "mflo"; goto do_div3; case M_DREM_3: dbl = 1; + /* Fall through. */ case M_REM_3: s = "mfhi"; do_div3: @@ -10369,11 +10514,13 @@ macro (struct mips_cl_insn *ip, char *str) case M_DLCA_AB: dbl = 1; + /* Fall through. */ case M_LCA_AB: call = 1; goto do_la; case M_DLA_AB: dbl = 1; + /* Fall through. */ case M_LA_AB: do_la: /* Load the address of a symbol into a register. If breg is not @@ -11703,7 +11850,7 @@ macro (struct mips_cl_insn *ip, char *str) else if (offbits != 16) { /* The offset field is too narrow to be used for a low-part - relocation, so load the whole address into the auxillary + relocation, so load the whole address into the auxiliary register. */ load_address (tempreg, &offset_expr, &used_at); if (breg != 0) @@ -12596,6 +12743,7 @@ macro (struct mips_cl_insn *ip, char *str) case M_DMUL: dbl = 1; + /* Fall through. */ case M_MUL: if (mips_opts.arch == CPU_R5900) macro_build (NULL, dbl ? "dmultu" : "multu", "d,s,t", op[0], op[1], @@ -12609,6 +12757,7 @@ macro (struct mips_cl_insn *ip, char *str) case M_DMUL_I: dbl = 1; + /* Fall through. */ case M_MUL_I: /* The MIPS assembler some times generates shifts and adds. I'm not trying to be that fancy. GCC should do this for us @@ -12621,12 +12770,14 @@ macro (struct mips_cl_insn *ip, char *str) case M_DMULO_I: dbl = 1; + /* Fall through. */ case M_MULO_I: imm = 1; goto do_mulo; case M_DMULO: dbl = 1; + /* Fall through. */ case M_MULO: do_mulo: start_noreorder (); @@ -12658,12 +12809,14 @@ macro (struct mips_cl_insn *ip, char *str) case M_DMULOU_I: dbl = 1; + /* Fall through. */ case M_MULOU_I: imm = 1; goto do_mulou; case M_DMULOU: dbl = 1; + /* Fall through. */ case M_MULOU: do_mulou: start_noreorder (); @@ -13367,11 +13520,13 @@ mips16_macro (struct mips_cl_insn *ip) case M_DDIV_3: dbl = 1; + /* Fall through. */ case M_DIV_3: s = "mflo"; goto do_div3; case M_DREM_3: dbl = 1; + /* Fall through. */ case M_REM_3: s = "mfhi"; do_div3: @@ -13416,6 +13571,7 @@ mips16_macro (struct mips_cl_insn *ip) case M_DMUL: dbl = 1; + /* Fall through. */ case M_MUL: macro_build (NULL, dbl ? "dmultu" : "multu", "x,y", op[1], op[2]); macro_build (NULL, "mflo", "x", op[0]); @@ -13696,13 +13852,14 @@ mips16_ip (char *str, struct mips_cl_insn *insn) char *end, *s, c; struct mips_opcode *first; struct mips_operand_token *tokens; - - forced_insn_length = 0; + unsigned int l; for (s = str; ISLOWER (*s); ++s) ; end = s; c = *end; + + l = 0; switch (c) { case '\0': @@ -13713,26 +13870,27 @@ mips16_ip (char *str, struct mips_cl_insn *insn) break; case '.': - if (s[1] == 't' && s[2] == ' ') + s++; + if (*s == 't') { - forced_insn_length = 2; - s += 3; - break; + l = 2; + s++; } - else if (s[1] == 'e' && s[2] == ' ') + else if (*s == 'e') { - forced_insn_length = 4; - s += 3; - break; + l = 4; + s++; } + if (*s == '\0') + break; + else if (*s++ == ' ') + break; /* Fall through. */ default: set_insn_error (0, _("unrecognized opcode")); return; } - - if (mips_opts.noautoextend && !forced_insn_length) - forced_insn_length = 2; + forced_insn_length = l; *end = 0; first = (struct mips_opcode *) hash_find (mips16_op_hash, str); @@ -17185,6 +17343,21 @@ relaxed_branch_length (fragS *fragp, asection *sec, int update) return length; } +/* Get a FRAG's branch instruction delay slot size, either from the + short-delay-slot bit of a branch-and-link instruction if AL is TRUE, + or SHORT_INSN_SIZE otherwise. */ + +static int +frag_branch_delay_slot_size (fragS *fragp, bfd_boolean al, int short_insn_size) +{ + char *buf = fragp->fr_literal + fragp->fr_fix; + + if (al) + return (read_compressed_insn (buf, 4) & 0x02000000) ? 2 : 4; + else + return short_insn_size; +} + /* Compute the length of a branch sequence, and adjust the RELAX_MICROMIPS_TOOFAR32 bit accordingly. If FRAGP is NULL, the worst-case length is computed, with UPDATE being used to indicate @@ -17194,9 +17367,21 @@ relaxed_branch_length (fragS *fragp, asection *sec, int update) static int relaxed_micromips_32bit_branch_length (fragS *fragp, asection *sec, int update) { + bfd_boolean insn32 = TRUE; + bfd_boolean nods = TRUE; + bfd_boolean al = TRUE; + int short_insn_size; bfd_boolean toofar; int length; + if (fragp) + { + insn32 = RELAX_MICROMIPS_INSN32 (fragp->fr_subtype); + nods = RELAX_MICROMIPS_NODS (fragp->fr_subtype); + al = RELAX_MICROMIPS_LINK (fragp->fr_subtype); + } + short_insn_size = insn32 ? 4 : 2; + if (fragp && S_IS_DEFINED (fragp->fr_symbol) && !S_IS_WEAK (fragp->fr_symbol) @@ -17233,19 +17418,15 @@ relaxed_micromips_32bit_branch_length (fragS *fragp, asection *sec, int update) { bfd_boolean compact_known = fragp != NULL; bfd_boolean compact = FALSE; - bfd_boolean insn32 = TRUE; bfd_boolean uncond; - int short_insn_size; if (fragp) { compact = RELAX_MICROMIPS_COMPACT (fragp->fr_subtype); uncond = RELAX_MICROMIPS_UNCOND (fragp->fr_subtype); - insn32 = RELAX_MICROMIPS_INSN32 (fragp->fr_subtype); } else uncond = update < 0; - short_insn_size = insn32 ? 4 : 2; /* If label is out of range, we turn branch
: @@ -17275,6 +17456,13 @@ relaxed_micromips_32bit_branch_length (fragS *fragp, asection *sec, int update) if (mips_pic != NO_PIC) length += 4 + short_insn_size; + /* Add an extra nop if the jump has no compact form and we need + to fill the delay slot. */ + if ((mips_pic == NO_PIC || al) && nods) + length += (fragp + ? frag_branch_delay_slot_size (fragp, al, short_insn_size) + : short_insn_size); + /* If branch
is conditional, we prepend negated branch : 0f # 4 bytes @@ -17283,6 +17471,12 @@ relaxed_micromips_32bit_branch_length (fragS *fragp, asection *sec, int update) if (!uncond) length += (compact_known && compact) ? 4 : 4 + short_insn_size; } + else if (nods) + { + /* Add an extra nop to fill the delay slot. */ + gas_assert (fragp); + length += frag_branch_delay_slot_size (fragp, al, short_insn_size); + } return length; } @@ -17847,6 +18041,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp) char *buf = fragp->fr_literal + fragp->fr_fix; bfd_boolean compact = RELAX_MICROMIPS_COMPACT (fragp->fr_subtype); bfd_boolean insn32 = RELAX_MICROMIPS_INSN32 (fragp->fr_subtype); + bfd_boolean nods = RELAX_MICROMIPS_NODS (fragp->fr_subtype); bfd_boolean al = RELAX_MICROMIPS_LINK (fragp->fr_subtype); int type = RELAX_MICROMIPS_TYPE (fragp->fr_subtype); bfd_boolean short_ds; @@ -17898,7 +18093,22 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp) fixp->fx_line = fragp->fr_line; if (type == 0) - return; + { + insn = read_compressed_insn (buf, 4); + buf += 4; + + if (nods) + { + /* Check the short-delay-slot bit. */ + if (!al || (insn & 0x02000000) != 0) + buf = write_compressed_insn (buf, 0x0c00, 2); + else + buf = write_compressed_insn (buf, 0x00000000, 4); + } + + gas_assert (buf == fragp->fr_literal + fragp->fr_fix); + return; + } } /* Relax 16-bit branches to 32-bit branches. */ @@ -17925,6 +18135,8 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp) || !RELAX_MICROMIPS_TOOFAR32 (fragp->fr_subtype)) { buf = write_compressed_insn (buf, insn, 4); + if (nods) + buf = write_compressed_insn (buf, 0x0c00, 2); gas_assert (buf == fragp->fr_literal + fragp->fr_fix); return; } @@ -17937,7 +18149,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp) _("relaxed out-of-range branch into a jump")); /* Set the short-delay-slot bit. */ - short_ds = al && (insn & 0x02000000) != 0; + short_ds = !al || (insn & 0x02000000) != 0; if (!RELAX_MICROMIPS_UNCOND (fragp->fr_subtype)) { @@ -18007,7 +18219,8 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp) if (mips_pic == NO_PIC) { - unsigned long jal = short_ds ? 0x74000000 : 0xf4000000; /* jal/s */ + unsigned long jal = (short_ds || nods + ? 0x74000000 : 0xf4000000); /* jal/s */ /* j/jal/jals R_MICROMIPS_26_S1 */ insn = al ? jal : 0xd4000000; @@ -18019,7 +18232,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp) buf = write_compressed_insn (buf, insn, 4); - if (compact) + if (compact || nods) { /* nop */ if (insn32) @@ -18068,7 +18281,7 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp) buf = write_compressed_insn (buf, insn, 4); - if (compact) + if (compact || nods) /* nop */ buf = write_compressed_insn (buf, 0x00000000, 4); } @@ -18076,12 +18289,20 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp) { /* jr/jrc/jalr/jalrs $at */ unsigned long jalr = short_ds ? 0x45e0 : 0x45c0; /* jalr/s */ - unsigned long jr = compact ? 0x45a0 : 0x4580; /* jr/c */ + unsigned long jr = compact || nods ? 0x45a0 : 0x4580; /* jr/c */ insn = al ? jalr : jr; insn |= at << MICROMIPSOP_SH_MJ; buf = write_compressed_insn (buf, insn, 2); + if (al && nods) + { + /* nop */ + if (short_ds) + buf = write_compressed_insn (buf, 0x0c00, 2); + else + buf = write_compressed_insn (buf, 0x00000000, 4); + } } } @@ -18192,10 +18413,10 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp) _("unsupported relocation")); break; } - if (reloc != BFD_RELOC_NONE) + if (reloc == BFD_RELOC_NONE) + ; + else if (ext) { - gas_assert (ext); - exp.X_op = O_symbol; exp.X_add_symbol = fragp->fr_symbol; exp.X_add_number = fragp->fr_offset; @@ -18210,6 +18431,9 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT asec, fragS *fragp) in 2 octets. */ fixp->fx_no_overflow = 1; } + else + as_bad_where (fragp->fr_file, fragp->fr_line, + _("invalid unextended operand value")); } else mips16_immed (fragp->fr_file, fragp->fr_line, type,