X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gas%2Fconfig%2Ftc-mips.c;h=d19a14987c25f1e77b7dc65f9a45d1dbc2a6ab08;hb=ad3fea084db196784e00a78cec90acf33897441c;hp=673c13885d9fa66a983693ea39531cb7e2822320;hpb=4e2a74a8413a6389d557bf54bc8a4a85004322d5;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/config/tc-mips.c b/gas/config/tc-mips.c index 673c13885d..d19a14987c 100644 --- a/gas/config/tc-mips.c +++ b/gas/config/tc-mips.c @@ -274,17 +274,23 @@ static int file_ase_mdmx; command line (e.g., by -march). */ static int file_ase_smartmips; -#define ISA_SUPPORT_SMARTMIPS (mips_opts.isa == ISA_MIPS32 \ - || mips_opts.isa == ISA_MIPS32R2) +#define ISA_SUPPORTS_SMARTMIPS (mips_opts.isa == ISA_MIPS32 \ + || mips_opts.isa == ISA_MIPS32R2) /* True if -mdsp was passed or implied by arguments passed on the command line (e.g., by -march). */ static int file_ase_dsp; +#define ISA_SUPPORTS_DSP_ASE (mips_opts.isa == ISA_MIPS32R2 \ + || mips_opts.isa == ISA_MIPS64R2) + /* True if -mmt was passed or implied by arguments passed on the command line (e.g., by -march). */ static int file_ase_mt; +#define ISA_SUPPORTS_MT_ASE (mips_opts.isa == ISA_MIPS32R2 \ + || mips_opts.isa == ISA_MIPS64R2) + /* The argument of the -march= flag. The architecture we are assembling. */ static int file_mips_arch = CPU_UNKNOWN; static const char *mips_arch_string; @@ -301,42 +307,61 @@ static int mips_32bitmode = 0; #define ABI_NEEDS_32BIT_REGS(ABI) ((ABI) == O32_ABI) /* Likewise 64-bit registers. */ -#define ABI_NEEDS_64BIT_REGS(ABI) \ - ((ABI) == N32_ABI \ - || (ABI) == N64_ABI \ +#define ABI_NEEDS_64BIT_REGS(ABI) \ + ((ABI) == N32_ABI \ + || (ABI) == N64_ABI \ || (ABI) == O64_ABI) -/* Return true if ISA supports 64 bit gp register instructions. */ -#define ISA_HAS_64BIT_REGS(ISA) ( \ - (ISA) == ISA_MIPS3 \ - || (ISA) == ISA_MIPS4 \ - || (ISA) == ISA_MIPS5 \ - || (ISA) == ISA_MIPS64 \ - || (ISA) == ISA_MIPS64R2 \ - ) +/* Return true if ISA supports 64 bit wide gp registers. */ +#define ISA_HAS_64BIT_REGS(ISA) \ + ((ISA) == ISA_MIPS3 \ + || (ISA) == ISA_MIPS4 \ + || (ISA) == ISA_MIPS5 \ + || (ISA) == ISA_MIPS64 \ + || (ISA) == ISA_MIPS64R2) + +/* Return true if ISA supports 64 bit wide float registers. */ +#define ISA_HAS_64BIT_FPRS(ISA) \ + ((ISA) == ISA_MIPS3 \ + || (ISA) == ISA_MIPS4 \ + || (ISA) == ISA_MIPS5 \ + || (ISA) == ISA_MIPS32R2 \ + || (ISA) == ISA_MIPS64 \ + || (ISA) == ISA_MIPS64R2) /* Return true if ISA supports 64-bit right rotate (dror et al.) instructions. */ -#define ISA_HAS_DROR(ISA) ( \ - (ISA) == ISA_MIPS64R2 \ - ) +#define ISA_HAS_DROR(ISA) \ + ((ISA) == ISA_MIPS64R2) /* Return true if ISA supports 32-bit right rotate (ror et al.) instructions. */ -#define ISA_HAS_ROR(ISA) ( \ - (ISA) == ISA_MIPS32R2 \ - || (ISA) == ISA_MIPS64R2 \ - || mips_opts.ase_smartmips \ - ) +#define ISA_HAS_ROR(ISA) \ + ((ISA) == ISA_MIPS32R2 \ + || (ISA) == ISA_MIPS64R2 \ + || mips_opts.ase_smartmips) + +/* Return true if ISA supports single-precision floats in odd registers. */ +#define ISA_HAS_ODD_SINGLE_FPR(ISA) \ + ((ISA) == ISA_MIPS32 \ + || (ISA) == ISA_MIPS32R2 \ + || (ISA) == ISA_MIPS64 \ + || (ISA) == ISA_MIPS64R2) + +/* Return true if ISA supports move to/from high part of a 64-bit + floating-point register. */ +#define ISA_HAS_MXHC1(ISA) \ + ((ISA) == ISA_MIPS32R2 \ + || (ISA) == ISA_MIPS64R2) #define HAVE_32BIT_GPRS \ - (mips_opts.gp32 || ! ISA_HAS_64BIT_REGS (mips_opts.isa)) + (mips_opts.gp32 || !ISA_HAS_64BIT_REGS (mips_opts.isa)) #define HAVE_32BIT_FPRS \ - (mips_opts.fp32 || ! ISA_HAS_64BIT_REGS (mips_opts.isa)) + (mips_opts.fp32 || !ISA_HAS_64BIT_FPRS (mips_opts.isa)) -#define HAVE_64BIT_GPRS (! HAVE_32BIT_GPRS) -#define HAVE_64BIT_FPRS (! HAVE_32BIT_FPRS) +#define HAVE_64BIT_GPRS (!HAVE_32BIT_GPRS) +#define HAVE_64BIT_FPRS (!HAVE_32BIT_FPRS) #define HAVE_NEWABI (mips_abi == N32_ABI || mips_abi == N64_ABI) @@ -1027,11 +1052,18 @@ static int validate_mips_insn (const struct mips_opcode *); struct mips_cpu_info { const char *name; /* CPU or ISA name. */ - int is_isa; /* Is this an ISA? (If 0, a CPU.) */ + int flags; /* ASEs available, or ISA flag. */ int isa; /* ISA level. */ int cpu; /* CPU number (default CPU if ISA). */ }; +#define MIPS_CPU_IS_ISA 0x0001 /* Is this an ISA? (If 0, a CPU.) */ +#define MIPS_CPU_ASE_SMARTMIPS 0x0002 /* CPU implements SmartMIPS ASE */ +#define MIPS_CPU_ASE_DSP 0x0004 /* CPU implements DSP ASE */ +#define MIPS_CPU_ASE_MT 0x0008 /* CPU implements MT ASE */ +#define MIPS_CPU_ASE_MIPS3D 0x0010 /* CPU implements MIPS-3D ASE */ +#define MIPS_CPU_ASE_MDMX 0x0020 /* CPU implements MDMX ASE */ + static const struct mips_cpu_info *mips_parse_cpu (const char *, const char *); static const struct mips_cpu_info *mips_cpu_info_from_isa (int); static const struct mips_cpu_info *mips_cpu_info_from_arch (int); @@ -1402,8 +1434,297 @@ init_vr4120_conflicts (void) #undef CONFLICT } -/* This function is called once, at assembler startup time. It should - set up all the tables, etc. that the MD part of the assembler will need. */ +struct regname { + const char *name; + unsigned int num; +}; + +#define RTYPE_MASK 0x1ff00 +#define RTYPE_NUM 0x00100 +#define RTYPE_FPU 0x00200 +#define RTYPE_FCC 0x00400 +#define RTYPE_VEC 0x00800 +#define RTYPE_GP 0x01000 +#define RTYPE_CP0 0x02000 +#define RTYPE_PC 0x04000 +#define RTYPE_ACC 0x08000 +#define RTYPE_CCC 0x10000 +#define RNUM_MASK 0x000ff +#define RWARN 0x80000 + +#define GENERIC_REGISTER_NUMBERS \ + {"$0", RTYPE_NUM | 0}, \ + {"$1", RTYPE_NUM | 1}, \ + {"$2", RTYPE_NUM | 2}, \ + {"$3", RTYPE_NUM | 3}, \ + {"$4", RTYPE_NUM | 4}, \ + {"$5", RTYPE_NUM | 5}, \ + {"$6", RTYPE_NUM | 6}, \ + {"$7", RTYPE_NUM | 7}, \ + {"$8", RTYPE_NUM | 8}, \ + {"$9", RTYPE_NUM | 9}, \ + {"$10", RTYPE_NUM | 10}, \ + {"$11", RTYPE_NUM | 11}, \ + {"$12", RTYPE_NUM | 12}, \ + {"$13", RTYPE_NUM | 13}, \ + {"$14", RTYPE_NUM | 14}, \ + {"$15", RTYPE_NUM | 15}, \ + {"$16", RTYPE_NUM | 16}, \ + {"$17", RTYPE_NUM | 17}, \ + {"$18", RTYPE_NUM | 18}, \ + {"$19", RTYPE_NUM | 19}, \ + {"$20", RTYPE_NUM | 20}, \ + {"$21", RTYPE_NUM | 21}, \ + {"$22", RTYPE_NUM | 22}, \ + {"$23", RTYPE_NUM | 23}, \ + {"$24", RTYPE_NUM | 24}, \ + {"$25", RTYPE_NUM | 25}, \ + {"$26", RTYPE_NUM | 26}, \ + {"$27", RTYPE_NUM | 27}, \ + {"$28", RTYPE_NUM | 28}, \ + {"$29", RTYPE_NUM | 29}, \ + {"$30", RTYPE_NUM | 30}, \ + {"$31", RTYPE_NUM | 31} + +#define FPU_REGISTER_NAMES \ + {"$f0", RTYPE_FPU | 0}, \ + {"$f1", RTYPE_FPU | 1}, \ + {"$f2", RTYPE_FPU | 2}, \ + {"$f3", RTYPE_FPU | 3}, \ + {"$f4", RTYPE_FPU | 4}, \ + {"$f5", RTYPE_FPU | 5}, \ + {"$f6", RTYPE_FPU | 6}, \ + {"$f7", RTYPE_FPU | 7}, \ + {"$f8", RTYPE_FPU | 8}, \ + {"$f9", RTYPE_FPU | 9}, \ + {"$f10", RTYPE_FPU | 10}, \ + {"$f11", RTYPE_FPU | 11}, \ + {"$f12", RTYPE_FPU | 12}, \ + {"$f13", RTYPE_FPU | 13}, \ + {"$f14", RTYPE_FPU | 14}, \ + {"$f15", RTYPE_FPU | 15}, \ + {"$f16", RTYPE_FPU | 16}, \ + {"$f17", RTYPE_FPU | 17}, \ + {"$f18", RTYPE_FPU | 18}, \ + {"$f19", RTYPE_FPU | 19}, \ + {"$f20", RTYPE_FPU | 20}, \ + {"$f21", RTYPE_FPU | 21}, \ + {"$f22", RTYPE_FPU | 22}, \ + {"$f23", RTYPE_FPU | 23}, \ + {"$f24", RTYPE_FPU | 24}, \ + {"$f25", RTYPE_FPU | 25}, \ + {"$f26", RTYPE_FPU | 26}, \ + {"$f27", RTYPE_FPU | 27}, \ + {"$f28", RTYPE_FPU | 28}, \ + {"$f29", RTYPE_FPU | 29}, \ + {"$f30", RTYPE_FPU | 30}, \ + {"$f31", RTYPE_FPU | 31} + +#define FPU_CONDITION_CODE_NAMES \ + {"$fcc0", RTYPE_FCC | 0}, \ + {"$fcc1", RTYPE_FCC | 1}, \ + {"$fcc2", RTYPE_FCC | 2}, \ + {"$fcc3", RTYPE_FCC | 3}, \ + {"$fcc4", RTYPE_FCC | 4}, \ + {"$fcc5", RTYPE_FCC | 5}, \ + {"$fcc6", RTYPE_FCC | 6}, \ + {"$fcc7", RTYPE_FCC | 7} + +#define COPROC_CONDITION_CODE_NAMES \ + {"$cc0", RTYPE_FCC | RTYPE_CCC | 0}, \ + {"$cc1", RTYPE_FCC | RTYPE_CCC | 1}, \ + {"$cc2", RTYPE_FCC | RTYPE_CCC | 2}, \ + {"$cc3", RTYPE_FCC | RTYPE_CCC | 3}, \ + {"$cc4", RTYPE_FCC | RTYPE_CCC | 4}, \ + {"$cc5", RTYPE_FCC | RTYPE_CCC | 5}, \ + {"$cc6", RTYPE_FCC | RTYPE_CCC | 6}, \ + {"$cc7", RTYPE_FCC | RTYPE_CCC | 7} + +#define N32N64_SYMBOLIC_REGISTER_NAMES \ + {"$a4", RTYPE_GP | 8}, \ + {"$a5", RTYPE_GP | 9}, \ + {"$a6", RTYPE_GP | 10}, \ + {"$a7", RTYPE_GP | 11}, \ + {"$ta0", RTYPE_GP | 8}, /* alias for $a4 */ \ + {"$ta1", RTYPE_GP | 9}, /* alias for $a5 */ \ + {"$ta2", RTYPE_GP | 10}, /* alias for $a6 */ \ + {"$ta3", RTYPE_GP | 11}, /* alias for $a7 */ \ + {"$t0", RTYPE_GP | 12}, \ + {"$t1", RTYPE_GP | 13}, \ + {"$t2", RTYPE_GP | 14}, \ + {"$t3", RTYPE_GP | 15} + +#define O32_SYMBOLIC_REGISTER_NAMES \ + {"$t0", RTYPE_GP | 8}, \ + {"$t1", RTYPE_GP | 9}, \ + {"$t2", RTYPE_GP | 10}, \ + {"$t3", RTYPE_GP | 11}, \ + {"$t4", RTYPE_GP | 12}, \ + {"$t5", RTYPE_GP | 13}, \ + {"$t6", RTYPE_GP | 14}, \ + {"$t7", RTYPE_GP | 15}, \ + {"$ta0", RTYPE_GP | 12}, /* alias for $t4 */ \ + {"$ta1", RTYPE_GP | 13}, /* alias for $t5 */ \ + {"$ta2", RTYPE_GP | 14}, /* alias for $t6 */ \ + {"$ta3", RTYPE_GP | 15} /* alias for $t7 */ + +/* Remaining symbolic register names */ +#define SYMBOLIC_REGISTER_NAMES \ + {"$zero", RTYPE_GP | 0}, \ + {"$at", RTYPE_GP | 1}, \ + {"$AT", RTYPE_GP | 1}, \ + {"$v0", RTYPE_GP | 2}, \ + {"$v1", RTYPE_GP | 3}, \ + {"$a0", RTYPE_GP | 4}, \ + {"$a1", RTYPE_GP | 5}, \ + {"$a2", RTYPE_GP | 6}, \ + {"$a3", RTYPE_GP | 7}, \ + {"$s0", RTYPE_GP | 16}, \ + {"$s1", RTYPE_GP | 17}, \ + {"$s2", RTYPE_GP | 18}, \ + {"$s3", RTYPE_GP | 19}, \ + {"$s4", RTYPE_GP | 20}, \ + {"$s5", RTYPE_GP | 21}, \ + {"$s6", RTYPE_GP | 22}, \ + {"$s7", RTYPE_GP | 23}, \ + {"$t8", RTYPE_GP | 24}, \ + {"$t9", RTYPE_GP | 25}, \ + {"$k0", RTYPE_GP | 26}, \ + {"$kt0", RTYPE_GP | 26}, \ + {"$k1", RTYPE_GP | 27}, \ + {"$kt1", RTYPE_GP | 27}, \ + {"$gp", RTYPE_GP | 28}, \ + {"$sp", RTYPE_GP | 29}, \ + {"$s8", RTYPE_GP | 30}, \ + {"$fp", RTYPE_GP | 30}, \ + {"$ra", RTYPE_GP | 31} + +#define MIPS16_SPECIAL_REGISTER_NAMES \ + {"$pc", RTYPE_PC | 0} + +#define MDMX_VECTOR_REGISTER_NAMES \ + /* {"$v0", RTYPE_VEC | 0}, clash with REG 2 above */ \ + /* {"$v1", RTYPE_VEC | 1}, clash with REG 3 above */ \ + {"$v2", RTYPE_VEC | 2}, \ + {"$v3", RTYPE_VEC | 3}, \ + {"$v4", RTYPE_VEC | 4}, \ + {"$v5", RTYPE_VEC | 5}, \ + {"$v6", RTYPE_VEC | 6}, \ + {"$v7", RTYPE_VEC | 7}, \ + {"$v8", RTYPE_VEC | 8}, \ + {"$v9", RTYPE_VEC | 9}, \ + {"$v10", RTYPE_VEC | 10}, \ + {"$v11", RTYPE_VEC | 11}, \ + {"$v12", RTYPE_VEC | 12}, \ + {"$v13", RTYPE_VEC | 13}, \ + {"$v14", RTYPE_VEC | 14}, \ + {"$v15", RTYPE_VEC | 15}, \ + {"$v16", RTYPE_VEC | 16}, \ + {"$v17", RTYPE_VEC | 17}, \ + {"$v18", RTYPE_VEC | 18}, \ + {"$v19", RTYPE_VEC | 19}, \ + {"$v20", RTYPE_VEC | 20}, \ + {"$v21", RTYPE_VEC | 21}, \ + {"$v22", RTYPE_VEC | 22}, \ + {"$v23", RTYPE_VEC | 23}, \ + {"$v24", RTYPE_VEC | 24}, \ + {"$v25", RTYPE_VEC | 25}, \ + {"$v26", RTYPE_VEC | 26}, \ + {"$v27", RTYPE_VEC | 27}, \ + {"$v28", RTYPE_VEC | 28}, \ + {"$v29", RTYPE_VEC | 29}, \ + {"$v30", RTYPE_VEC | 30}, \ + {"$v31", RTYPE_VEC | 31} + +#define MIPS_DSP_ACCUMULATOR_NAMES \ + {"$ac0", RTYPE_ACC | 0}, \ + {"$ac1", RTYPE_ACC | 1}, \ + {"$ac2", RTYPE_ACC | 2}, \ + {"$ac3", RTYPE_ACC | 3} + +static const struct regname reg_names[] = { + GENERIC_REGISTER_NUMBERS, + FPU_REGISTER_NAMES, + FPU_CONDITION_CODE_NAMES, + COPROC_CONDITION_CODE_NAMES, + + /* The $txx registers depends on the abi, + these will be added later into the symbol table from + one of the tables below once mips_abi is set after + parsing of arguments from the command line. */ + SYMBOLIC_REGISTER_NAMES, + + MIPS16_SPECIAL_REGISTER_NAMES, + MDMX_VECTOR_REGISTER_NAMES, + MIPS_DSP_ACCUMULATOR_NAMES, + {0, 0} +}; + +static const struct regname reg_names_o32[] = { + O32_SYMBOLIC_REGISTER_NAMES, + {0, 0} +}; + +static const struct regname reg_names_n32n64[] = { + N32N64_SYMBOLIC_REGISTER_NAMES, + {0, 0} +}; + +static int +reg_lookup (char **s, unsigned int types, unsigned int *regnop) +{ + symbolS *symbolP; + char *e; + char save_c; + int reg = -1; + + /* Find end of name. */ + e = *s; + if (is_name_beginner (*e)) + ++e; + while (is_part_of_name (*e)) + ++e; + + /* Terminate name. */ + save_c = *e; + *e = '\0'; + + /* Look for a register symbol. */ + if ((symbolP = symbol_find (*s)) && S_GET_SEGMENT (symbolP) == reg_section) + { + int r = S_GET_VALUE (symbolP); + if (r & types) + reg = r & RNUM_MASK; + else if ((types & RTYPE_VEC) && (r & ~1) == (RTYPE_GP | 2)) + /* Convert GP reg $v0/1 to MDMX reg $v0/1! */ + reg = (r & RNUM_MASK) - 2; + } + /* Else see if this is a register defined in an itbl entry. */ + else if ((types & RTYPE_GP) && itbl_have_entries) + { + char *n = *s; + unsigned long r; + + if (*n == '$') + ++n; + if (itbl_get_reg_val (n, &r)) + reg = r & RNUM_MASK; + } + + /* Advance to next token if a register was recognised. */ + if (reg >= 0) + *s = e; + else if (types & RWARN) + as_warn ("Unrecognized register name `%s'", *s); + + *e = save_c; + if (regnop) + *regnop = reg; + return reg >= 0; +} + +/* This function is called once, at assembler startup time. It should set up + all the tables, etc. that the MD part of the assembler will need. */ void md_begin (void) @@ -1490,46 +1811,20 @@ md_begin (void) /* We add all the general register names to the symbol table. This helps us detect invalid uses of them. */ - for (i = 0; i < 32; i++) - { - char buf[5]; - - sprintf (buf, "$%d", i); - symbol_table_insert (symbol_new (buf, reg_section, i, + for (i = 0; reg_names[i].name; i++) + symbol_table_insert (symbol_new (reg_names[i].name, reg_section, + reg_names[i].num, // & RNUM_MASK, + &zero_address_frag)); + if (HAVE_NEWABI) + for (i = 0; reg_names_n32n64[i].name; i++) + symbol_table_insert (symbol_new (reg_names_n32n64[i].name, reg_section, + reg_names_n32n64[i].num, // & RNUM_MASK, &zero_address_frag)); - } - symbol_table_insert (symbol_new ("$ra", reg_section, RA, - &zero_address_frag)); - symbol_table_insert (symbol_new ("$fp", reg_section, FP, - &zero_address_frag)); - symbol_table_insert (symbol_new ("$sp", reg_section, SP, - &zero_address_frag)); - symbol_table_insert (symbol_new ("$gp", reg_section, GP, - &zero_address_frag)); - symbol_table_insert (symbol_new ("$at", reg_section, AT, - &zero_address_frag)); - symbol_table_insert (symbol_new ("$kt0", reg_section, KT0, - &zero_address_frag)); - symbol_table_insert (symbol_new ("$kt1", reg_section, KT1, - &zero_address_frag)); - symbol_table_insert (symbol_new ("$zero", reg_section, ZERO, - &zero_address_frag)); - symbol_table_insert (symbol_new ("$pc", reg_section, -1, - &zero_address_frag)); - - /* If we don't add these register names to the symbol table, they - may end up being added as regular symbols by operand(), and then - make it to the object file as undefined in case they're not - regarded as local symbols. They're local in o32, since `$' is a - local symbol prefix, but not in n32 or n64. */ - for (i = 0; i < 8; i++) - { - char buf[6]; - - sprintf (buf, "$fcc%i", i); - symbol_table_insert (symbol_new (buf, reg_section, -1, + else + for (i = 0; reg_names_o32[i].name; i++) + symbol_table_insert (symbol_new (reg_names_o32[i].name, reg_section, + reg_names_o32[i].num, // & RNUM_MASK, &zero_address_frag)); - } mips_no_prev_insn (); @@ -1544,6 +1839,7 @@ md_begin (void) bfd_set_gp_size (stdoutput, g_switch_value); +#ifdef OBJ_ELF if (OUTPUT_FLAVOR == bfd_target_elf_flavour) { /* On a native system other than VxWorks, sections must be aligned @@ -1582,9 +1878,7 @@ md_begin (void) bfd_set_section_flags (stdoutput, sec, flags); bfd_set_section_alignment (stdoutput, sec, HAVE_NEWABI ? 3 : 2); -#ifdef OBJ_ELF mips_regmask_frag = frag_more (sizeof (Elf32_External_RegInfo)); -#endif } else { @@ -1594,7 +1888,6 @@ md_begin (void) bfd_set_section_flags (stdoutput, sec, flags); bfd_set_section_alignment (stdoutput, sec, 3); -#ifdef OBJ_ELF /* Set up the option header. */ { Elf_Internal_Options opthdr; @@ -1611,7 +1904,6 @@ md_begin (void) mips_regmask_frag = frag_more (sizeof (Elf64_External_RegInfo)); } -#endif } if (ECOFF_DEBUGGING) @@ -1621,7 +1913,6 @@ md_begin (void) SEC_HAS_CONTENTS | SEC_READONLY); (void) bfd_set_section_alignment (stdoutput, sec, 2); } -#ifdef OBJ_ELF else if (OUTPUT_FLAVOR == bfd_target_elf_flavour && mips_flag_pdr) { pdr_seg = subseg_new (".pdr", (subsegT) 0); @@ -1630,11 +1921,11 @@ md_begin (void) | SEC_DEBUGGING); (void) bfd_set_section_alignment (stdoutput, pdr_seg, 2); } -#endif subseg_set (seg, subseg); } } +#endif /* OBJ_ELF */ if (! ECOFF_DEBUGGING) md_obj_begin (); @@ -2415,9 +2706,6 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr, if ((address_expr->X_add_number & 3) != 0) as_bad (_("jump to misaligned address (0x%lx)"), (unsigned long) address_expr->X_add_number); - if (address_expr->X_add_number & ~0xfffffff) - as_warn (_("jump address range overflow (0x%lx)"), - (unsigned long) address_expr->X_add_number); ip->insn_opcode |= (address_expr->X_add_number >> 2) & 0x3ffffff; break; @@ -2425,9 +2713,6 @@ append_insn (struct mips_cl_insn *ip, expressionS *address_expr, if ((address_expr->X_add_number & 3) != 0) as_bad (_("jump to misaligned address (0x%lx)"), (unsigned long) address_expr->X_add_number); - if (address_expr->X_add_number & ~0xfffffff) - as_warn (_("jump address range overflow (0x%lx)"), - (unsigned long) address_expr->X_add_number); ip->insn_opcode |= (((address_expr->X_add_number & 0x7c0000) << 3) | ((address_expr->X_add_number & 0xf800000) >> 7) @@ -3021,7 +3306,7 @@ macro_build (expressionS *ep, const char *name, const char *fmt, ...) || mo->pinfo == INSN_MACRO || !OPCODE_IS_MEMBER (mo, (mips_opts.isa - | (file_ase_mips16 ? INSN_MIPS16 : 0) + | (mips_opts.mips16 ? INSN_MIPS16 : 0) | (mips_opts.ase_smartmips ? INSN_SMARTMIPS : 0)), mips_opts.arch) || (mips_opts.arch == CPU_R4650 && (mo->pinfo & FP_D) != 0)) @@ -7958,6 +8243,46 @@ static const struct mips_immed mips_immed[] = { { 0,0,0,0 } }; +/* Check whether an odd floating-point register is allowed. */ +static int +mips_oddfpreg_ok (const struct mips_opcode *insn, int argnum) +{ + const char *s = insn->name; + + if (insn->pinfo == INSN_MACRO) + /* Let a macro pass, we'll catch it later when it is expanded. */ + return 1; + + if (ISA_HAS_ODD_SINGLE_FPR (mips_opts.isa)) + { + /* Allow odd registers for single-precision ops. */ + switch (insn->pinfo & (FP_S | FP_D)) + { + case FP_S: + case 0: + return 1; /* both single precision - ok */ + case FP_D: + return 0; /* both double precision - fail */ + default: + break; + } + + /* Cvt.w.x and cvt.x.w allow an odd register for a 'w' or 's' operand. */ + s = strchr (insn->name, '.'); + if (argnum == 2) + s = s != NULL ? strchr (s + 1, '.') : NULL; + return (s != NULL && (s[1] == 'w' || s[1] == 's')); + } + + /* Single-precision coprocessor loads and moves are OK too. */ + if ((insn->pinfo & FP_S) + && (insn->pinfo & (INSN_COPROC_MEMORY_DELAY | INSN_STORE_MEMORY + | INSN_LOAD_COPROC_DELAY | INSN_COPROC_MOVE_DELAY))) + return 1; + + return 0; +} + /* This routine assembles an instruction into its binary format. As a side effect, it sets one of the global variables imm_reloc or offset_reloc to the type of relocation to do if one of the operands @@ -7978,6 +8303,8 @@ mips_ip (char *str, struct mips_cl_insn *ip) char *s_reset; char save_c = 0; offsetT min_range, max_range; + int argnum; + unsigned int rtype; insn_error = NULL; @@ -8038,6 +8365,9 @@ mips_ip (char *str, struct mips_cl_insn *ip) if (OPCODE_IS_MEMBER (insn, (mips_opts.isa + /* We don't check for mips_opts.mips16 here since + we want to allow jalx if -mips16 was specified + on the command line. */ | (file_ase_mips16 ? INSN_MIPS16 : 0) | (mips_opts.ase_mdmx ? INSN_MDMX : 0) | (mips_opts.ase_dsp ? INSN_DSP : 0) @@ -8082,6 +8412,7 @@ mips_ip (char *str, struct mips_cl_insn *ip) create_insn (ip, insn); insn_error = NULL; + argnum = 1; for (args = insn->args;; ++args) { int is_mdmx; @@ -8498,11 +8829,11 @@ do_msbd: s = expr_end; continue; - case 'T': /* Coprocessor register */ + case 'T': /* Coprocessor register. */ /* +T is for disassembly only; never match. */ break; - case 't': /* Coprocessor register number */ + case 't': /* Coprocessor register number. */ if (s[0] == '$' && ISDIGIT (s[1])) { ++s; @@ -8636,7 +8967,7 @@ do_msbd: s = expr_end; continue; - case 'P': /* Performance register */ + case 'P': /* Performance register. */ my_getExpression (&imm_expr, s); check_absolute_expr (ip, &imm_expr); if (imm_expr.X_add_number != 0 && imm_expr.X_add_number != 1) @@ -8647,6 +8978,20 @@ do_msbd: s = expr_end; continue; + case 'G': /* Coprocessor destination register. */ + if (((ip->insn_opcode >> OP_SH_OP) & OP_MASK_OP) == OP_OP_COP0) + ok = reg_lookup (&s, RTYPE_NUM | RTYPE_CP0, ®no); + else + ok = reg_lookup (&s, RTYPE_NUM | RTYPE_GP, ®no); + ip->insn_opcode |= regno << OP_SH_RD; + if (ok) + { + lastregno = regno; + continue; + } + else + break; + case 'b': /* base register */ case 'd': /* destination register */ case 's': /* source register */ @@ -8655,106 +9000,22 @@ do_msbd: case 'v': /* both dest and source */ case 'w': /* both dest and target */ case 'E': /* coprocessor target register */ - case 'G': /* coprocessor destination register */ case 'K': /* 'rdhwr' destination register */ case 'x': /* ignore register name */ case 'z': /* must be zero register */ case 'U': /* destination register (clo/clz). */ case 'g': /* coprocessor destination register */ - s_reset = s; - if (s[0] == '$') + s_reset = s; + if (*args == 'E' || *args == 'K') + ok = reg_lookup (&s, RTYPE_NUM, ®no); + else + { + ok = reg_lookup (&s, RTYPE_NUM | RTYPE_GP, ®no); + if (regno == AT && ! mips_opts.noat) + as_warn ("Used $at without \".set noat\""); + } + if (ok) { - if (ISDIGIT (s[1])) - { - ++s; - regno = 0; - do - { - regno *= 10; - regno += *s - '0'; - ++s; - } - while (ISDIGIT (*s)); - if (regno > 31) - as_bad (_("Invalid register number (%d)"), regno); - } - else if (*args == 'E' || *args == 'G' || *args == 'K') - goto notreg; - else - { - if (s[1] == 'r' && s[2] == 'a') - { - s += 3; - regno = RA; - } - else if (s[1] == 'f' && s[2] == 'p') - { - s += 3; - regno = FP; - } - else if (s[1] == 's' && s[2] == 'p') - { - s += 3; - regno = SP; - } - else if (s[1] == 'g' && s[2] == 'p') - { - s += 3; - regno = GP; - } - else if (s[1] == 'a' && s[2] == 't') - { - s += 3; - regno = AT; - } - else if (s[1] == 'k' && s[2] == 't' && s[3] == '0') - { - s += 4; - regno = KT0; - } - else if (s[1] == 'k' && s[2] == 't' && s[3] == '1') - { - s += 4; - regno = KT1; - } - else if (s[1] == 'z' && s[2] == 'e' && s[3] == 'r' && s[4] == 'o') - { - s += 5; - regno = ZERO; - } - else if (itbl_have_entries) - { - char *p, *n; - unsigned long r; - - p = s + 1; /* advance past '$' */ - n = itbl_get_field (&p); /* n is name */ - - /* See if this is a register defined in an - itbl entry. */ - if (itbl_get_reg_val (n, &r)) - { - /* Get_field advances to the start of - the next field, so we need to back - rack to the end of the last field. */ - if (p) - s = p - 1; - else - s = strchr (s, '\0'); - regno = r; - } - else - goto notreg; - } - else - goto notreg; - } - if (regno == AT - && ! mips_opts.noat - && *args != 'E' - && *args != 'G' - && *args != 'K') - as_warn (_("Used $at without \".set noat\"")); c = *args; if (*s == ' ') ++s; @@ -8820,7 +9081,6 @@ do_msbd: lastregno = regno; continue; } - notreg: switch (*args++) { case 'r': @@ -8873,40 +9133,22 @@ do_msbd: case 'R': /* floating point source register */ case 'V': case 'W': + rtype = RTYPE_FPU; + if (is_mdmx + || (mips_opts.ase_mdmx + && (ip->insn_mo->pinfo & FP_D) + && (ip->insn_mo->pinfo & (INSN_COPROC_MOVE_DELAY + | INSN_COPROC_MEMORY_DELAY + | INSN_LOAD_COPROC_DELAY + | INSN_LOAD_MEMORY_DELAY + | INSN_STORE_MEMORY)))) + rtype |= RTYPE_VEC; s_reset = s; - /* Accept $fN for FP and MDMX register numbers, and in - addition accept $vN for MDMX register numbers. */ - if ((s[0] == '$' && s[1] == 'f' && ISDIGIT (s[2])) - || (is_mdmx != 0 && s[0] == '$' && s[1] == 'v' - && ISDIGIT (s[2]))) + if (reg_lookup (&s, rtype, ®no)) { - s += 2; - regno = 0; - do - { - regno *= 10; - regno += *s - '0'; - ++s; - } - while (ISDIGIT (*s)); - - if (regno > 31) - as_bad (_("Invalid float register number (%d)"), regno); - if ((regno & 1) != 0 && HAVE_32BIT_FPRS - && ! (strcmp (str, "mtc1") == 0 - || strcmp (str, "mfc1") == 0 - || strcmp (str, "lwc1") == 0 - || strcmp (str, "swc1") == 0 - || strcmp (str, "l.s") == 0 - || strcmp (str, "s.s") == 0 - || strcmp (str, "mftc1") == 0 - || strcmp (str, "mfthc1") == 0 - || strcmp (str, "cftc1") == 0 - || strcmp (str, "mttc1") == 0 - || strcmp (str, "mtthc1") == 0 - || strcmp (str, "cttc1") == 0)) + && ! mips_oddfpreg_ok (ip->insn_mo, argnum)) as_warn (_("Float register should be even, was %d"), regno); @@ -9294,19 +9536,11 @@ do_msbd: case 'N': /* 3 bit branch condition code */ case 'M': /* 3 bit compare condition code */ - if (strncmp (s, "$fcc", 4) != 0) + rtype = RTYPE_CCC; + if (ip->insn_mo->pinfo & (FP_D| FP_S)) + rtype |= RTYPE_FCC; + if (!reg_lookup (&s, rtype, ®no)) break; - s += 4; - regno = 0; - do - { - regno *= 10; - regno += *s - '0'; - ++s; - } - while (ISDIGIT (*s)); - if (regno > 7) - as_bad (_("Invalid condition code register $fcc%d"), regno); if ((strcmp(str + strlen(str) - 3, ".ps") == 0 || strcmp(str + strlen(str) - 5, "any2f") == 0 || strcmp(str + strlen(str) - 5, "any2t") == 0) @@ -9473,8 +9707,38 @@ mips16_ip (char *str, struct mips_cl_insn *ip) argsstart = s; for (;;) { + bfd_boolean ok; + assert (strcmp (insn->name, str) == 0); + if (OPCODE_IS_MEMBER (insn, mips_opts.isa, mips_opts.arch)) + ok = TRUE; + else + ok = FALSE; + + if (! ok) + { + if (insn + 1 < &mips16_opcodes[bfd_mips16_num_opcodes] + && strcmp (insn->name, insn[1].name) == 0) + { + ++insn; + continue; + } + else + { + if (!insn_error) + { + static char buf[100]; + sprintf (buf, + _("opcode not supported on this processor: %s (%s)"), + mips_cpu_info_from_arch (mips_opts.arch)->name, + mips_cpu_info_from_isa (mips_opts.isa)->name); + insn_error = buf; + } + return; + } + } + create_insn (ip, insn); imm_expr.X_op = O_absent; imm_reloc[0] = BFD_RELOC_UNUSED; @@ -9587,70 +9851,19 @@ mips16_ip (char *str, struct mips_cl_insn *ip) case 'R': case 'X': case 'Y': - if (s[0] != '$') - break; - s_reset = s; - if (ISDIGIT (s[1])) + s_reset = s; + if (!reg_lookup (&s, RTYPE_NUM | RTYPE_GP, ®no)) { - ++s; - regno = 0; - do - { - regno *= 10; - regno += *s - '0'; - ++s; - } - while (ISDIGIT (*s)); - if (regno > 31) - { - as_bad (_("invalid register number (%d)"), regno); - regno = 2; - } - } - else - { - if (s[1] == 'r' && s[2] == 'a') - { - s += 3; - regno = RA; - } - else if (s[1] == 'f' && s[2] == 'p') - { - s += 3; - regno = FP; - } - else if (s[1] == 's' && s[2] == 'p') - { - s += 3; - regno = SP; - } - else if (s[1] == 'g' && s[2] == 'p') - { - s += 3; - regno = GP; - } - else if (s[1] == 'a' && s[2] == 't') - { - s += 3; - regno = AT; - } - else if (s[1] == 'k' && s[2] == 't' && s[3] == '0') - { - s += 4; - regno = KT0; - } - else if (s[1] == 'k' && s[2] == 't' && s[3] == '1') - { - s += 4; - regno = KT1; - } - else if (s[1] == 'z' && s[2] == 'e' && s[3] == 'r' && s[4] == 'o') + if (c == 'v' || c == 'w') { - s += 5; - regno = ZERO; + if (c == 'v') + ip->insn_opcode |= lastregno << MIPS16OP_SH_RX; + else + ip->insn_opcode |= lastregno << MIPS16OP_SH_RY; + ++args; + continue; } - else - break; + break; } if (*s == ' ') @@ -9856,29 +10069,18 @@ mips16_ip (char *str, struct mips_cl_insn *ip) mask = 7 << 3; while (*s != '\0') { - int freg, reg1, reg2; + unsigned int freg, reg1, reg2; while (*s == ' ' || *s == ',') ++s; - if (*s != '$') - { - as_bad (_("can't parse register list")); - break; - } - ++s; - if (*s != 'f') + if (reg_lookup (&s, RTYPE_GP | RTYPE_NUM, ®1)) freg = 0; + else if (reg_lookup (&s, RTYPE_FPU, ®1)) + freg = 1; else { - freg = 1; - ++s; - } - reg1 = 0; - while (ISDIGIT (*s)) - { - reg1 *= 10; - reg1 += *s - '0'; - ++s; + as_bad (_("can't parse register list")); + break; } if (*s == ' ') ++s; @@ -9887,25 +10089,11 @@ mips16_ip (char *str, struct mips_cl_insn *ip) else { ++s; - if (*s != '$') - break; - ++s; - if (freg) + if (!reg_lookup (&s, freg ? RTYPE_FPU + : (RTYPE_GP | RTYPE_NUM), ®2)) { - if (*s == 'f') - ++s; - else - { - as_bad (_("invalid register list")); - break; - } - } - reg2 = 0; - while (ISDIGIT (*s)) - { - reg2 *= 10; - reg2 += *s - '0'; - ++s; + as_bad (_("invalid register list")); + break; } } if (freg && reg1 == 0 && reg2 == 0 && c == 'L') @@ -9970,39 +10158,26 @@ mips16_ip (char *str, struct mips_cl_insn *ip) continue; } - if (*s != '$') + if (! reg_lookup (&s, RTYPE_GP | RTYPE_NUM, ®1)) { as_bad (_("can't parse register list")); break; } - ++s; - reg1 = 0; - while (ISDIGIT (*s)) - { - reg1 *= 10; - reg1 += *s - '0'; - ++s; - } - SKIP_SPACE_TABS (s); + while (*s == ' ') + ++s; + if (*s != '-') reg2 = reg1; else { ++s; - if (*s != '$') + if (! reg_lookup (&s, RTYPE_GP | RTYPE_NUM, ®2) + || reg2 < reg1) { as_bad (_("can't parse register list")); break; } - ++s; - reg2 = 0; - while (ISDIGIT (*s)) - { - reg2 *= 10; - reg2 += *s - '0'; - ++s; - } } while (reg1 <= reg2) @@ -11233,14 +11408,43 @@ mips_after_parse_args (void) || !ISA_HAS_64BIT_REGS (mips_opts.isa)); } - /* ??? GAS treats single-float processors as though they had 64-bit - float registers (although it complains when double-precision - instructions are used). As things stand, saying they have 32-bit - registers would lead to spurious "register must be even" messages. - So here we assume float registers are always the same size as - integer ones, unless the user says otherwise. */ - if (file_mips_fp32 < 0) - file_mips_fp32 = file_mips_gp32; + switch (file_mips_fp32) + { + default: + case -1: + /* No user specified float register size. + ??? GAS treats single-float processors as though they had 64-bit + float registers (although it complains when double-precision + instructions are used). As things stand, saying they have 32-bit + registers would lead to spurious "register must be even" messages. + So here we assume float registers are never smaller than the + integer ones. */ + if (file_mips_gp32 == 0) + /* 64-bit integer registers implies 64-bit float registers. */ + file_mips_fp32 = 0; + else if ((mips_opts.ase_mips3d > 0 || mips_opts.ase_mdmx > 0) + && ISA_HAS_64BIT_FPRS (mips_opts.isa)) + /* -mips3d and -mdmx imply 64-bit float registers, if possible. */ + file_mips_fp32 = 0; + else + /* 32-bit float registers. */ + file_mips_fp32 = 1; + break; + + /* The user specified the size of the float registers. Check if it + agrees with the ABI and ISA. */ + case 0: + if (!ISA_HAS_64BIT_FPRS (mips_opts.isa)) + as_bad (_("-mfp64 used with a 32-bit fpu")); + else if (ABI_NEEDS_32BIT_REGS (mips_abi) + && !ISA_HAS_MXHC1 (mips_opts.isa)) + as_warn (_("-mfp64 used with a 32-bit ABI")); + break; + case 1: + if (ABI_NEEDS_64BIT_REGS (mips_abi)) + as_warn (_("-mfp32 used with a 64-bit ABI")); + break; + } /* End of GCC-shared inference code. */ @@ -11259,13 +11463,36 @@ mips_after_parse_args (void) if (mips_opts.mips16 == -1) mips_opts.mips16 = (CPU_HAS_MIPS16 (file_mips_arch)) ? 1 : 0; if (mips_opts.ase_mips3d == -1) - mips_opts.ase_mips3d = (CPU_HAS_MIPS3D (file_mips_arch)) ? 1 : 0; + mips_opts.ase_mips3d = ((CPU_HAS_MIPS3D (file_mips_arch) + || (arch_info->flags & MIPS_CPU_ASE_MIPS3D)) + && file_mips_fp32 == 0) ? 1 : 0; + if (mips_opts.ase_mips3d && file_mips_fp32 == 1) + as_bad (_("-mfp32 used with -mips3d")); + if (mips_opts.ase_mdmx == -1) - mips_opts.ase_mdmx = (CPU_HAS_MDMX (file_mips_arch)) ? 1 : 0; + mips_opts.ase_mdmx = ((CPU_HAS_MDMX (file_mips_arch) + || (arch_info->flags & MIPS_CPU_ASE_MDMX)) + && file_mips_fp32 == 0) ? 1 : 0; + if (mips_opts.ase_mdmx && file_mips_fp32 == 1) + as_bad (_("-mfp32 used with -mdmx")); + + if (mips_opts.ase_smartmips == -1) + mips_opts.ase_smartmips = (arch_info->flags & MIPS_CPU_ASE_SMARTMIPS) ? 1 : 0; + if (mips_opts.ase_smartmips && !ISA_SUPPORTS_SMARTMIPS) + as_warn ("%s ISA does not support SmartMIPS", + mips_cpu_info_from_isa (mips_opts.isa)->name); + if (mips_opts.ase_dsp == -1) - mips_opts.ase_dsp = (CPU_HAS_DSP (file_mips_arch)) ? 1 : 0; + mips_opts.ase_dsp = (arch_info->flags & MIPS_CPU_ASE_DSP) ? 1 : 0; + if (mips_opts.ase_dsp && !ISA_SUPPORTS_DSP_ASE) + as_warn ("%s ISA does not support DSP ASE", + mips_cpu_info_from_isa (mips_opts.isa)->name); + if (mips_opts.ase_mt == -1) - mips_opts.ase_mt = (CPU_HAS_MT (file_mips_arch)) ? 1 : 0; + mips_opts.ase_mt = (arch_info->flags & MIPS_CPU_ASE_MT) ? 1 : 0; + if (mips_opts.ase_mt && !ISA_SUPPORTS_MT_ASE) + as_warn ("%s ISA does not support MT ASE", + mips_cpu_info_from_isa (mips_opts.isa)->name); file_mips_isa = mips_opts.isa; file_ase_mips16 = mips_opts.mips16; @@ -12119,6 +12346,28 @@ s_mipsset (int x ATTRIBUTE_UNUSED) { mips_opts.nobopt = 1; } + else if (strcmp (name, "gp=default") == 0) + mips_opts.gp32 = file_mips_gp32; + else if (strcmp (name, "gp=32") == 0) + mips_opts.gp32 = 1; + else if (strcmp (name, "gp=64") == 0) + { + if (!ISA_HAS_64BIT_REGS (mips_opts.isa)) + as_warn ("%s isa does not support 64-bit registers", + mips_cpu_info_from_isa (mips_opts.isa)->name); + mips_opts.gp32 = 0; + } + else if (strcmp (name, "fp=default") == 0) + mips_opts.fp32 = file_mips_fp32; + else if (strcmp (name, "fp=32") == 0) + mips_opts.fp32 = 1; + else if (strcmp (name, "fp=64") == 0) + { + if (!ISA_HAS_64BIT_FPRS (mips_opts.isa)) + as_warn ("%s isa does not support 64-bit floating point registers", + mips_cpu_info_from_isa (mips_opts.isa)->name); + mips_opts.fp32 = 0; + } else if (strcmp (name, "mips16") == 0 || strcmp (name, "MIPS-16") == 0) mips_opts.mips16 = 1; @@ -12127,7 +12376,7 @@ s_mipsset (int x ATTRIBUTE_UNUSED) mips_opts.mips16 = 0; else if (strcmp (name, "smartmips") == 0) { - if (!ISA_SUPPORT_SMARTMIPS) + if (!ISA_SUPPORTS_SMARTMIPS) as_warn ("%s ISA does not support SmartMIPS ASE", mips_cpu_info_from_isa (mips_opts.isa)->name); mips_opts.ase_smartmips = 1; @@ -12143,11 +12392,21 @@ s_mipsset (int x ATTRIBUTE_UNUSED) else if (strcmp (name, "nomdmx") == 0) mips_opts.ase_mdmx = 0; else if (strcmp (name, "dsp") == 0) - mips_opts.ase_dsp = 1; + { + if (!ISA_SUPPORTS_DSP_ASE) + as_warn ("%s ISA does not support DSP ASE", + mips_cpu_info_from_isa (mips_opts.isa)->name); + mips_opts.ase_dsp = 1; + } else if (strcmp (name, "nodsp") == 0) mips_opts.ase_dsp = 0; else if (strcmp (name, "mt") == 0) - mips_opts.ase_mt = 1; + { + if (!ISA_SUPPORTS_MT_ASE) + as_warn ("%s ISA does not support MT ASE", + mips_cpu_info_from_isa (mips_opts.isa)->name); + mips_opts.ase_mt = 1; + } else if (strcmp (name, "nomt") == 0) mips_opts.ase_mt = 0; else if (strncmp (name, "mips", 4) == 0 || strncmp (name, "arch=", 5) == 0) @@ -12759,73 +13018,11 @@ s_mips_weakext (int ignore ATTRIBUTE_UNUSED) int tc_get_register (int frame) { - int reg; + unsigned int reg; SKIP_WHITESPACE (); - if (*input_line_pointer++ != '$') - { - as_warn (_("expected `$'")); - reg = ZERO; - } - else if (ISDIGIT (*input_line_pointer)) - { - reg = get_absolute_expression (); - if (reg < 0 || reg >= 32) - { - as_warn (_("Bad register number")); - reg = ZERO; - } - } - else - { - if (strncmp (input_line_pointer, "ra", 2) == 0) - { - reg = RA; - input_line_pointer += 2; - } - else if (strncmp (input_line_pointer, "fp", 2) == 0) - { - reg = FP; - input_line_pointer += 2; - } - else if (strncmp (input_line_pointer, "sp", 2) == 0) - { - reg = SP; - input_line_pointer += 2; - } - else if (strncmp (input_line_pointer, "gp", 2) == 0) - { - reg = GP; - input_line_pointer += 2; - } - else if (strncmp (input_line_pointer, "at", 2) == 0) - { - reg = AT; - input_line_pointer += 2; - } - else if (strncmp (input_line_pointer, "kt0", 3) == 0) - { - reg = KT0; - input_line_pointer += 3; - } - else if (strncmp (input_line_pointer, "kt1", 3) == 0) - { - reg = KT1; - input_line_pointer += 3; - } - else if (strncmp (input_line_pointer, "zero", 4) == 0) - { - reg = ZERO; - input_line_pointer += 4; - } - else - { - as_warn (_("Unrecognized register name")); - reg = ZERO; - while (ISALNUM(*input_line_pointer)) - input_line_pointer++; - } - } + if (! reg_lookup (&input_line_pointer, RWARN | RTYPE_NUM | RTYPE_GP, ®)) + reg = 0; if (frame) { mips_frame_reg = reg != 0 ? reg : SP; @@ -13927,6 +14124,12 @@ mips_elf_final_processing (void) if (mips_32bitmode) elf_elfheader (stdoutput)->e_flags |= EF_MIPS_32BITMODE; + +#if 0 /* XXX FIXME */ + /* 32 bit code with 64 bit FP registers. */ + if (!file_mips_fp32 && ABI_NEEDS_32BIT_REGS (mips_abi)) + elf_elfheader (stdoutput)->e_flags |= ???; +#endif } #endif /* OBJ_ELF || OBJ_MAYBE_ELF */ @@ -14329,72 +14532,90 @@ s_mips_mask (int reg_type) static const struct mips_cpu_info mips_cpu_info_table[] = { /* Entries for generic ISAs */ - { "mips1", 1, ISA_MIPS1, CPU_R3000 }, - { "mips2", 1, ISA_MIPS2, CPU_R6000 }, - { "mips3", 1, ISA_MIPS3, CPU_R4000 }, - { "mips4", 1, ISA_MIPS4, CPU_R8000 }, - { "mips5", 1, ISA_MIPS5, CPU_MIPS5 }, - { "mips32", 1, ISA_MIPS32, CPU_MIPS32 }, - { "mips32r2", 1, ISA_MIPS32R2, CPU_MIPS32R2 }, - { "mips64", 1, ISA_MIPS64, CPU_MIPS64 }, - { "mips64r2", 1, ISA_MIPS64R2, CPU_MIPS64R2 }, + { "mips1", MIPS_CPU_IS_ISA, ISA_MIPS1, CPU_R3000 }, + { "mips2", MIPS_CPU_IS_ISA, ISA_MIPS2, CPU_R6000 }, + { "mips3", MIPS_CPU_IS_ISA, ISA_MIPS3, CPU_R4000 }, + { "mips4", MIPS_CPU_IS_ISA, ISA_MIPS4, CPU_R8000 }, + { "mips5", MIPS_CPU_IS_ISA, ISA_MIPS5, CPU_MIPS5 }, + { "mips32", MIPS_CPU_IS_ISA, ISA_MIPS32, CPU_MIPS32 }, + { "mips32r2", MIPS_CPU_IS_ISA, ISA_MIPS32R2, CPU_MIPS32R2 }, + { "mips64", MIPS_CPU_IS_ISA, ISA_MIPS64, CPU_MIPS64 }, + { "mips64r2", MIPS_CPU_IS_ISA, ISA_MIPS64R2, CPU_MIPS64R2 }, /* MIPS I */ - { "r3000", 0, ISA_MIPS1, CPU_R3000 }, - { "r2000", 0, ISA_MIPS1, CPU_R3000 }, - { "r3900", 0, ISA_MIPS1, CPU_R3900 }, + { "r3000", 0, ISA_MIPS1, CPU_R3000 }, + { "r2000", 0, ISA_MIPS1, CPU_R3000 }, + { "r3900", 0, ISA_MIPS1, CPU_R3900 }, /* MIPS II */ - { "r6000", 0, ISA_MIPS2, CPU_R6000 }, + { "r6000", 0, ISA_MIPS2, CPU_R6000 }, /* MIPS III */ - { "r4000", 0, ISA_MIPS3, CPU_R4000 }, - { "r4010", 0, ISA_MIPS2, CPU_R4010 }, - { "vr4100", 0, ISA_MIPS3, CPU_VR4100 }, - { "vr4111", 0, ISA_MIPS3, CPU_R4111 }, - { "vr4120", 0, ISA_MIPS3, CPU_VR4120 }, - { "vr4130", 0, ISA_MIPS3, CPU_VR4120 }, - { "vr4181", 0, ISA_MIPS3, CPU_R4111 }, - { "vr4300", 0, ISA_MIPS3, CPU_R4300 }, - { "r4400", 0, ISA_MIPS3, CPU_R4400 }, - { "r4600", 0, ISA_MIPS3, CPU_R4600 }, - { "orion", 0, ISA_MIPS3, CPU_R4600 }, - { "r4650", 0, ISA_MIPS3, CPU_R4650 }, + { "r4000", 0, ISA_MIPS3, CPU_R4000 }, + { "r4010", 0, ISA_MIPS2, CPU_R4010 }, + { "vr4100", 0, ISA_MIPS3, CPU_VR4100 }, + { "vr4111", 0, ISA_MIPS3, CPU_R4111 }, + { "vr4120", 0, ISA_MIPS3, CPU_VR4120 }, + { "vr4130", 0, ISA_MIPS3, CPU_VR4120 }, + { "vr4181", 0, ISA_MIPS3, CPU_R4111 }, + { "vr4300", 0, ISA_MIPS3, CPU_R4300 }, + { "r4400", 0, ISA_MIPS3, CPU_R4400 }, + { "r4600", 0, ISA_MIPS3, CPU_R4600 }, + { "orion", 0, ISA_MIPS3, CPU_R4600 }, + { "r4650", 0, ISA_MIPS3, CPU_R4650 }, /* MIPS IV */ - { "r8000", 0, ISA_MIPS4, CPU_R8000 }, - { "r10000", 0, ISA_MIPS4, CPU_R10000 }, - { "r12000", 0, ISA_MIPS4, CPU_R12000 }, - { "vr5000", 0, ISA_MIPS4, CPU_R5000 }, - { "vr5400", 0, ISA_MIPS4, CPU_VR5400 }, - { "vr5500", 0, ISA_MIPS4, CPU_VR5500 }, - { "rm5200", 0, ISA_MIPS4, CPU_R5000 }, - { "rm5230", 0, ISA_MIPS4, CPU_R5000 }, - { "rm5231", 0, ISA_MIPS4, CPU_R5000 }, - { "rm5261", 0, ISA_MIPS4, CPU_R5000 }, - { "rm5721", 0, ISA_MIPS4, CPU_R5000 }, - { "rm7000", 0, ISA_MIPS4, CPU_RM7000 }, - { "rm9000", 0, ISA_MIPS4, CPU_RM9000 }, + { "r8000", 0, ISA_MIPS4, CPU_R8000 }, + { "r10000", 0, ISA_MIPS4, CPU_R10000 }, + { "r12000", 0, ISA_MIPS4, CPU_R12000 }, + { "vr5000", 0, ISA_MIPS4, CPU_R5000 }, + { "vr5400", 0, ISA_MIPS4, CPU_VR5400 }, + { "vr5500", 0, ISA_MIPS4, CPU_VR5500 }, + { "rm5200", 0, ISA_MIPS4, CPU_R5000 }, + { "rm5230", 0, ISA_MIPS4, CPU_R5000 }, + { "rm5231", 0, ISA_MIPS4, CPU_R5000 }, + { "rm5261", 0, ISA_MIPS4, CPU_R5000 }, + { "rm5721", 0, ISA_MIPS4, CPU_R5000 }, + { "rm7000", 0, ISA_MIPS4, CPU_RM7000 }, + { "rm9000", 0, ISA_MIPS4, CPU_RM9000 }, /* MIPS 32 */ - { "4kc", 0, ISA_MIPS32, CPU_MIPS32 }, - { "4km", 0, ISA_MIPS32, CPU_MIPS32 }, - { "4kp", 0, ISA_MIPS32, CPU_MIPS32 }, - - /* MIPS32 Release 2 */ - { "m4k", 0, ISA_MIPS32R2, CPU_MIPS32R2 }, - { "24k", 0, ISA_MIPS32R2, CPU_MIPS32R2 }, - { "24kc", 0, ISA_MIPS32R2, CPU_MIPS32R2 }, - { "24kf", 0, ISA_MIPS32R2, CPU_MIPS32R2 }, - { "24kx", 0, ISA_MIPS32R2, CPU_MIPS32R2 }, + { "4kc", 0, ISA_MIPS32, CPU_MIPS32 }, + { "4km", 0, ISA_MIPS32, CPU_MIPS32 }, + { "4kp", 0, ISA_MIPS32, CPU_MIPS32 }, + { "4ksc", MIPS_CPU_ASE_SMARTMIPS, ISA_MIPS32, CPU_MIPS32 }, + + /* MIPS 32 Release 2 */ + { "4kec", 0, ISA_MIPS32R2, CPU_MIPS32R2 }, + { "4kem", 0, ISA_MIPS32R2, CPU_MIPS32R2 }, + { "4kep", 0, ISA_MIPS32R2, CPU_MIPS32R2 }, + { "4ksd", MIPS_CPU_ASE_SMARTMIPS, ISA_MIPS32R2, CPU_MIPS32R2 }, + { "m4k", 0, ISA_MIPS32R2, CPU_MIPS32R2 }, + { "m4kp", 0, ISA_MIPS32R2, CPU_MIPS32R2 }, + { "24k", 0, ISA_MIPS32R2, CPU_MIPS32R2 }, + { "24kc", 0, ISA_MIPS32R2, CPU_MIPS32R2 }, + { "24kf", 0, ISA_MIPS32R2, CPU_MIPS32R2 }, + { "24kx", 0, ISA_MIPS32R2, CPU_MIPS32R2 }, + /* 24ke is a 24k with DSP ASE, other ASEs are optional. */ + { "24ke", MIPS_CPU_ASE_DSP, ISA_MIPS32R2, CPU_MIPS32R2 }, + { "24kec", MIPS_CPU_ASE_DSP, ISA_MIPS32R2, CPU_MIPS32R2 }, + { "24kef", MIPS_CPU_ASE_DSP, ISA_MIPS32R2, CPU_MIPS32R2 }, + { "24kex", MIPS_CPU_ASE_DSP, ISA_MIPS32R2, CPU_MIPS32R2 }, + /* 34k is a 24k with MT ASE, other ASEs are optional. */ + { "34kc", MIPS_CPU_ASE_MT, ISA_MIPS32R2, CPU_MIPS32R2 }, + { "34kf", MIPS_CPU_ASE_MT, ISA_MIPS32R2, CPU_MIPS32R2 }, + { "34kx", MIPS_CPU_ASE_MT, ISA_MIPS32R2, CPU_MIPS32R2 }, /* MIPS 64 */ - { "5kc", 0, ISA_MIPS64, CPU_MIPS64 }, - { "5kf", 0, ISA_MIPS64, CPU_MIPS64 }, - { "20kc", 0, ISA_MIPS64, CPU_MIPS64 }, + { "5kc", 0, ISA_MIPS64, CPU_MIPS64 }, + { "5kf", 0, ISA_MIPS64, CPU_MIPS64 }, + { "20kc", MIPS_CPU_ASE_MIPS3D, ISA_MIPS64, CPU_MIPS64 }, + + /* MIPS 64 Release 2 */ + { "25kf", MIPS_CPU_ASE_MIPS3D, ISA_MIPS64R2, CPU_MIPS64R2 }, /* Broadcom SB-1 CPU core */ - { "sb1", 0, ISA_MIPS64, CPU_SB1 }, + { "sb1", 0, ISA_MIPS64, CPU_SB1 }, /* End marker */ { NULL, 0, 0, 0 } @@ -14509,7 +14730,7 @@ mips_cpu_info_from_isa (int isa) int i; for (i = 0; mips_cpu_info_table[i].name != NULL; i++) - if (mips_cpu_info_table[i].is_isa + if ((mips_cpu_info_table[i].flags & MIPS_CPU_IS_ISA) && isa == mips_cpu_info_table[i].isa) return (&mips_cpu_info_table[i]); @@ -14681,3 +14902,14 @@ mips_cfi_frame_initial_instructions (void) cfi_add_CFA_def_cfa_register (SP); } +int +tc_mips_regname_to_dw2regnum (char *regname) +{ + unsigned int regnum = -1; + unsigned int reg; + + if (reg_lookup (®name, RTYPE_GP | RTYPE_NUM, ®)) + regnum = reg; + + return regnum; +}