This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH 5/9] Re-work RISC-V gas flags: now we just support -mabi and -march


From: Andrew Waterman <andrew@sifive.com>

We've decided to standardize on two flags for RISC-V: "-march" sets the
target architecture (which determines which instructions can be
generated), and "-mabi" sets the target ABI.  We needed to rework this
because the old flag set didn't support soft-float or single-float ABIs,
and didn't support an x32-style ABI on RISC-V.

Additionally, we've changed the behavior of the -march flag: it's now a
lot stricter and only parses things we can actually understand.
Additionally, it's now lowercase-only: the rationale is that while the
RISC-V ISA manual specifies that ISA strings are case-insensitive, in
Linux-land things are usually case-sensitive.  Since this flag can be
used to determine library paths, we didn't want to bake some
case-insensitivity in there that would case trouble later.

This patch implements these two new flags and removes the old flags that
could conflict with these.  There wasn't a RISC-V release before, so we
want to just support a clean flag set.
---
 bfd/elfnn-riscv.c     |   4 +-
 binutils/readelf.c    |  21 +++++-
 gas/config/tc-riscv.c | 197 ++++++++++++++++++++++++--------------------------
 gas/config/tc-riscv.h |   1 -
 gas/doc/as.texinfo    |   5 +-
 gas/doc/c-riscv.texi  |  23 ++----
 include/elf/riscv.h   |  16 +++-
 opcodes/riscv-dis.c   |   8 +-
 8 files changed, 144 insertions(+), 131 deletions(-)

diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c
index 461bce3..d76163e 100644
--- a/bfd/elfnn-riscv.c
+++ b/bfd/elfnn-riscv.c
@@ -2597,8 +2597,8 @@ _bfd_riscv_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
       return TRUE;
     }
 
-  /* Disallow linking soft-float and hard-float.  */
-  if ((old_flags ^ new_flags) & EF_RISCV_SOFT_FLOAT)
+  /* Disallow linking different float ABIs.  */
+  if ((old_flags ^ new_flags) & EF_RISCV_FLOAT_ABI)
     {
       (*_bfd_error_handler)
 	(_("%B: can't link hard-float modules with soft-float modules"), ibfd);
diff --git a/binutils/readelf.c b/binutils/readelf.c
index c8e9726..873a471 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -3317,8 +3317,25 @@ get_machine_flags (unsigned e_flags, unsigned e_machine)
 	case EM_RISCV:
 	  if (e_flags & EF_RISCV_RVC)
 	    strcat (buf, ", RVC");
-	  if (e_flags & EF_RISCV_SOFT_FLOAT)
-	    strcat (buf, ", soft-float ABI");
+
+	  switch (e_flags & EF_RISCV_FLOAT_ABI)
+	    {
+	    case EF_RISCV_FLOAT_ABI_SOFT:
+	      strcat (buf, ", soft-float ABI");
+	      break;
+
+	    case EF_RISCV_FLOAT_ABI_SINGLE:
+	      strcat (buf, ", single-float ABI");
+	      break;
+
+	    case EF_RISCV_FLOAT_ABI_DOUBLE:
+	      strcat (buf, ", double-float ABI");
+	      break;
+
+	    case EF_RISCV_FLOAT_ABI_QUAD:
+	      strcat (buf, ", quad-float ABI");
+	      break;
+	    }
 	  break;
 
 	case EM_SH:
diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c
index d011864..77c92cf 100644
--- a/gas/config/tc-riscv.c
+++ b/gas/config/tc-riscv.c
@@ -61,9 +61,10 @@ struct riscv_cl_insn
 
 static const char default_arch[] = DEFAULT_ARCH;
 
-unsigned xlen = 0; /* width of an x-register */
+static unsigned xlen = 0; /* width of an x-register */
+static unsigned abi_xlen = 0; /* width of a pointer in the ABI */
 
-#define LOAD_ADDRESS_INSN (xlen == 64 ? "ld" : "lw")
+#define LOAD_ADDRESS_INSN (abi_xlen == 64 ? "ld" : "lw")
 #define ADD32_INSN (xlen == 64 ? "addiw" : "addi")
 
 static unsigned elf_flags = 0;
@@ -129,56 +130,49 @@ riscv_add_subset (const char *subset)
   riscv_subsets = s;
 }
 
-/* Set which ISA and extensions are available.  Formally, ISA strings must
-   begin with RV32 or RV64, but we allow the prefix to be omitted.
+/* Set which ISA and extensions are available.  */
 
-   FIXME: Version numbers are not supported yet.  */
 static void
-riscv_set_arch (const char *p)
+riscv_set_arch (const char *s)
 {
-  const char *all_subsets = "IMAFDC";
+  const char *all_subsets = "imafdc";
   const char *extension = NULL;
-  int rvc = 0;
-  int i;
+  const char *p = s;
 
-  if (strncasecmp (p, "RV32", 4) == 0)
+  if (strncmp (p, "rv32", 4) == 0)
     {
       xlen = 32;
       p += 4;
     }
-  else if (strncasecmp (p, "RV64", 4) == 0)
+  else if (strncmp (p, "rv64", 4) == 0)
     {
       xlen = 64;
       p += 4;
     }
-  else if (strncasecmp (p, "RV", 2) == 0)
-    p += 2;
+  else
+    as_fatal ("-march=%s: ISA string must begin with rv32 or rv64", s);
 
-  switch (TOUPPER(*p))
+  switch (*p)
     {
-      case 'I':
+      case 'i':
 	break;
 
-      case 'G':
+      case 'g':
 	p++;
-	/* Fall through.  */
-
-      case '\0':
-	for (i = 0; all_subsets[i] != '\0'; i++)
+	for ( ; *all_subsets != 'c'; all_subsets++)
 	  {
-	    const char subset[] = {all_subsets[i], '\0'};
+	    const char subset[] = {*all_subsets, '\0'};
 	    riscv_add_subset (subset);
 	  }
 	break;
 
       default:
-	as_fatal ("`I' must be the first ISA subset name specified (got %c)",
-		  *p);
+	as_fatal ("-march=%s: first ISA subset must be `i' or `g'", s);
     }
 
   while (*p)
     {
-      if (TOUPPER(*p) == 'X')
+      if (*p == 'x')
 	{
 	  char *subset = xstrdup (p), *q = subset;
 
@@ -187,8 +181,8 @@ riscv_set_arch (const char *p)
 	  *q = '\0';
 
 	  if (extension)
-	    as_fatal ("only one eXtension is supported (found %s and %s)",
-		      extension, subset);
+	    as_fatal ("-march=%s: only one non-standard extension is supported"
+		      " (found `%s' and `%s')", s, extension, subset);
 	  extension = subset;
 	  riscv_add_subset (subset);
 	  p += strlen (subset);
@@ -200,24 +194,11 @@ riscv_set_arch (const char *p)
 	{
 	  const char subset[] = {*p, 0};
 	  riscv_add_subset (subset);
-	  if (TOUPPER(*p) == 'C')
-	    rvc = 1;
 	  all_subsets++;
 	  p++;
 	}
       else
-	as_fatal ("unsupported ISA subset %c", *p);
-    }
-
-  if (rvc)
-    {
-      /* Override -m[no-]rvc setting if C was explicitly listed.  */
-      riscv_set_rvc (TRUE);
-    }
-  else
-    {
-      /* Add RVC anyway.  -m[no-]rvc toggles its availability.  */
-      riscv_add_subset ("C");
+	as_fatal ("-march=%s: unsupported ISA subset `%c'", s, *p);
     }
 }
 
@@ -604,8 +585,9 @@ void
 md_begin (void)
 {
   int i = 0;
+  unsigned long mach = xlen == 64 ? bfd_mach_riscv64 : bfd_mach_riscv32;
 
-  if (! bfd_set_arch_mach (stdoutput, bfd_arch_riscv, 0))
+  if (! bfd_set_arch_mach (stdoutput, bfd_arch_riscv, mach))
     as_warn (_("Could not set architecture and machine"));
 
   op_hash = hash_new ();
@@ -1717,72 +1699,46 @@ const char *md_shortopts = "O::g::G:";
 
 enum options
 {
-  OPTION_M32 = OPTION_MD_BASE,
-  OPTION_M64,
-  OPTION_MARCH,
+  OPTION_MARCH = OPTION_MD_BASE,
   OPTION_PIC,
   OPTION_NO_PIC,
-  OPTION_MSOFT_FLOAT,
-  OPTION_MHARD_FLOAT,
-  OPTION_MRVC,
-  OPTION_MNO_RVC,
+  OPTION_MABI,
   OPTION_END_OF_ENUM
 };
 
 struct option md_longopts[] =
 {
-  {"m32", no_argument, NULL, OPTION_M32},
-  {"m64", no_argument, NULL, OPTION_M64},
   {"march", required_argument, NULL, OPTION_MARCH},
   {"fPIC", no_argument, NULL, OPTION_PIC},
   {"fpic", no_argument, NULL, OPTION_PIC},
   {"fno-pic", no_argument, NULL, OPTION_NO_PIC},
-  {"mrvc", no_argument, NULL, OPTION_MRVC},
-  {"mno-rvc", no_argument, NULL, OPTION_MNO_RVC},
-  {"msoft-float", no_argument, NULL, OPTION_MSOFT_FLOAT},
-  {"mhard-float", no_argument, NULL, OPTION_MHARD_FLOAT},
+  {"mabi", required_argument, NULL, OPTION_MABI},
 
   {NULL, no_argument, NULL, 0}
 };
 size_t md_longopts_size = sizeof (md_longopts);
 
-enum float_mode
-{
-  FLOAT_MODE_DEFAULT,
-  FLOAT_MODE_SOFT,
-  FLOAT_MODE_HARD
+enum float_abi {
+  FLOAT_ABI_DEFAULT = -1,
+  FLOAT_ABI_SOFT,
+  FLOAT_ABI_SINGLE,
+  FLOAT_ABI_DOUBLE,
+  FLOAT_ABI_QUAD
 };
-static enum float_mode float_mode = FLOAT_MODE_DEFAULT;
+static enum float_abi float_abi = FLOAT_ABI_DEFAULT;
+
+static void
+riscv_set_abi (unsigned new_xlen, enum float_abi new_float_abi)
+{
+  abi_xlen = new_xlen;
+  float_abi = new_float_abi;
+}
 
 int
 md_parse_option (int c, const char *arg)
 {
   switch (c)
     {
-    case OPTION_MRVC:
-      riscv_set_rvc (TRUE);
-      break;
-
-    case OPTION_MNO_RVC:
-      riscv_set_rvc (FALSE);
-      break;
-
-    case OPTION_MSOFT_FLOAT:
-      float_mode = FLOAT_MODE_SOFT;
-      break;
-
-    case OPTION_MHARD_FLOAT:
-      float_mode = FLOAT_MODE_HARD;
-      break;
-
-    case OPTION_M32:
-      xlen = 32;
-      break;
-
-    case OPTION_M64:
-      xlen = 64;
-      break;
-
     case OPTION_MARCH:
       riscv_set_arch (arg);
       break;
@@ -1795,6 +1751,27 @@ md_parse_option (int c, const char *arg)
       riscv_opts.pic = TRUE;
       break;
 
+    case OPTION_MABI:
+      if (strcmp (arg, "ilp32") == 0)
+	riscv_set_abi (32, FLOAT_ABI_SOFT);
+      else if (strcmp (arg, "ilp32f") == 0)
+	riscv_set_abi (32, FLOAT_ABI_SINGLE);
+      else if (strcmp (arg, "ilp32d") == 0)
+	riscv_set_abi (32, FLOAT_ABI_DOUBLE);
+      else if (strcmp (arg, "ilp32q") == 0)
+	riscv_set_abi (32, FLOAT_ABI_QUAD);
+      else if (strcmp (arg, "lp64") == 0)
+	riscv_set_abi (64, FLOAT_ABI_SOFT);
+      else if (strcmp (arg, "lp64f") == 0)
+	riscv_set_abi (64, FLOAT_ABI_SINGLE);
+      else if (strcmp (arg, "lp64d") == 0)
+	riscv_set_abi (64, FLOAT_ABI_DOUBLE);
+      else if (strcmp (arg, "lp64q") == 0)
+	riscv_set_abi (64, FLOAT_ABI_QUAD);
+      else
+	return 0;
+      break;
+
     default:
       return 0;
     }
@@ -1805,9 +1782,6 @@ md_parse_option (int c, const char *arg)
 void
 riscv_after_parse_args (void)
 {
-  if (riscv_subsets == NULL)
-    riscv_set_arch ("RVIMAFD");
-
   if (xlen == 0)
     {
       if (strcmp (default_arch, "riscv32") == 0)
@@ -1817,6 +1791,38 @@ riscv_after_parse_args (void)
       else
 	as_bad ("unknown default architecture `%s'", default_arch);
     }
+
+  if (riscv_subsets == NULL)
+    riscv_set_arch (xlen == 64 ? "rv64g" : "rv32g");
+
+  /* Add the RVC extension, regardless of -march, to support .option rvc.  */
+  if (riscv_subset_supports ("c"))
+    riscv_set_rvc (TRUE);
+  else
+    riscv_add_subset ("c");
+
+  /* Infer ABI from ISA if not specified on command line.  */
+  if (abi_xlen == 0)
+    abi_xlen = xlen;
+  else if (abi_xlen > xlen)
+    as_bad ("can't have %d-bit ABI on %d-bit ISA", abi_xlen, xlen);
+  else if (abi_xlen < xlen)
+    as_bad ("%d-bit ABI not yet supported on %d-bit ISA", abi_xlen, xlen);
+
+  if (float_abi == FLOAT_ABI_DEFAULT)
+    {
+      struct riscv_subset *subset;
+
+      /* Assume soft-float unless D extension is present.  */
+      float_abi = FLOAT_ABI_SOFT;
+
+      for (subset = riscv_subsets; subset != NULL; subset = subset->next)
+	if (strcasecmp (subset->name, "D") == 0)
+	  float_abi = FLOAT_ABI_DOUBLE;
+    }
+
+  /* Insert float_abi into the EF_RISCV_FLOAT_ABI field of elf_flags.  */
+  elf_flags |= float_abi * (EF_RISCV_FLOAT_ABI & ~(EF_RISCV_FLOAT_ABI << 1));
 }
 
 long
@@ -2449,24 +2455,7 @@ tc_riscv_regname_to_dw2regnum (char *regname)
 void
 riscv_elf_final_processing (void)
 {
-  enum float_mode elf_float_mode = float_mode;
-
   elf_elfheader (stdoutput)->e_flags |= elf_flags;
-
-  if (elf_float_mode == FLOAT_MODE_DEFAULT)
-    {
-      struct riscv_subset *subset;
-
-      /* Assume soft-float unless D extension is present.  */
-      elf_float_mode = FLOAT_MODE_SOFT;
-
-      for (subset = riscv_subsets; subset != NULL; subset = subset->next)
-	if (strcasecmp (subset->name, "D") == 0)
-	  elf_float_mode = FLOAT_MODE_HARD;
-    }
-
-  if (elf_float_mode == FLOAT_MODE_SOFT)
-    elf_elfheader (stdoutput)->e_flags |= EF_RISCV_SOFT_FLOAT;
 }
 
 /* Parse the .sleb128 and .uleb128 pseudos.  Only allow constant expressions,
diff --git a/gas/config/tc-riscv.h b/gas/config/tc-riscv.h
index 32cf3ee..5e07fda 100644
--- a/gas/config/tc-riscv.h
+++ b/gas/config/tc-riscv.h
@@ -94,7 +94,6 @@ extern void riscv_cfi_frame_initial_instructions (void);
 #define tc_regname_to_dw2regnum tc_riscv_regname_to_dw2regnum
 extern int tc_riscv_regname_to_dw2regnum (char *);
 
-extern unsigned xlen;
 #define DWARF2_DEFAULT_RETURN_COLUMN X_RA
 
 /* Even on RV64, use 4-byte alignment, as F registers may be only 32 bits.  */
diff --git a/gas/doc/as.texinfo b/gas/doc/as.texinfo
index 2b00acc..4b14e08 100644
--- a/gas/doc/as.texinfo
+++ b/gas/doc/as.texinfo
@@ -514,9 +514,8 @@ gcc(1), ld(1), and the Info entries for @file{binutils} and @file{ld}.
 @ifset RISCV
 
 @emph{Target RISC-V options:}
-   [@b{-m32}|@b{-m64}]
-   [@b{-mrvc}]
-   [@b{-mhard-float}|@b{-msoft-float}]
+   [@b{-march}=@var{ISA}]
+   [@b{-mabi}=@var{ABI}]
 @end ifset
 @ifset S390
 
diff --git a/gas/doc/c-riscv.texi b/gas/doc/c-riscv.texi
index 8674ff2..25e4486 100644
--- a/gas/doc/c-riscv.texi
+++ b/gas/doc/c-riscv.texi
@@ -25,24 +25,17 @@ The following table lists all availiable RISC-V specific options
 
 @c man begin OPTIONS
 @table @gcctabopt
-@cindex @samp{-m32} option, RISC-V
-@cindex @samp{-m64} option, RISC-V
-@item -m32 | -m64
-Select the base ISA, either RV32 or RV64.
-
-@cindex @samp{-mrvc} option, RISC-V
-@item -mrvc
-Enables the C ISA subset for compressed instructions.
-
-@cindex @samp{-msoft-float} option, RISC-V
-@cindex @samp{-mhard-float} option, RISC-V
-@item -msoft-float | -mhard-float
-Select the floating-point ABI, hard-float has F registers while soft-float
-doesn't.
 
 @cindex @samp{-march=ISA} option, RISC-V
 @item -march=ISA
-Select the base isa, as specified by ISA.  For example -march=RV32IMA.
+Select the base isa, as specified by ISA.  For example -march=rv32ima.
+
+@cindex @samp{-mabi=ABI} option, RISC-V
+@item -mabi=ABI
+Selects the ABI, which is either "ilp32" or "lp64", optionally followed
+by "f", "d", or "q" to indicate single-precision, double-precision, or
+quad-precision floating-point calling convention, or none to indicate
+the soft-float calling convention.
 
 @end table
 @c man end
diff --git a/include/elf/riscv.h b/include/elf/riscv.h
index 4407611..5303bd9 100644
--- a/include/elf/riscv.h
+++ b/include/elf/riscv.h
@@ -94,7 +94,19 @@ END_RELOC_NUMBERS (R_RISCV_max)
 /* File may contain compressed instructions.  */
 #define EF_RISCV_RVC 0x0001
 
-/* File uses the soft-float calling convention.  */
-#define EF_RISCV_SOFT_FLOAT 0x0002
+/* Which floating-point ABI a file uses.  */
+#define EF_RISCV_FLOAT_ABI 0x0006
+
+/* File uses the soft-float ABI.  */
+#define EF_RISCV_FLOAT_ABI_SOFT 0x0000
+
+/* File uses the single-float ABI.  */
+#define EF_RISCV_FLOAT_ABI_SINGLE 0x0002
+
+/* File uses the double-float ABI.  */
+#define EF_RISCV_FLOAT_ABI_DOUBLE 0x0004
+
+/* File uses the quad-float ABI.  */
+#define EF_RISCV_FLOAT_ABI_QUAD 0x0006
 
 #endif /* _ELF_RISCV_H */
diff --git a/opcodes/riscv-dis.c b/opcodes/riscv-dis.c
index 3b4e1e0..cb26350 100644
--- a/opcodes/riscv-dis.c
+++ b/opcodes/riscv-dis.c
@@ -406,8 +406,12 @@ riscv_disassemble_insn (bfd_vma memaddr, insn_t word, disassemble_info *info)
     {
       int xlen = 0;
 
-      /* The incoming section might not always be complete.  */
-      if (info->section != NULL)
+      /* If XLEN is not known, get its value from the ELF class.  */
+      if (info->mach == bfd_mach_riscv64)
+	xlen = 64;
+      else if (info->mach == bfd_mach_riscv32)
+	xlen = 32;
+      else if (info->section != NULL)
 	{
 	  Elf_Internal_Ehdr *ehdr = elf_elfheader (info->section->owner);
 	  xlen = ehdr->e_ident[EI_CLASS] == ELFCLASS64 ? 64 : 32;
-- 
2.7.3


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]