diff --git a/bfd/elf32-mips.c b/bfd/elf32-mips.c index 1de302f..af405bc 100644 --- a/bfd/elf32-mips.c +++ b/bfd/elf32-mips.c @@ -2315,6 +2315,8 @@ static const struct ecoff_debug_swap mips_elf32_ecoff_debug_swap = { #define elf_backend_collect TRUE #define elf_backend_type_change_ok TRUE #define elf_backend_can_gc_sections TRUE +#define elf_backend_gc_mark_extra_sections \ + _bfd_mips_elf_gc_mark_extra_sections #define elf_info_to_howto mips_info_to_howto_rela #define elf_info_to_howto_rel mips_info_to_howto_rel #define elf_backend_sym_is_global mips_elf_sym_is_global diff --git a/bfd/elf64-mips.c b/bfd/elf64-mips.c index 9d50a79..8662d66 100644 --- a/bfd/elf64-mips.c +++ b/bfd/elf64-mips.c @@ -4185,6 +4185,8 @@ const struct elf_size_info mips_elf64_size_info = #define elf_backend_collect TRUE #define elf_backend_type_change_ok TRUE #define elf_backend_can_gc_sections TRUE +#define elf_backend_gc_mark_extra_sections \ + _bfd_mips_elf_gc_mark_extra_sections #define elf_info_to_howto mips_elf64_info_to_howto_rela #define elf_info_to_howto_rel mips_elf64_info_to_howto_rel #define elf_backend_object_p mips_elf64_object_p diff --git a/bfd/elfn32-mips.c b/bfd/elfn32-mips.c index c37ff9d..1286cc1 100644 --- a/bfd/elfn32-mips.c +++ b/bfd/elfn32-mips.c @@ -3410,6 +3410,8 @@ static const struct ecoff_debug_swap mips_elf32_ecoff_debug_swap = { #define elf_backend_collect TRUE #define elf_backend_type_change_ok TRUE #define elf_backend_can_gc_sections TRUE +#define elf_backend_gc_mark_extra_sections \ + _bfd_mips_elf_gc_mark_extra_sections #define elf_info_to_howto mips_info_to_howto_rela #define elf_info_to_howto_rel mips_info_to_howto_rel #define elf_backend_sym_is_global mips_elf_sym_is_global diff --git a/bfd/elfxx-mips.c b/bfd/elfxx-mips.c index 2b3d40d..a72ccc3 100644 --- a/bfd/elfxx-mips.c +++ b/bfd/elfxx-mips.c @@ -12243,6 +12243,36 @@ _bfd_mips_elf_gc_sweep_hook (bfd *abfd ATTRIBUTE_UNUSED, return TRUE; } + +/* Prevent .MIPS.abiflags from being discarded with --gc-sections. */ + +bfd_boolean +_bfd_mips_elf_gc_mark_extra_sections (struct bfd_link_info *info, + elf_gc_mark_hook_fn gc_mark_hook) +{ + bfd *sub; + + _bfd_elf_gc_mark_extra_sections (info, gc_mark_hook); + + for (sub = info->input_bfds; sub != NULL; sub = sub->link.next) + { + asection *o; + + if (! is_mips_elf (sub)) + continue; + + for (o = sub->sections; o != NULL; o = o->next) + if (!o->gc_mark + && MIPS_ELF_ABIFLAGS_SECTION_NAME_P + (bfd_get_section_name (sub, o))) + { + if (!_bfd_elf_gc_mark (info, o, gc_mark_hook)) + return FALSE; + } + } + + return TRUE; +} /* Copy data from a MIPS ELF indirect symbol to its direct symbol, hiding the old indirect symbol. Process additional relocation @@ -13773,6 +13803,7 @@ update_mips_abiflags_isa (bfd *abfd, Elf_Internal_ABIFlags_v0 *abiflags) break; case E_MIPS_ARCH_32R2: abiflags->isa_level = 32; + /* Handle MIPS32r3 and MIPS32r5 which do not have a header flag. */ if (abiflags->isa_rev < 2) abiflags->isa_rev = 2; break; @@ -13781,6 +13812,7 @@ update_mips_abiflags_isa (bfd *abfd, Elf_Internal_ABIFlags_v0 *abiflags) abiflags->isa_rev = 1; break; case E_MIPS_ARCH_64R2: + /* Handle MIPS64r3 and MIPS64r5 which do not have a header flag. */ abiflags->isa_level = 64; if (abiflags->isa_rev < 2) abiflags->isa_rev = 2; @@ -13834,7 +13866,8 @@ infer_mips_abiflags (bfd *abfd, Elf_Internal_ABIFlags_v0* abiflags) && abiflags->gpr_size == AFL_REG_32)) abiflags->cpr1_size = AFL_REG_32; else if (abiflags->fp_abi == Val_GNU_MIPS_ABI_FP_DOUBLE - || abiflags->fp_abi == Val_GNU_MIPS_ABI_FP_64) + || abiflags->fp_abi == Val_GNU_MIPS_ABI_FP_64 + || abiflags->fp_abi == Val_GNU_MIPS_ABI_FP_64A) abiflags->cpr1_size = AFL_REG_64; abiflags->cpr2_size = AFL_REG_NONE; @@ -13845,6 +13878,13 @@ infer_mips_abiflags (bfd *abfd, Elf_Internal_ABIFlags_v0* abiflags) abiflags->ases |= AFL_ASE_MIPS16; if (elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH_ASE_MICROMIPS) abiflags->ases |= AFL_ASE_MICROMIPS; + + if (abiflags->fp_abi != Val_GNU_MIPS_ABI_FP_ANY + && abiflags->fp_abi != Val_GNU_MIPS_ABI_FP_SOFT + && abiflags->fp_abi != Val_GNU_MIPS_ABI_FP_64A + && abiflags->isa_level >= 32 + && abiflags->isa_ext != AFL_EXT_LOONGSON_3A) + abiflags->flags1 |= AFL_FLAGS1_ODDSPREG; } /* We need to use a special link routine to handle the .reginfo and @@ -14684,14 +14724,25 @@ mips_elf_merge_obj_attributes (bfd *ibfd, bfd *obfd) out_attr[Tag_GNU_MIPS_ABI_FP].i = in_fp; else if (out_fp == Val_GNU_MIPS_ABI_FP_XX && (in_fp == Val_GNU_MIPS_ABI_FP_DOUBLE - || in_fp == Val_GNU_MIPS_ABI_FP_64)) + || in_fp == Val_GNU_MIPS_ABI_FP_64 + || in_fp == Val_GNU_MIPS_ABI_FP_64A)) { mips_elf_tdata (obfd)->abi_fp_bfd = ibfd; out_attr[Tag_GNU_MIPS_ABI_FP].i = in_attr[Tag_GNU_MIPS_ABI_FP].i; } else if (in_fp == Val_GNU_MIPS_ABI_FP_XX && (out_fp == Val_GNU_MIPS_ABI_FP_DOUBLE - || out_fp == Val_GNU_MIPS_ABI_FP_64)) + || out_fp == Val_GNU_MIPS_ABI_FP_64 + || out_fp == Val_GNU_MIPS_ABI_FP_64A)) + /* Keep the current setting. */; + else if (out_fp == Val_GNU_MIPS_ABI_FP_64A + && in_fp == Val_GNU_MIPS_ABI_FP_64) + { + mips_elf_tdata (obfd)->abi_fp_bfd = ibfd; + out_attr[Tag_GNU_MIPS_ABI_FP].i = in_attr[Tag_GNU_MIPS_ABI_FP].i; + } + else if (in_fp == Val_GNU_MIPS_ABI_FP_64A + && out_fp == Val_GNU_MIPS_ABI_FP_64) /* Keep the current setting. */; else if (in_fp != Val_GNU_MIPS_ABI_FP_ANY) { @@ -14789,6 +14840,7 @@ _bfd_mips_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd) bfd_boolean ok; bfd_boolean null_input_bfd = TRUE; asection *sec; + obj_attribute *out_attr; /* Check if we have the same endianness. */ if (! _bfd_generic_verify_endian_match (ibfd, obfd)) @@ -14884,6 +14936,11 @@ _bfd_mips_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd) (*_bfd_error_handler) (_("%B: warning: Inconsistent ISA extensions between e_flags and " ".MIPS.abiflags"), ibfd); + if (in_abiflags.flags2 != 0) + (*_bfd_error_handler) + (_("%B: warning: Unexpected flag in the flags2 field of " + ".MIPS.abiflags (0x%lx)"), ibfd, + (unsigned long) in_abiflags.flags2); } if (!mips_elf_tdata (obfd)->abiflags_valid) @@ -14917,7 +14974,7 @@ _bfd_mips_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd) } /* Update the output abiflags fp_abi using the computed fp_abi. */ - obj_attribute *out_attr = elf_known_obj_attributes (obfd)[OBJ_ATTR_GNU]; + out_attr = elf_known_obj_attributes (obfd)[OBJ_ATTR_GNU]; mips_elf_tdata (obfd)->abiflags.fp_abi = out_attr[Tag_GNU_MIPS_ABI_FP].i; #define max(a,b) ((a) > (b) ? (a) : (b)) @@ -14937,6 +14994,8 @@ _bfd_mips_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd) #undef max mips_elf_tdata (obfd)->abiflags.ases |= mips_elf_tdata (ibfd)->abiflags.ases; + mips_elf_tdata (obfd)->abiflags.flags1 + |= mips_elf_tdata (ibfd)->abiflags.flags1; new_flags = elf_elfheader (ibfd)->e_flags; elf_elfheader (obfd)->e_flags |= new_flags & EF_MIPS_NOREORDER; @@ -15257,7 +15316,7 @@ _bfd_mips_fp_abi_string (int fp) return "-msoft-float"; case Val_GNU_MIPS_ABI_FP_OLD_64: - return "-mips32r2 -mfp64 (12 callee-saved)"; + return _("-mips32r2 -mfp64 (12 callee-saved)"); case Val_GNU_MIPS_ABI_FP_XX: return "-mfpxx"; @@ -15265,6 +15324,9 @@ _bfd_mips_fp_abi_string (int fp) case Val_GNU_MIPS_ABI_FP_64: return "-mgp32 -mfp64"; + case Val_GNU_MIPS_ABI_FP_64A: + return "-mgp32 -mfp64 -mno-odd-spreg"; + default: return 0; } @@ -15300,7 +15362,7 @@ print_mips_ases (FILE *file, unsigned int mask) if (mask & AFL_ASE_XPA) fputs ("\n\tXPA ASE", file); if (mask == 0) - fputs (_("\n\tNone"), file); + fprintf (file, "\n\t%s", _("None")); } static void @@ -15312,7 +15374,7 @@ print_mips_isa_ext (FILE *file, unsigned int isa_ext) fputs (_("None"), file); break; case AFL_EXT_XLR: - fputs ("RMI XLR instruction", file); + fputs ("RMI XLR", file); break; case AFL_EXT_OCTEON2: fputs ("Cavium Networks Octeon2", file); @@ -15397,6 +15459,9 @@ print_mips_fp_abi_value (FILE *file, int val) case Val_GNU_MIPS_ABI_FP_64: fprintf (file, _("Hard float (32-bit CPU, 64-bit FPU)\n")); break; + case Val_GNU_MIPS_ABI_FP_64A: + fprintf (file, _("Hard float compat (32-bit CPU, 64-bit FPU)\n")); + break; default: fprintf (file, "??? (%d)\n", val); break; @@ -15846,8 +15911,9 @@ _bfd_mips_post_process_headers (bfd *abfd, struct bfd_link_info *link_info) i_ehdrp->e_ident[EI_ABIVERSION] = 1; } - if (mips_elf_tdata (abfd)->abiflags.fp_abi == Val_GNU_MIPS_ABI_FP_64) - i_ehdrp->e_ident[EI_ABIVERSION] = 3; - _bfd_elf_post_process_headers (abfd, link_info); + + if (mips_elf_tdata (abfd)->abiflags.fp_abi == Val_GNU_MIPS_ABI_FP_64 + || mips_elf_tdata (abfd)->abiflags.fp_abi == Val_GNU_MIPS_ABI_FP_64A) + i_ehdrp->e_ident[EI_ABIVERSION] = 3; } diff --git a/bfd/elfxx-mips.h b/bfd/elfxx-mips.h index 95b98ac..a4d1b27 100644 --- a/bfd/elfxx-mips.h +++ b/bfd/elfxx-mips.h @@ -157,6 +157,8 @@ extern bfd_vma _bfd_mips_elf_plt_sym_val (bfd_vma, const asection *, const arelent *rel); extern long _bfd_mips_elf_get_synthetic_symtab (bfd *, long, asymbol **, long, asymbol **, asymbol **); +extern bfd_boolean _bfd_mips_elf_gc_mark_extra_sections + (struct bfd_link_info *, elf_gc_mark_hook_fn); extern void _bfd_mips_post_process_headers (bfd *abfd, struct bfd_link_info *link_info); diff --git a/binutils/readelf.c b/binutils/readelf.c index b8b5377..7463c55 100644 --- a/binutils/readelf.c +++ b/binutils/readelf.c @@ -12019,6 +12019,9 @@ print_mips_fp_abi_value (int val) case Val_GNU_MIPS_ABI_FP_64: printf (_("Hard float (32-bit CPU, 64-bit FPU)\n")); break; + case Val_GNU_MIPS_ABI_FP_64A: + printf (_("Hard float compat (32-bit CPU, 64-bit FPU)\n")); + break; default: printf ("??? (%d)\n", val); break; @@ -12673,7 +12676,7 @@ print_mips_ases (unsigned int mask) if (mask & AFL_ASE_XPA) fputs ("\n\tXPA ASE", stdout); if (mask == 0) - fputs (_("\n\tNone"), stdout); + fprintf (stdout, "\n\t%s", _("None")); } static void @@ -12685,7 +12688,7 @@ print_mips_isa_ext (unsigned int isa_ext) fputs (_("None"), stdout); break; case AFL_EXT_XLR: - fputs ("RMI XLR instruction", stdout); + fputs ("RMI XLR", stdout); break; case AFL_EXT_OCTEON2: fputs ("Cavium Networks Octeon2", stdout); diff --git a/gas/config/tc-mips.c b/gas/config/tc-mips.c index acc772a..b0ecf19 100644 --- a/gas/config/tc-mips.c +++ b/gas/config/tc-mips.c @@ -258,6 +258,10 @@ struct mips_set_options Changed by .set singlefloat or .set doublefloat, command-line options -msingle-float or -mdouble-float. The default is false. */ bfd_boolean single_float; + + /* 1 if single-precision operations on odd-numbered registers are + not allowed (even if supported by ISA_HAS_ODD_SINGLE_FPR). */ + int nooddspreg; }; /* Specifies whether module level options have been checked yet. */ @@ -276,7 +280,7 @@ static struct mips_set_options file_mips_opts = /* noreorder */ 0, /* at */ ATREG, /* warn_about_macros */ 0, /* nomove */ 0, /* nobopt */ 0, /* noautoextend */ 0, /* insn32 */ FALSE, /* gp */ -1, /* fp */ -1, /* arch */ CPU_UNKNOWN, /* sym32 */ FALSE, - /* soft_float */ FALSE, /* single_float */ FALSE + /* soft_float */ FALSE, /* single_float */ FALSE, /* nooddspreg */ -1 }; /* This is similar to file_mips_opts, but for the current set of options. */ @@ -287,7 +291,7 @@ static struct mips_set_options mips_opts = /* noreorder */ 0, /* at */ ATREG, /* warn_about_macros */ 0, /* nomove */ 0, /* nobopt */ 0, /* noautoextend */ 0, /* insn32 */ FALSE, /* gp */ -1, /* fp */ -1, /* arch */ CPU_UNKNOWN, /* sym32 */ FALSE, - /* soft_float */ FALSE, /* single_float */ FALSE + /* soft_float */ FALSE, /* single_float */ FALSE, /* nooddspreg */ -1 }; /* Which bits of file_ase were explicitly set or cleared by ASE options. */ @@ -393,15 +397,17 @@ static int mips_32bitmode = 0; ) /* 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_MIPS32R3 \ - || (ISA) == ISA_MIPS32R5 \ - || (ISA) == ISA_MIPS64 \ - || (ISA) == ISA_MIPS64R2 \ - || (ISA) == ISA_MIPS64R3 \ - || (ISA) == ISA_MIPS64R5) +#define ISA_HAS_ODD_SINGLE_FPR(ISA, CPU)\ + (((ISA) == ISA_MIPS32 \ + || (ISA) == ISA_MIPS32R2 \ + || (ISA) == ISA_MIPS32R3 \ + || (ISA) == ISA_MIPS32R5 \ + || (ISA) == ISA_MIPS64 \ + || (ISA) == ISA_MIPS64R2 \ + || (ISA) == ISA_MIPS64R3 \ + || (ISA) == ISA_MIPS64R5 \ + || (CPU) == CPU_R5900) \ + && (CPU) != CPU_LOONGSON_3A) /* Return true if ISA supports move to/from high part of a 64-bit floating-point register. */ @@ -1436,6 +1442,8 @@ enum options OPTION_NO_PDR, OPTION_MVXWORKS_PIC, OPTION_NAN, + OPTION_ODD_SPREG, + OPTION_NO_ODD_SPREG, OPTION_END_OF_ENUM }; @@ -1542,6 +1550,8 @@ struct option md_longopts[] = {"mhard-float", no_argument, NULL, OPTION_HARD_FLOAT}, {"msingle-float", no_argument, NULL, OPTION_SINGLE_FLOAT}, {"mdouble-float", no_argument, NULL, OPTION_DOUBLE_FLOAT}, + {"modd-spreg", no_argument, NULL, OPTION_ODD_SPREG}, + {"mno-odd-spreg", no_argument, NULL, OPTION_NO_ODD_SPREG}, /* Strictly speaking this next option is ELF specific, but we allow it for other ports as well in order to @@ -3658,11 +3668,11 @@ fpabi_requires (int fpabi, const char *what) Tag_GNU_MIPS_ABI_FP, fpabi, what); } +/* Check -mabi and register sizes against the specified FP ABI. */ static void check_fpabi (int fpabi) { bfd_boolean needs_check = FALSE; - /* Check -mabi and register sizes. */ switch (fpabi) { case Val_GNU_MIPS_ABI_FP_DOUBLE: @@ -3683,11 +3693,16 @@ check_fpabi (int fpabi) needs_check = TRUE; break; + case Val_GNU_MIPS_ABI_FP_64A: case Val_GNU_MIPS_ABI_FP_64: if (mips_abi != O32_ABI) fpabi_requires (fpabi, "-mabi=32"); - else if (file_mips_opts.fp == 32) - fpabi_incompatible_with (fpabi, "fp=32"); + else if (file_mips_opts.fp != 64) + fpabi_requires (fpabi, "fp=64"); + else if (fpabi == Val_GNU_MIPS_ABI_FP_64 && file_mips_opts.nooddspreg) + fpabi_incompatible_with (fpabi, "nooddspreg"); + else if (fpabi == Val_GNU_MIPS_ABI_FP_64A && !file_mips_opts.nooddspreg) + fpabi_requires (fpabi, "nooddspreg"); else needs_check = TRUE; break; @@ -3696,12 +3711,12 @@ check_fpabi (int fpabi) if (file_mips_opts.soft_float) fpabi_incompatible_with (fpabi, "softfloat"); else if (!file_mips_opts.single_float) - fpabi_incompatible_with (fpabi, "doublefloat"); + fpabi_requires (fpabi, "singlefloat"); break; case Val_GNU_MIPS_ABI_FP_SOFT: if (!file_mips_opts.soft_float) - fpabi_incompatible_with (fpabi, "hardfloat"); + fpabi_requires (fpabi, "softfloat"); break; case Val_GNU_MIPS_ABI_FP_OLD_64: @@ -3763,6 +3778,9 @@ mips_check_options (struct mips_set_options *opts, bfd_boolean abi_checks) break; } + if (ABI_NEEDS_64BIT_REGS (mips_abi) && opts->nooddspreg) + as_bad (_("`nooddspreg` cannot be used with a 64-bit ABI")); + if (opts->micromips == 1 && opts->mips16 == 1) as_bad (_("`mips16' cannot be used with `micromips'")); } @@ -3820,6 +3838,16 @@ file_mips_check_options (void) arch_info = mips_cpu_info_from_arch (file_mips_opts.arch); + /* Disable operations on odd-numbered floating-point registers by default + when using the FPXX ABI. */ + if (file_mips_opts.nooddspreg < 0) + { + if (file_mips_opts.fp == 0) + file_mips_opts.nooddspreg = 1; + else + file_mips_opts.nooddspreg = 0; + } + /* End of GCC-shared inference code. */ /* This flag is set when we have a 64-bit capable CPU but use only @@ -4469,46 +4497,41 @@ static bfd_boolean mips_oddfpreg_ok (const struct mips_opcode *insn, int opnum) { const char *s = insn->name; - bfd_boolean oddspreg = (ISA_HAS_ODD_SINGLE_FPR (mips_opts.isa) - || mips_opts.arch == CPU_R5900); + bfd_boolean oddspreg = (ISA_HAS_ODD_SINGLE_FPR (mips_opts.isa, mips_opts.arch) + || FPR_SIZE == 64) + && !mips_opts.nooddspreg; if (insn->pinfo == INSN_MACRO) /* Let a macro pass, we'll catch it later when it is expanded. */ return TRUE; - if (oddspreg) - { - /* Allow odd registers for single-precision ops. */ - switch (insn->pinfo & (FP_S | FP_D)) - { - case FP_S: - case 0: - return TRUE; - case FP_D: - return FALSE; - default: - break; - } - - /* Cvt.w.x and cvt.x.w allow an odd register for a 'w' or 's' operand. */ - s = strchr (insn->name, '.'); - if (s != NULL && opnum == 2) - s = strchr (s + 1, '.'); - return (s != NULL && (s[1] == 'w' || s[1] == 's')); - } - - /* Single-precision coprocessor loads and moves are OK too. */ + /* Single-precision coprocessor loads and moves are OK for 32-bit registers, + otherwise it depends on oddspreg. */ if ((insn->pinfo & FP_S) - && (insn->pinfo & (INSN_COPROC_MEMORY_DELAY | INSN_STORE_MEMORY - | INSN_LOAD_COPROC_DELAY | INSN_COPROC_MOVE_DELAY))) + && (insn->pinfo & INSN_FP_32_MOVE)) + return FPR_SIZE == 32 || oddspreg; + + /* Allow odd registers for single-precision ops and double-precision if the + floating-point registers are 64-bit wide. */ + switch (insn->pinfo & (FP_S | FP_D)) { - if (FPR_SIZE == 0 && !oddspreg) - as_bad (_("unsupported access to the upper half of double-precision " - "registers")); - return TRUE; + case FP_S: + case 0: + return oddspreg; + case FP_D: + return FPR_SIZE == 64; + default: + break; } - return FALSE; + /* Cvt.w.x and cvt.x.w allow an odd register for a 'w' or 's' operand. */ + s = strchr (insn->name, '.'); + if (s != NULL && opnum == 2) + s = strchr (s + 1, '.'); + if (s != NULL && (s[1] == 'w' || s[1] == 's')) + return oddspreg; + + return FPR_SIZE == 64; } /* Information about an instruction argument that we're trying to match. */ @@ -4731,10 +4754,12 @@ check_regno (struct mips_arg_info *arg, if (type == OP_REG_FP && (regno & 1) != 0 - && FPR_SIZE != 64 && !mips_oddfpreg_ok (arg->insn->insn_mo, arg->opnum)) { - if (FPR_SIZE != 0) + /* This was a warning prior to introducing O32 FPXX and FP64 support + so maintain a warning for FP32 but raise an error for the new + cases. */ + if (FPR_SIZE == 32) as_warn (_("float register should be even, was %d"), regno); else as_bad (_("float register should be even, was %d"), regno); @@ -5611,7 +5636,7 @@ match_float_constant (struct mips_arg_info *arg, expressionS *imm, If using 32-bit registers, set IMM to the high order 32 bits and OFFSET to the low order 32 bits. Otherwise, set IMM to the entire 64 bit constant. */ - if (using_gprs ? GPR_SIZE == 32 : FPR_SIZE != 64) + if (GPR_SIZE == 32 || (!using_gprs && FPR_SIZE != 64)) { imm->X_op = O_constant; offset->X_op = O_constant; @@ -11799,10 +11824,10 @@ macro (struct mips_cl_insn *ip, char *str) { if (ISA_HAS_MXHC1 (mips_opts.isa)) macro_build (NULL, "mthc1", "t,G", AT, op[0]); - else if (mips_opts.fp != 32) + else if (FPR_SIZE != 32) as_bad (_("Unable to generate `%s' compliant code " "without mthc1"), - (mips_opts.fp == 64) ? "fp64" : "fpxx"); + (FPR_SIZE == 64) ? "fp64" : "fpxx"); else macro_build (NULL, "mtc1", "t,G", AT, op[0] + 1); if (offset_expr.X_op == O_absent) @@ -14058,6 +14083,14 @@ md_parse_option (int c, char *arg) file_mips_opts.fp = 64; break; + case OPTION_ODD_SPREG: + file_mips_opts.nooddspreg = 0; + break; + + case OPTION_NO_ODD_SPREG: + file_mips_opts.nooddspreg = 1; + break; + case OPTION_SINGLE_FLOAT: file_mips_opts.single_float = 1; break; @@ -15158,6 +15191,10 @@ parse_code_option (char * name) mips_opts.single_float = 1; else if (strcmp (name, "doublefloat") == 0) mips_opts.single_float = 0; + else if (strcmp (name, "nooddspreg") == 0) + mips_opts.nooddspreg = 1; + else if (strcmp (name, "oddspreg") == 0) + mips_opts.nooddspreg = 0; else if (strcmp (name, "mips16") == 0 || strcmp (name, "MIPS-16") == 0) mips_opts.mips16 = 1; @@ -15319,6 +15356,9 @@ s_mipsset (int x ATTRIBUTE_UNUSED) case 0: break; case ISA_MIPS1: + /* MIPS I cannot support FPXX. */ + mips_opts.fp = 32; + /* fall-through. */ case ISA_MIPS2: case ISA_MIPS32: case ISA_MIPS32R2: @@ -17599,6 +17639,10 @@ mips_elf_final_processing (void) if (file_ase_micromips) flags.ases |= AFL_ASE_MICROMIPS; flags.flags1 = 0; + if ((ISA_HAS_ODD_SINGLE_FPR (file_mips_opts.isa, file_mips_opts.arch) + || file_mips_opts.fp == 64) + && !file_mips_opts.nooddspreg) + flags.flags1 |= AFL_FLAGS1_ODDSPREG; flags.flags2 = 0; bfd_mips_elf_swap_abiflags_v0_out (stdoutput, &flags, @@ -18643,7 +18687,16 @@ md_mips_end (void) file_mips_check_options (); /* Set a floating-point ABI if the user did not. */ - if (!obj_elf_seen_attribute (OBJ_ATTR_GNU, Tag_GNU_MIPS_ABI_FP)) + if (obj_elf_seen_attribute (OBJ_ATTR_GNU, Tag_GNU_MIPS_ABI_FP)) + { + + /* Perform consistency checks on the floating-point ABI. */ + fpabi = bfd_elf_get_obj_attr_int (stdoutput, OBJ_ATTR_GNU, + Tag_GNU_MIPS_ABI_FP); + if (fpabi != Val_GNU_MIPS_ABI_FP_ANY) + check_fpabi (fpabi); + } + else { /* Soft-float gets precedence over single-float, the two options should not be used together so this should not matter. */ @@ -18664,7 +18717,9 @@ md_mips_end (void) fpabi = Val_GNU_MIPS_ABI_FP_XX; break; case 64: - if (file_mips_opts.gp == 32) + if (file_mips_opts.gp == 32 && file_mips_opts.nooddspreg) + fpabi = Val_GNU_MIPS_ABI_FP_64A; + else if (file_mips_opts.gp == 32) fpabi = Val_GNU_MIPS_ABI_FP_64; else fpabi = Val_GNU_MIPS_ABI_FP_DOUBLE; @@ -18675,10 +18730,4 @@ md_mips_end (void) bfd_elf_add_obj_attr_int (stdoutput, OBJ_ATTR_GNU, Tag_GNU_MIPS_ABI_FP, fpabi); } - - /* Perform consistency checks on the floating-point ABI. */ - fpabi = bfd_elf_get_obj_attr_int (stdoutput, OBJ_ATTR_GNU, - Tag_GNU_MIPS_ABI_FP); - if (fpabi != Val_GNU_MIPS_ABI_FP_ANY) - check_fpabi (fpabi); } diff --git a/gas/doc/as.texinfo b/gas/doc/as.texinfo index 04757df..251b6d5 100644 --- a/gas/doc/as.texinfo +++ b/gas/doc/as.texinfo @@ -400,6 +400,7 @@ gcc(1), ld(1), and the Info entries for @file{binutils} and @file{ld}. [@b{-non_shared}] [@b{-xgot} [@b{-mvxworks-pic}] [@b{-mabi}=@var{ABI}] [@b{-32}] [@b{-n32}] [@b{-64}] [@b{-mfp32}] [@b{-mgp32}] [@b{-mfp64}] [@b{-mgp64}] [@b{-mfpxx}] + [@b{-modd-spreg}] [@b{-mno-odd-spreg}] [@b{-march}=@var{CPU}] [@b{-mtune}=@var{CPU}] [@b{-mips1}] [@b{-mips2}] [@b{-mips3}] [@b{-mips4}] [@b{-mips5}] [@b{-mips32}] [@b{-mips32r2}] [@b{-mips32r3}] [@b{-mips32r5}] [@b{-mips64}] [@b{-mips64r2}] @@ -1335,6 +1336,12 @@ this flag in combination with @samp{-mabi=32} enables an ABI variant which will operate correctly with floating-point registers which are 32 or 64 bits wide. +@item -modd-spreg +@itemx -mno-odd-spreg +Enable use of floating-point operations on odd-numbered single-precision +registers when supported by the ISA. @samp{-mfpxx} implies +@samp{-mno-odd-spreg}, otherwise the default is @samp{-modd-spreg}. + @item -mips16 @itemx -no-mips16 Generate code for the MIPS 16 processor. This is equivalent to putting diff --git a/gas/doc/c-mips.texi b/gas/doc/c-mips.texi index 8ed4d51..1e52e09 100644 --- a/gas/doc/c-mips.texi +++ b/gas/doc/c-mips.texi @@ -133,8 +133,15 @@ compatible with either @samp{-mfp32} or @samp{-mfp64}. This option can only be used with MIPS II and above. The @code{.set fp=xx} directive allows a part of an object to be marked -as not making assumptions about 32-bit or 64-bita FP registers. The +as not making assumptions about 32-bit or 64-bit FP registers. The default value is restored by @code{.set fp=default}. + +@item -modd-spreg +@itemx -mno-odd-spreg +Enable use of floating-point operations on odd-numbered single-precision +registers when supported by the ISA. @samp{-mfpxx} implies +@samp{-mno-odd-spreg}, otherwise the default is @samp{-modd-spreg} + @item -mips16 @itemx -no-mips16 Generate code for the MIPS 16 processor. This is equivalent to putting @@ -831,7 +838,7 @@ pass all floating-point data in general-purpose registers. @item 4 - Deprecated This variant existed as an initial attempt at supporting 64-bit wide floating-point registers for O32 ABI on a MIPS32r2 cpu. This has been -superceded by @value{5} and @value{6}. +superceded by @value{5}, @value{6} and @value{7}. @item 5 - Double-precision 32-bit CPU, 32-bit or 64-bit FPU This variant is used by 32-bit ABIs to indicate that the floating-point @@ -845,6 +852,14 @@ This variant is used by 32-bit ABIs to indicate that the floating-point code in the module requires 64-bit wide floating-point registers. Double-precision support is used. Only O32 currently supports this variant and requires a minimum architecture of MIPS32r2. + +@item 7 - Double-precision compat 32-bit FPU, 64-bit FPU +This variant is used by 32-bit ABIs to indicate that the floating-point +code in the module requires 64-bit wide floating-point registers. +Double-precision support is used. This differs from the previous ABI +as it restricts use of odd-numbered single-precision registers. Only +O32 currently supports this variant and requires a minimum architecture +of MIPS32r2. @end table @node MIPS FP ABI Selection @@ -863,20 +878,22 @@ has been used the module will be marked as soft-float. If single-precision. The remaining ABIs are then selected based on the FP register width. Double-precision is selected if the width of GP and FP registers match and the special double-precision variants -for 32-bit ABIs are then selected depending on @samp{-mfpxx} and -@samp{-mfp64}. +for 32-bit ABIs are then selected depending on @samp{-mfpxx}, +@samp{-mfp64} and @samp{-mno-odd-spreg}. @node MIPS FP ABI Compatibility @subsection Linking different FP ABI variants Modules using the default FP ABI (no floating-point) can be linked with any other (singular) FP ABI variant. -Special compatibility support exists for O32 with the three +Special compatibility support exists for O32 with the four double-precision FP ABI variants. The @samp{-mfpxx} FP ABI is specifically -designed to be compatible with both the standard double-precision ABI and -the @samp{-mfp64} FP ABI. This makes it desirable for O32 modules to be +designed to be compatible with the standard double-precision ABI and the +@samp{-mfp64} FP ABIs. This makes it desirable for O32 modules to be built as @samp{-mfpxx} to ensure the maximum compatibility with other -modules produced for more specific needs. +modules produced for more specific needs. The only FP ABIs which cannot +be linked together are the standard double-precision ABI and the full +@samp{-mfp64} ABI with @samp{-modd-spreg}. @node MIPS NaN Encodings @section Directives to record which NaN encoding is being used diff --git a/include/elf/mips.h b/include/elf/mips.h index 2553e6d..24c2380 100644 --- a/include/elf/mips.h +++ b/include/elf/mips.h @@ -1071,7 +1071,7 @@ typedef struct unsigned char cpr2_size[1]; /* The floating-point ABI. */ unsigned char fp_abi[1]; - /* Mask of processor-specific extensions. */ + /* Processor-specific extension. */ unsigned char isa_ext[4]; /* Mask of ASEs used. */ unsigned char ases[4]; @@ -1096,7 +1096,7 @@ typedef struct unsigned char cpr2_size; /* The floating-point ABI. */ unsigned char fp_abi; - /* Mask of processor-specific extensions. */ + /* Processor-specific extension. */ unsigned long isa_ext; /* Mask of ASEs used. */ unsigned long ases; @@ -1233,6 +1233,9 @@ extern void bfd_mips_elf_swap_abiflags_v0_out #define AFL_EXT_LOONGSON_2E 17 /* ST Microelectronics Loongson 2E. */ #define AFL_EXT_LOONGSON_2F 18 /* ST Microelectronics Loongson 2F. */ +/* Masks for the flags1 word of an ABI flags structure. */ +#define AFL_FLAGS1_ODDSPREG 1 /* Uses odd single-precision registers. */ + extern unsigned int bfd_mips_isa_ext (bfd *); @@ -1274,6 +1277,9 @@ enum /* Using -mips32r2 -mfp64. */ Val_GNU_MIPS_ABI_FP_64 = 6, + /* Using -mips32r2 -mfp64 -mno-odd-spreg. */ + Val_GNU_MIPS_ABI_FP_64A = 7, + /* Values defined for Tag_GNU_MIPS_ABI_MSA. */ /* Not tagged or not using any ABIs affected by the differences. */ diff --git a/include/opcode/mips.h b/include/opcode/mips.h index 6ae1f3a..13ebba76 100644 --- a/include/opcode/mips.h +++ b/include/opcode/mips.h @@ -1010,6 +1010,8 @@ struct mips_opcode #define INSN_WRITE_GPR_24 0x10000000 /* A user-defined instruction. */ #define INSN_UDI 0x20000000 +/* Is mtc1, mfc1, swc1, lwc1. */ +#define INSN_FP_32_MOVE 0x40000000 /* Instruction is actually a macro. It should be ignored by the disassembler, and requires special treatment by the assembler. */ #define INSN_MACRO 0xffffffff diff --git a/opcodes/micromips-opc.c b/opcodes/micromips-opc.c index af7cbf6..d8fcbca 100644 --- a/opcodes/micromips-opc.c +++ b/opcodes/micromips-opc.c @@ -204,6 +204,7 @@ decode_micromips_operand (const char *p) #define SM INSN_STORE_MEMORY #define BD16 INSN2_BRANCH_DELAY_16BIT /* Used in pinfo2. */ #define BD32 INSN2_BRANCH_DELAY_32BIT /* Used in pinfo2. */ +#define F32M INSN_FP_32_MOVE #define WR_1 INSN_WRITE_1 #define WR_2 INSN_WRITE_2 @@ -540,14 +541,14 @@ const struct mips_opcode micromips_opcodes[] = {"ceil.l.s", "T,S", 0x5400133b, 0xfc00ffff, WR_1|RD_2|FP_S|FP_D, 0, I1, 0, 0 }, {"ceil.w.d", "T,S", 0x54005b3b, 0xfc00ffff, WR_1|RD_2|FP_S|FP_D, 0, I1, 0, 0 }, {"ceil.w.s", "T,S", 0x54001b3b, 0xfc00ffff, WR_1|RD_2|FP_S, 0, I1, 0, 0 }, -{"cfc1", "t,G", 0x5400103b, 0xfc00ffff, WR_1|RD_C1|FP_S, 0, I1, 0, 0 }, -{"cfc1", "t,S", 0x5400103b, 0xfc00ffff, WR_1|RD_C1|FP_S, 0, I1, 0, 0 }, +{"cfc1", "t,G", 0x5400103b, 0xfc00ffff, WR_1|RD_C1, 0, I1, 0, 0 }, +{"cfc1", "t,S", 0x5400103b, 0xfc00ffff, WR_1|RD_C1, 0, I1, 0, 0 }, {"cfc2", "t,G", 0x0000cd3c, 0xfc00ffff, WR_1|RD_C2, 0, I1, 0, 0 }, {"clo", "t,s", 0x00004b3c, 0xfc00ffff, WR_1|RD_2, 0, I1, 0, 0 }, {"clz", "t,s", 0x00005b3c, 0xfc00ffff, WR_1|RD_2, 0, I1, 0, 0 }, {"cop2", "C", 0x00000002, 0xfc000007, CP, 0, I1, 0, 0 }, -{"ctc1", "t,G", 0x5400183b, 0xfc00ffff, RD_1|WR_CC|FP_S, 0, I1, 0, 0 }, -{"ctc1", "t,S", 0x5400183b, 0xfc00ffff, RD_1|WR_CC|FP_S, 0, I1, 0, 0 }, +{"ctc1", "t,G", 0x5400183b, 0xfc00ffff, RD_1|WR_CC, 0, I1, 0, 0 }, +{"ctc1", "t,S", 0x5400183b, 0xfc00ffff, RD_1|WR_CC, 0, I1, 0, 0 }, {"ctc2", "t,G", 0x0000dd3c, 0xfc00ffff, RD_1|WR_C2|WR_CC, 0, I1, 0, 0 }, {"cvt.d.l", "T,S", 0x5400537b, 0xfc00ffff, WR_1|RD_2|FP_D, 0, I1, 0, 0 }, {"cvt.d.s", "T,S", 0x5400137b, 0xfc00ffff, WR_1|RD_2|FP_S|FP_D, 0, I1, 0, 0 }, @@ -789,13 +790,13 @@ const struct mips_opcode micromips_opcodes[] = {"lw", "md,mA(ma)", 0x6400, 0xfc00, WR_1|RD_3|LM, 0, I1, 0, 0 }, /* lwgp */ {"lw", "t,o(b)", 0xfc000000, 0xfc000000, WR_1|RD_3|LM, 0, I1, 0, 0 }, {"lw", "t,A(b)", 0, (int) M_LW_AB, INSN_MACRO, 0, I1, 0, 0 }, -{"lwc1", "T,o(b)", 0x9c000000, 0xfc000000, WR_1|RD_3|FP_S|LM, 0, I1, 0, 0 }, -{"lwc1", "E,o(b)", 0x9c000000, 0xfc000000, WR_1|RD_3|FP_S|LM, 0, I1, 0, 0 }, +{"lwc1", "T,o(b)", 0x9c000000, 0xfc000000, WR_1|RD_3|FP_S|LM|F32M, 0, I1, 0, 0 }, +{"lwc1", "E,o(b)", 0x9c000000, 0xfc000000, WR_1|RD_3|FP_S|LM|F32M, 0, I1, 0, 0 }, {"lwc1", "T,A(b)", 0, (int) M_LWC1_AB, INSN_MACRO, INSN2_M_FP_S, I1, 0, 0 }, {"lwc1", "E,A(b)", 0, (int) M_LWC1_AB, INSN_MACRO, INSN2_M_FP_S, I1, 0, 0 }, {"lwc2", "E,~(b)", 0x20000000, 0xfc00f000, RD_3|WR_CC|LM, 0, I1, 0, 0 }, {"lwc2", "E,A(b)", 0, (int) M_LWC2_AB, INSN_MACRO, 0, I1, 0, 0 }, -{"l.s", "T,o(b)", 0x9c000000, 0xfc000000, WR_1|RD_3|FP_S|LM, 0, I1, 0, 0 }, /* lwc1 */ +{"l.s", "T,o(b)", 0x9c000000, 0xfc000000, WR_1|RD_3|FP_S|LM|F32M, 0, I1, 0, 0 }, /* lwc1 */ {"l.s", "T,A(b)", 0, (int) M_LWC1_AB, INSN_MACRO, INSN2_M_FP_S, I1, 0, 0 }, {"lwl", "t,~(b)", 0x60000000, 0xfc00f000, WR_1|RD_3|LM, 0, I1, 0, 0 }, {"lwl", "t,A(b)", 0, (int) M_LWL_AB, INSN_MACRO, 0, I1, 0, 0 }, @@ -810,7 +811,7 @@ const struct mips_opcode micromips_opcodes[] = {"lwr", "t,A(b)", 0, (int) M_LWR_AB, INSN_MACRO, 0, I1, 0, 0 }, {"lwu", "t,~(b)", 0x6000e000, 0xfc00f000, WR_1|RD_3|LM, 0, I3, 0, 0 }, {"lwu", "t,A(b)", 0, (int) M_LWU_AB, INSN_MACRO, 0, I3, 0, 0 }, -{"lwxc1", "D,t(b)", 0x54000048, 0xfc0007ff, WR_1|RD_2|RD_3|FP_S|LM, 0, I1, 0, 0 }, +{"lwxc1", "D,t(b)", 0x54000048, 0xfc0007ff, WR_1|RD_2|RD_3|FP_S|LM|F32M, 0, I1, 0, 0 }, {"flush", "t,~(b)", 0x60001000, 0xfc00f000, WR_1|RD_3, 0, I1, 0, 0 }, /* same */ {"flush", "t,A(b)", 0, (int) M_LWR_AB, INSN_MACRO, 0, I1, 0, 0 }, {"lwxs", "d,t(b)", 0x00000118, 0xfc0007ff, WR_1|RD_2|RD_3|LM, 0, I1, 0, 0 }, @@ -823,8 +824,8 @@ const struct mips_opcode micromips_opcodes[] = {"maddu", "7,s,t", 0x00001abc, 0xfc003fff, RD_2|RD_3|MOD_a, 0, 0, D32, 0 }, {"mfc0", "t,G", 0x000000fc, 0xfc00ffff, WR_1|RD_C0, 0, I1, 0, 0 }, {"mfc0", "t,G,H", 0x000000fc, 0xfc00c7ff, WR_1|RD_C0, 0, I1, 0, 0 }, -{"mfc1", "t,S", 0x5400203b, 0xfc00ffff, WR_1|RD_2|FP_S, 0, I1, 0, 0 }, -{"mfc1", "t,G", 0x5400203b, 0xfc00ffff, WR_1|RD_2|FP_S, 0, I1, 0, 0 }, +{"mfc1", "t,S", 0x5400203b, 0xfc00ffff, WR_1|RD_2|FP_S|F32M, 0, I1, 0, 0 }, +{"mfc1", "t,G", 0x5400203b, 0xfc00ffff, WR_1|RD_2|FP_S|F32M, 0, I1, 0, 0 }, {"mfc2", "t,G", 0x00004d3c, 0xfc00ffff, WR_1|RD_C2, 0, I1, 0, 0 }, {"mfgc0", "t,G", 0x000004fc, 0xfc00ffff, WR_1|RD_C0, 0, 0, IVIRT, 0 }, {"mfgc0", "t,G,H", 0x000004fc, 0xfc00c7ff, WR_1|RD_C0, 0, 0, IVIRT, 0 }, @@ -869,8 +870,8 @@ const struct mips_opcode micromips_opcodes[] = {"msubu", "7,s,t", 0x00003abc, 0xfc003fff, RD_2|RD_3|MOD_a, 0, 0, D32, 0 }, {"mtc0", "t,G", 0x000002fc, 0xfc00ffff, RD_1|WR_C0|WR_CC, 0, I1, 0, 0 }, {"mtc0", "t,G,H", 0x000002fc, 0xfc00c7ff, RD_1|WR_C0|WR_CC, 0, I1, 0, 0 }, -{"mtc1", "t,S", 0x5400283b, 0xfc00ffff, RD_1|WR_2|FP_S, 0, I1, 0, 0 }, -{"mtc1", "t,G", 0x5400283b, 0xfc00ffff, RD_1|WR_2|FP_S, 0, I1, 0, 0 }, +{"mtc1", "t,S", 0x5400283b, 0xfc00ffff, RD_1|WR_2|FP_S|F32M, 0, I1, 0, 0 }, +{"mtc1", "t,G", 0x5400283b, 0xfc00ffff, RD_1|WR_2|FP_S|F32M, 0, I1, 0, 0 }, {"mtc2", "t,G", 0x00005d3c, 0xfc00ffff, RD_1|WR_C2|WR_CC, 0, I1, 0, 0 }, {"mtgc0", "t,G", 0x000006fc, 0xfc00ffff, RD_1|WR_C0|WR_CC, 0, 0, IVIRT, 0 }, {"mtgc0", "t,G,H", 0x000006fc, 0xfc00c7ff, RD_1|WR_C0|WR_CC, 0, 0, IVIRT, 0 }, @@ -1037,13 +1038,13 @@ const struct mips_opcode micromips_opcodes[] = {"sw", "mp,mU(ms)", 0xc800, 0xfc00, RD_1|RD_3|SM, 0, I1, 0, 0 }, /* swsp */ {"sw", "t,o(b)", 0xf8000000, 0xfc000000, RD_1|RD_3|SM, 0, I1, 0, 0 }, {"sw", "t,A(b)", 0, (int) M_SW_AB, INSN_MACRO, 0, I1, 0, 0 }, -{"swc1", "T,o(b)", 0x98000000, 0xfc000000, RD_1|RD_3|SM|FP_S, 0, I1, 0, 0 }, -{"swc1", "E,o(b)", 0x98000000, 0xfc000000, RD_1|RD_3|SM|FP_S, 0, I1, 0, 0 }, +{"swc1", "T,o(b)", 0x98000000, 0xfc000000, RD_1|RD_3|SM|FP_S|F32M, 0, I1, 0, 0 }, +{"swc1", "E,o(b)", 0x98000000, 0xfc000000, RD_1|RD_3|SM|FP_S|F32M, 0, I1, 0, 0 }, {"swc1", "T,A(b)", 0, (int) M_SWC1_AB, INSN_MACRO, INSN2_M_FP_S, I1, 0, 0 }, {"swc1", "E,A(b)", 0, (int) M_SWC1_AB, INSN_MACRO, INSN2_M_FP_S, I1, 0, 0 }, {"swc2", "E,~(b)", 0x20008000, 0xfc00f000, RD_3|RD_C2|SM, 0, I1, 0, 0 }, {"swc2", "E,A(b)", 0, (int) M_SWC2_AB, INSN_MACRO, 0, I1, 0, 0 }, -{"s.s", "T,o(b)", 0x98000000, 0xfc000000, RD_1|RD_3|SM|FP_S, 0, I1, 0, 0 }, /* swc1 */ +{"s.s", "T,o(b)", 0x98000000, 0xfc000000, RD_1|RD_3|SM|FP_S|F32M, 0, I1, 0, 0 }, /* swc1 */ {"s.s", "T,A(b)", 0, (int) M_SWC1_AB, INSN_MACRO, INSN2_M_FP_S, I1, 0, 0 }, {"swl", "t,~(b)", 0x60008000, 0xfc00f000, RD_1|RD_3|SM, 0, I1, 0, 0 }, {"swl", "t,A(b)", 0, (int) M_SWL_AB, INSN_MACRO, 0, I1, 0, 0 }, @@ -1058,7 +1059,7 @@ const struct mips_opcode micromips_opcodes[] = {"swr", "t,A(b)", 0, (int) M_SWR_AB, INSN_MACRO, 0, I1, 0, 0 }, {"invalidate", "t,~(b)", 0x60009000, 0xfc00f000, RD_1|RD_3|SM, 0, I1, 0, 0 }, /* same */ {"invalidate", "t,A(b)", 0, (int) M_SWR_AB, INSN_MACRO, 0, I1, 0, 0 }, -{"swxc1", "D,t(b)", 0x54000088, 0xfc0007ff, RD_1|RD_2|RD_3|SM|FP_S, 0, I1, 0, 0 }, +{"swxc1", "D,t(b)", 0x54000088, 0xfc0007ff, RD_1|RD_2|RD_3|SM|FP_S|F32M, 0, I1, 0, 0 }, {"sync_acquire", "", 0x00116b7c, 0xffffffff, NODS, 0, I1, 0, 0 }, {"sync_mb", "", 0x00106b7c, 0xffffffff, NODS, 0, I1, 0, 0 }, {"sync_release", "", 0x00126b7c, 0xffffffff, NODS, 0, I1, 0, 0 }, diff --git a/opcodes/mips-opc.c b/opcodes/mips-opc.c index e2c258c..04c23c5 100644 --- a/opcodes/mips-opc.c +++ b/opcodes/mips-opc.c @@ -200,6 +200,7 @@ decode_mips_operand (const char *p) #define TRAP INSN_NO_DELAY_SLOT #define LM INSN_LOAD_MEMORY #define SM INSN_STORE_MEMORY +#define F32M INSN_FP_32_MOVE #define WR_1 INSN_WRITE_1 #define WR_2 INSN_WRITE_2 @@ -901,8 +902,8 @@ const struct mips_opcode mips_builtin_opcodes[] = {"ceil.w.d", "D,S", 0x4620000e, 0xffff003f, WR_1|RD_2|FP_S|FP_D, 0, I2, 0, SF }, {"ceil.w.s", "D,S", 0x4600000e, 0xffff003f, WR_1|RD_2|FP_S, 0, I2, 0, EE }, /* cfc0 is at the bottom of the table. */ -{"cfc1", "t,G", 0x44400000, 0xffe007ff, WR_1|RD_C1|LCD|FP_S, 0, I1, 0, 0 }, -{"cfc1", "t,S", 0x44400000, 0xffe007ff, WR_1|RD_C1|LCD|FP_S, 0, I1, 0, 0 }, +{"cfc1", "t,G", 0x44400000, 0xffe007ff, WR_1|RD_C1|LCD, 0, I1, 0, 0 }, +{"cfc1", "t,S", 0x44400000, 0xffe007ff, WR_1|RD_C1|LCD, 0, I1, 0, 0 }, /* cfc2 is at the bottom of the table. */ /* cfc3 is at the bottom of the table. */ {"cftc1", "d,E", 0x41000023, 0xffe007ff, WR_1|RD_C1|TRAP|LCD|FP_S, 0, 0, MT32, 0 }, @@ -914,8 +915,8 @@ const struct mips_opcode mips_builtin_opcodes[] = {"clo", "U,s", 0x70000021, 0xfc0007ff, WR_1|RD_2, 0, I32|N55, 0, 0 }, {"clz", "U,s", 0x70000020, 0xfc0007ff, WR_1|RD_2, 0, I32|N55, 0, 0 }, /* ctc0 is at the bottom of the table. */ -{"ctc1", "t,G", 0x44c00000, 0xffe007ff, RD_1|WR_CC|COD|FP_S, 0, I1, 0, 0 }, -{"ctc1", "t,S", 0x44c00000, 0xffe007ff, RD_1|WR_CC|COD|FP_S, 0, I1, 0, 0 }, +{"ctc1", "t,G", 0x44c00000, 0xffe007ff, RD_1|WR_CC|COD, 0, I1, 0, 0 }, +{"ctc1", "t,S", 0x44c00000, 0xffe007ff, RD_1|WR_CC|COD, 0, I1, 0, 0 }, /* ctc2 is at the bottom of the table. */ /* ctc3 is at the bottom of the table. */ {"cttc1", "t,g", 0x41800023, 0xffe007ff, RD_1|WR_CC|TRAP|COD|FP_S, 0, 0, MT32, 0 }, @@ -1208,11 +1209,11 @@ const struct mips_opcode mips_builtin_opcodes[] = {"lw", "t,A(b)", 0, (int) M_LW_AB, INSN_MACRO, 0, I1, 0, 0 }, {"lwc0", "E,o(b)", 0xc0000000, 0xfc000000, RD_3|WR_CC|CLD, 0, I1, 0, IOCT|IOCTP|IOCT2 }, {"lwc0", "E,A(b)", 0, (int) M_LWC0_AB, INSN_MACRO, 0, I1, 0, IOCT|IOCTP|IOCT2 }, -{"lwc1", "T,o(b)", 0xc4000000, 0xfc000000, WR_1|RD_3|CLD|FP_S, 0, I1, 0, 0 }, -{"lwc1", "E,o(b)", 0xc4000000, 0xfc000000, WR_1|RD_3|CLD|FP_S, 0, I1, 0, 0 }, +{"lwc1", "T,o(b)", 0xc4000000, 0xfc000000, WR_1|RD_3|CLD|FP_S|F32M,0, I1, 0, 0 }, +{"lwc1", "E,o(b)", 0xc4000000, 0xfc000000, WR_1|RD_3|CLD|FP_S|F32M,0, I1, 0, 0 }, {"lwc1", "T,A(b)", 0, (int) M_LWC1_AB, INSN_MACRO, INSN2_M_FP_S, I1, 0, 0 }, {"lwc1", "E,A(b)", 0, (int) M_LWC1_AB, INSN_MACRO, INSN2_M_FP_S, I1, 0, 0 }, -{"l.s", "T,o(b)", 0xc4000000, 0xfc000000, WR_1|RD_3|CLD|FP_S, 0, I1, 0, 0 }, /* lwc1 */ +{"l.s", "T,o(b)", 0xc4000000, 0xfc000000, WR_1|RD_3|CLD|FP_S|F32M,0, I1, 0, 0 }, /* lwc1 */ {"l.s", "T,A(b)", 0, (int) M_LWC1_AB, INSN_MACRO, INSN2_M_FP_S, I1, 0, 0 }, {"lwc2", "E,o(b)", 0xc8000000, 0xfc000000, RD_3|WR_CC|CLD, 0, I1, 0, IOCT|IOCTP|IOCT2|EE }, {"lwc2", "E,A(b)", 0, (int) M_LWC2_AB, INSN_MACRO, 0, I1, 0, IOCT|IOCTP|IOCT2|EE }, @@ -1229,7 +1230,7 @@ const struct mips_opcode mips_builtin_opcodes[] = {"fork", "d,s,t", 0x7c000008, 0xfc0007ff, WR_1|RD_2|RD_3|TRAP, 0, 0, MT32, 0 }, {"lwu", "t,o(b)", 0x9c000000, 0xfc000000, WR_1|RD_3|LM, 0, I3, 0, 0 }, {"lwu", "t,A(b)", 0, (int) M_LWU_AB, INSN_MACRO, 0, I3, 0, 0 }, -{"lwxc1", "D,t(b)", 0x4c000000, 0xfc00f83f, WR_1|RD_2|RD_3|LM|FP_S, 0, I4_33, 0, 0 }, +{"lwxc1", "D,t(b)", 0x4c000000, 0xfc00f83f, WR_1|RD_2|RD_3|LM|FP_S|F32M, 0, I4_33, 0, 0 }, {"lwxs", "d,t(b)", 0x70000088, 0xfc0007ff, WR_1|RD_2|RD_3|LM, 0, 0, SMT, 0 }, {"macc", "d,s,t", 0x00000028, 0xfc0007ff, WR_1|RD_2|RD_3|WR_HILO, 0, N412, 0, 0 }, {"macc", "d,s,t", 0x00000158, 0xfc0007ff, WR_1|RD_2|RD_3|WR_HILO, 0, N5, 0, 0 }, @@ -1310,8 +1311,8 @@ const struct mips_opcode mips_builtin_opcodes[] = {"mfhc0", "t,G,H", 0x40400000, 0xffe007f8, WR_1|RD_C0|LCD, 0, I33, XPA, 0 }, {"mfhgc0", "t,G", 0x40600400, 0xffe007ff, WR_1|RD_C0|LCD, 0, I33, IVIRT|XPA, 0 }, {"mfhgc0", "t,G,H", 0x40600400, 0xffe007f8, WR_1|RD_C0|LCD, 0, I33, IVIRT|XPA, 0 }, -{"mfc1", "t,S", 0x44000000, 0xffe007ff, WR_1|RD_2|LCD|FP_S, 0, I1, 0, 0 }, -{"mfc1", "t,G", 0x44000000, 0xffe007ff, WR_1|RD_2|LCD|FP_S, 0, I1, 0, 0 }, +{"mfc1", "t,S", 0x44000000, 0xffe007ff, WR_1|RD_2|LCD|FP_S|F32M,0, I1, 0, 0 }, +{"mfc1", "t,G", 0x44000000, 0xffe007ff, WR_1|RD_2|LCD|FP_S|F32M,0, I1, 0, 0 }, {"mfhc1", "t,S", 0x44600000, 0xffe007ff, WR_1|RD_2|LCD|FP_D, 0, I33, 0, 0 }, {"mfhc1", "t,G", 0x44600000, 0xffe007ff, WR_1|RD_2|LCD|FP_D, 0, I33, 0, 0 }, /* mfc2 is at the bottom of the table. */ @@ -1407,8 +1408,8 @@ const struct mips_opcode mips_builtin_opcodes[] = {"mthc0", "t,G,H", 0x40c00000, 0xffe007f8, RD_1|WR_C0|WR_CC|COD, 0, I33, XPA, 0 }, {"mthgc0", "t,G", 0x40600600, 0xffe007ff, RD_1|WR_C0|WR_CC|COD, 0, I33, IVIRT|XPA, 0 }, {"mthgc0", "t,G,H", 0x40600600, 0xffe007f8, RD_1|WR_C0|WR_CC|COD, 0, I33, IVIRT|XPA, 0 }, -{"mtc1", "t,S", 0x44800000, 0xffe007ff, RD_1|WR_2|COD|FP_S, 0, I1, 0, 0 }, -{"mtc1", "t,G", 0x44800000, 0xffe007ff, RD_1|WR_2|COD|FP_S, 0, I1, 0, 0 }, +{"mtc1", "t,S", 0x44800000, 0xffe007ff, RD_1|WR_2|COD|FP_S|F32M,0, I1, 0, 0 }, +{"mtc1", "t,G", 0x44800000, 0xffe007ff, RD_1|WR_2|COD|FP_S|F32M,0, I1, 0, 0 }, {"mthc1", "t,S", 0x44e00000, 0xffe007ff, RD_1|WR_2|COD|FP_D, 0, I33, 0, 0 }, {"mthc1", "t,G", 0x44e00000, 0xffe007ff, RD_1|WR_2|COD|FP_D, 0, I33, 0, 0 }, /* mtc2 is at the bottom of the table. */ @@ -1848,11 +1849,11 @@ const struct mips_opcode mips_builtin_opcodes[] = {"swapd", "t,b", 0x70000016, 0xfc00ffff, MOD_1|RD_2|LM|SM, 0, XLR, 0, 0 }, {"swc0", "E,o(b)", 0xe0000000, 0xfc000000, RD_3|RD_C0|SM, 0, I1, 0, IOCT|IOCTP|IOCT2 }, {"swc0", "E,A(b)", 0, (int) M_SWC0_AB, INSN_MACRO, 0, I1, 0, IOCT|IOCTP|IOCT2 }, -{"swc1", "T,o(b)", 0xe4000000, 0xfc000000, RD_1|RD_3|SM|FP_S, 0, I1, 0, 0 }, -{"swc1", "E,o(b)", 0xe4000000, 0xfc000000, RD_1|RD_3|SM|FP_S, 0, I1, 0, 0 }, +{"swc1", "T,o(b)", 0xe4000000, 0xfc000000, RD_1|RD_3|SM|FP_S|F32M, 0, I1, 0, 0 }, +{"swc1", "E,o(b)", 0xe4000000, 0xfc000000, RD_1|RD_3|SM|FP_S|F32M, 0, I1, 0, 0 }, {"swc1", "T,A(b)", 0, (int) M_SWC1_AB, INSN_MACRO, INSN2_M_FP_S, I1, 0, 0 }, {"swc1", "E,A(b)", 0, (int) M_SWC1_AB, INSN_MACRO, INSN2_M_FP_S, I1, 0, 0 }, -{"s.s", "T,o(b)", 0xe4000000, 0xfc000000, RD_1|RD_3|SM|FP_S, 0, I1, 0, 0 }, /* swc1 */ +{"s.s", "T,o(b)", 0xe4000000, 0xfc000000, RD_1|RD_3|SM|FP_S|F32M, 0, I1, 0, 0 }, /* swc1 */ {"s.s", "T,A(b)", 0, (int) M_SWC1_AB, INSN_MACRO, INSN2_M_FP_S, I1, 0, 0 }, {"swc2", "E,o(b)", 0xe8000000, 0xfc000000, RD_3|RD_C2|SM, 0, I1, 0, IOCT|IOCTP|IOCT2|EE }, {"swc2", "E,A(b)", 0, (int) M_SWC2_AB, INSN_MACRO, 0, I1, 0, IOCT|IOCTP|IOCT2|EE }, @@ -1866,7 +1867,7 @@ const struct mips_opcode mips_builtin_opcodes[] = {"swr", "t,A(b)", 0, (int) M_SWR_AB, INSN_MACRO, 0, I1, 0, 0 }, {"invalidate", "t,o(b)", 0xb8000000, 0xfc000000, RD_1|RD_3, 0, I2, 0, 0 }, /* same */ {"invalidate", "t,A(b)", 0, (int) M_SWR_AB, INSN_MACRO, 0, I2, 0, 0 }, /* as swr */ -{"swxc1", "S,t(b)", 0x4c000008, 0xfc0007ff, RD_1|RD_2|RD_3|SM|FP_S, 0, I4_33, 0, 0 }, +{"swxc1", "S,t(b)", 0x4c000008, 0xfc0007ff, RD_1|RD_2|RD_3|SM|FP_S|F32M, 0, I4_33, 0, 0 }, {"synciobdma", "", 0x0000008f, 0xffffffff, NODS, 0, IOCT, 0, 0 }, {"syncs", "", 0x0000018f, 0xffffffff, NODS, 0, IOCT, 0, 0 }, {"syncw", "", 0x0000010f, 0xffffffff, NODS, 0, IOCT, 0, 0 },