public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH 0/2] New target hook TARGET_COMPUTE_MULTILIB and implementation for RISC-V
@ 2021-07-21  9:28 Kito Cheng
  2021-07-21  9:28 ` [PATCH 1/2] Add TARGET_COMPUTE_MULTILIB hook to override multi-lib result Kito Cheng
                   ` (2 more replies)
  0 siblings, 3 replies; 13+ messages in thread
From: Kito Cheng @ 2021-07-21  9:28 UTC (permalink / raw)
  To: gcc-patches, kito.cheng, jimw

This patch set allow target to use customized multi-lib mechanism rather than the built-in
multi-lib mechanism.

The motivation of this patch is RISC-V might have very complicated multi-lib re-use
rule*, which is hard to maintain and use current multi-lib scripts,
we even hit the "argument list too long" error when we tried to add more
multi-lib reuse rule.
 
* Here is an example for RISC-V multi-lib rules:
https://gist.github.com/kito-cheng/0289cd42d9a756382e5afeb77b42b73b

V2 Changes:
- NO changes for first patch(TARGET_COMPUTE_MULTILIB part) since first version.
- Handle option other than -march and -mabi for riscv_compute_multilib.



^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH 1/2] Add TARGET_COMPUTE_MULTILIB hook to override multi-lib result.
  2021-07-21  9:28 [PATCH 0/2] New target hook TARGET_COMPUTE_MULTILIB and implementation for RISC-V Kito Cheng
@ 2021-07-21  9:28 ` Kito Cheng
  2021-09-01  0:16   ` Jim Wilson
  2021-07-21  9:28 ` [PATCH 2/2] RISC-V: Implement TARGET_COMPUTE_MULTILIB Kito Cheng
  2021-07-29 18:44 ` [PATCH 0/2] New target hook TARGET_COMPUTE_MULTILIB and implementation for RISC-V Kito Cheng
  2 siblings, 1 reply; 13+ messages in thread
From: Kito Cheng @ 2021-07-21  9:28 UTC (permalink / raw)
  To: gcc-patches, kito.cheng, jimw; +Cc: Kito Cheng

Create a new hook to let target could override the multi-lib result,
the motivation is RISC-V might have very complicated multi-lib re-use
rule*, which is hard to maintain and use current multi-lib scripts,
we even hit the "argument list too long" error when we tried to add more
multi-lib reuse rule.

So I think it would be great to have a target specific way to determine
the multi-lib re-use rule, then we could write those rule in C, instead
of expand every possible case in MULTILIB_REUSE.

* Here is an example for RISC-V multi-lib rules:
https://gist.github.com/kito-cheng/0289cd42d9a756382e5afeb77b42b73b

gcc/ChangeLog:

	* common/common-target.def (compute_multilib): New.
	* common/common-targhooks.c (default_compute_multilib): New.
	* doc/tm.texi.in (TARGET_COMPUTE_MULTILIB): New.
	* doc/tm.texi: Regen.
	* gcc.c: Include common/common-target.h.
	(set_multilib_dir) Call targetm_common.compute_multilib.
	(SWITCH_LIVE): Move to opts.h.
	(SWITCH_FALSE): Ditto.
	(SWITCH_IGNORE): Ditto.
	(SWITCH_IGNORE_PERMANENTLY): Ditto.
	(SWITCH_KEEP_FOR_GCC): Ditto.
	(struct switchstr): Ditto.
	* opts.h (SWITCH_LIVE): Move from gcc.c.
	(SWITCH_FALSE): Ditto.
	(SWITCH_IGNORE): Ditto.
	(SWITCH_IGNORE_PERMANENTLY): Ditto.
	(SWITCH_KEEP_FOR_GCC): Ditto.
	(struct switchstr): Ditto.
---
 gcc/common/common-target.def  | 25 ++++++++++++++++++
 gcc/common/common-targhooks.c | 15 +++++++++++
 gcc/doc/tm.texi               |  5 ++++
 gcc/doc/tm.texi.in            |  3 +++
 gcc/gcc.c                     | 48 +++++++++--------------------------
 gcc/opts.h                    | 36 ++++++++++++++++++++++++++
 6 files changed, 96 insertions(+), 36 deletions(-)

diff --git a/gcc/common/common-target.def b/gcc/common/common-target.def
index f54590a2a54..a720ecbea98 100644
--- a/gcc/common/common-target.def
+++ b/gcc/common/common-target.def
@@ -84,6 +84,31 @@ The result will be pruned to cases with PREFIX if not NULL.",
  vec<const char *>, (int option_code, const char *prefix),
  default_get_valid_option_values)
 
+DEFHOOK
+(compute_multilib,
+ "Some target like RISC-V might have complicated multilib reuse rule which is\
+  hard to implemented on current multilib scheme, this hook allow target to\
+  override the result from built-in multilib mechanism.\
+  @var{switches} is the raw option list with @var{n_switches} items;\
+  @var{multilib_dir} is the multi-lib result which compute by the built-in\
+  multi-lib mechanism;\
+  @var{multilib_defaults} is the default options list for multi-lib; \
+  @var{multilib_select} is the string contain the list of supported multi-lib, \
+  and the option checking list. \
+  @var{multilib_matches}, @var{multilib_exclusions}, and @var{multilib_reuse} \
+  are corresponding to @var{MULTILIB_MATCHES}, @var{MULTILIB_EXCLUSIONS} \
+  @var{MULTILIB_REUSE}. \
+  The default definition does nothing but return @var{multilib_dir} directly.",
+ const char *, (const struct switchstr *switches,
+		int n_switches,
+		const char *multilib_dir,
+		const char *multilib_defaults,
+		const char *multilib_select,
+		const char *multilib_matches,
+		const char *multilib_exclusions,
+		const char *multilib_reuse),
+ default_compute_multilib)
+
 /* Leave the boolean fields at the end.  */
 
 /* True if unwinding tables should be generated by default.  */
diff --git a/gcc/common/common-targhooks.c b/gcc/common/common-targhooks.c
index 325f199bff3..1477aeeb536 100644
--- a/gcc/common/common-targhooks.c
+++ b/gcc/common/common-targhooks.c
@@ -90,3 +90,18 @@ const struct default_options empty_optimization_table[] =
   {
     { OPT_LEVELS_NONE, 0, NULL, 0 }
   };
+
+/* Default version of TARGET_COMPUTE_MULTILIB.  */
+const char *
+default_compute_multilib(
+  const struct switchstr *,
+  int,
+  const char *multilib,
+  const char *,
+  const char *,
+  const char *,
+  const char *,
+  const char *)
+{
+  return multilib;
+}
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index c8f4abe3e41..0268ea77996 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -778,6 +778,11 @@ options are changed via @code{#pragma GCC optimize} or by using the
 Set target-dependent initial values of fields in @var{opts}.
 @end deftypefn
 
+@deftypefn {Common Target Hook} {const char *} TARGET_COMPUTE_MULTILIB (const struct switchstr *@var{switches}, int @var{n_switches}, const char *@var{multilib_dir}, const char *@var{multilib_defaults}, const char *@var{multilib_select}, const char *@var{multilib_matches}, const char *@var{multilib_exclusions}, const char *@var{multilib_reuse})
+Some target like RISC-V might have complicated multilib reuse rule which is  hard to implemented on current multilib scheme, this hook allow target to  override the result from built-in multilib mechanism.  @var{switches} is the raw option list with @var{n_switches} items;  @var{multilib_dir} is the multi-lib result which compute by the built-in  multi-lib mechanism;  @var{multilib_defaults} is the default options list for multi-lib;   @var{multilib_select} is the string contain the list of supported multi-lib,   and the option checking list.   @var{multilib_matches}, @var{multilib_exclusions}, and @var{multilib_reuse}   are corresponding to @var{MULTILIB_MATCHES}, @var{MULTILIB_EXCLUSIONS}   @var{MULTILIB_REUSE}.   The default definition does nothing but return @var{multilib_dir} directly.
+@end deftypefn
+
+
 @defmac SWITCHABLE_TARGET
 Some targets need to switch between substantially different subtargets
 during compilation.  For example, the MIPS target has one subtarget for
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index 9c4b5016053..6f93edc15c0 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -736,6 +736,9 @@ options are changed via @code{#pragma GCC optimize} or by using the
 
 @hook TARGET_OPTION_INIT_STRUCT
 
+@hook TARGET_COMPUTE_MULTILIB
+
+
 @defmac SWITCHABLE_TARGET
 Some targets need to switch between substantially different subtargets
 during compilation.  For example, the MIPS target has one subtarget for
diff --git a/gcc/gcc.c b/gcc/gcc.c
index 3e98bc7973e..dafe754267a 100644
--- a/gcc/gcc.c
+++ b/gcc/gcc.c
@@ -43,6 +43,7 @@ compilation is specified by a string called a "spec".  */
 #include "opts.h"
 #include "filenames.h"
 #include "spellcheck.h"
+#include "common/common-target.h"
 
 \f
 
@@ -3573,42 +3574,6 @@ execute (void)
   }
 }
 \f
-/* Find all the switches given to us
-   and make a vector describing them.
-   The elements of the vector are strings, one per switch given.
-   If a switch uses following arguments, then the `part1' field
-   is the switch itself and the `args' field
-   is a null-terminated vector containing the following arguments.
-   Bits in the `live_cond' field are:
-   SWITCH_LIVE to indicate this switch is true in a conditional spec.
-   SWITCH_FALSE to indicate this switch is overridden by a later switch.
-   SWITCH_IGNORE to indicate this switch should be ignored (used in %<S).
-   SWITCH_IGNORE_PERMANENTLY to indicate this switch should be ignored.
-   SWITCH_KEEP_FOR_GCC to indicate that this switch, otherwise ignored,
-   should be included in COLLECT_GCC_OPTIONS.
-   in all do_spec calls afterwards.  Used for %<S from self specs.
-   The `known' field describes whether this is an internal switch.
-   The `validated' field describes whether any spec has looked at this switch;
-   if it remains false at the end of the run, the switch must be meaningless.
-   The `ordering' field is used to temporarily mark switches that have to be
-   kept in a specific order.  */
-
-#define SWITCH_LIVE    			(1 << 0)
-#define SWITCH_FALSE   			(1 << 1)
-#define SWITCH_IGNORE			(1 << 2)
-#define SWITCH_IGNORE_PERMANENTLY	(1 << 3)
-#define SWITCH_KEEP_FOR_GCC		(1 << 4)
-
-struct switchstr
-{
-  const char *part1;
-  const char **args;
-  unsigned int live_cond;
-  bool known;
-  bool validated;
-  bool ordering;
-};
-
 static struct switchstr *switches;
 
 static int n_switches;
@@ -9855,6 +9820,17 @@ set_multilib_dir (void)
       ++p;
     }
 
+  multilib_dir =
+    targetm_common.compute_multilib (
+      switches,
+      n_switches,
+      multilib_dir,
+      multilib_defaults,
+      multilib_select,
+      multilib_matches,
+      multilib_exclusions,
+      multilib_reuse);
+
   if (multilib_dir == NULL && multilib_os_dir != NULL
       && strcmp (multilib_os_dir, ".") == 0)
     {
diff --git a/gcc/opts.h b/gcc/opts.h
index bafc790112b..f99a469364c 100644
--- a/gcc/opts.h
+++ b/gcc/opts.h
@@ -500,4 +500,40 @@ extern char *gen_producer_string (const char *language_string,
   } \
   while (false)
 
+/* Find all the switches given to us
+   and make a vector describing them.
+   The elements of the vector are strings, one per switch given.
+   If a switch uses following arguments, then the `part1' field
+   is the switch itself and the `args' field
+   is a null-terminated vector containing the following arguments.
+   Bits in the `live_cond' field are:
+   SWITCH_LIVE to indicate this switch is true in a conditional spec.
+   SWITCH_FALSE to indicate this switch is overridden by a later switch.
+   SWITCH_IGNORE to indicate this switch should be ignored (used in %<S).
+   SWITCH_IGNORE_PERMANENTLY to indicate this switch should be ignored.
+   SWITCH_KEEP_FOR_GCC to indicate that this switch, otherwise ignored,
+   should be included in COLLECT_GCC_OPTIONS.
+   in all do_spec calls afterwards.  Used for %<S from self specs.
+   The `known' field describes whether this is an internal switch.
+   The `validated' field describes whether any spec has looked at this switch;
+   if it remains false at the end of the run, the switch must be meaningless.
+   The `ordering' field is used to temporarily mark switches that have to be
+   kept in a specific order.  */
+
+#define SWITCH_LIVE    			(1 << 0)
+#define SWITCH_FALSE   			(1 << 1)
+#define SWITCH_IGNORE			(1 << 2)
+#define SWITCH_IGNORE_PERMANENTLY	(1 << 3)
+#define SWITCH_KEEP_FOR_GCC		(1 << 4)
+
+struct switchstr
+{
+  const char *part1;
+  const char **args;
+  unsigned int live_cond;
+  bool known;
+  bool validated;
+  bool ordering;
+};
+
 #endif
-- 
2.31.1


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH 2/2] RISC-V: Implement TARGET_COMPUTE_MULTILIB
  2021-07-21  9:28 [PATCH 0/2] New target hook TARGET_COMPUTE_MULTILIB and implementation for RISC-V Kito Cheng
  2021-07-21  9:28 ` [PATCH 1/2] Add TARGET_COMPUTE_MULTILIB hook to override multi-lib result Kito Cheng
@ 2021-07-21  9:28 ` Kito Cheng
  2021-09-01  0:22   ` Jim Wilson
  2022-09-09  7:20   ` Andreas Schwab
  2021-07-29 18:44 ` [PATCH 0/2] New target hook TARGET_COMPUTE_MULTILIB and implementation for RISC-V Kito Cheng
  2 siblings, 2 replies; 13+ messages in thread
From: Kito Cheng @ 2021-07-21  9:28 UTC (permalink / raw)
  To: gcc-patches, kito.cheng, jimw; +Cc: Kito Cheng

Use TARGET_COMPUTE_MULTILIB to search the multi-lib reuse for riscv*-*-elf*,
according following rules:

 1. Check ABI is same.
 2. Check both has atomic extension or both don't have atomic extension.
    - Because mix soft and hard atomic operation doesn't make sense and
      won't work as expect.
 3. Check current arch is superset of the target multi-lib arch.
    - It might result slower performance or larger code size, but it
      safe to run.
 4. Pick most match multi-lib set if more than one multi-lib are pass
    the above checking.

Example for how to select multi-lib:
  We build code with -march=rv32imaf and -mabi=ilp32, and we have
  following 5 multi-lib set:

    1. rv32ia/ilp32
    2. rv32ima/ilp32
    3. rv32imf/ilp32
    4. rv32imaf/ilp32f
    5. rv32imafd/ilp32

  The first and second multi-lib is safe to like, 3rd multi-lib can't
  re-use becasue it don't have atomic extension, which is mismatch according
  rule 2, and the 4th multi-lib can't re-use too due to the ABI mismatch,
  the last multi-lib can't use since current arch is not superset of the
  arch of multi-lib.

And emit error if not found suitable multi-lib set, the error message
only emit when link with standard libraries.

Example for when error will be emitted:

  $ riscv64-unknown-elf-gcc -print-multi-lib
  .;
  rv32i/ilp32;@march=rv32i@mabi=ilp32
  rv32im/ilp32;@march=rv32im@mabi=ilp32
  rv32iac/ilp32;@march=rv32iac@mabi=ilp32
  rv32imac/ilp32;@march=rv32imac@mabi=ilp32
  rv32imafc/ilp32f;@march=rv32imafc@mabi=ilp32f
  rv64imac/lp64;@march=rv64imac@mabi=lp64

  // No actual linking, so no error emitted.
  $ riscv64-unknown-elf-gcc -print-multi-directory -march=rv32ia -mabi=ilp32
  .

  // Link to default libc and libgcc, so check the multi-lib, and emit
  // error because not found suitable multilib.
  $ riscv64-unknown-elf-gcc -march=rv32ia -mabi=ilp32 ~/hello.c
  riscv64-unknown-elf-gcc: fatal error: can't found suitable multilib set for '-march=rv32ia'/'-mabi=ilp32'
  compilation terminated.

  // No error emitted, because not link to stdlib.
  $ riscv64-unknown-elf-gcc -march=rv32ia -mabi=ilp32 ~/hello.c -nostdlib

  // No error emitted, because compile only.
  $ riscv64-unknown-elf-gcc -march=rv32ia -mabi=ilp32 ~/hello.c -c

gcc/ChangeLog:

	* common/config/riscv/riscv-common.c: Include <vector>.
	(struct riscv_multi_lib_info_t): New.
	(riscv_subset_list::match_score): Ditto.
	(find_last_appear_switch): Ditto.
	(struct multi_lib_info_t): Ditto.
	(riscv_current_arch_str): Ditto.
	(riscv_current_abi_str): Ditto.
	(riscv_multi_lib_info_t::parse): Ditto.
	(riscv_check_cond): Ditto.
	(riscv_check_other_cond): Ditto.
	(riscv_compute_multilib): Ditto.
	(TARGET_COMPUTE_MULTILIB): Defined.
	* config/riscv/elf.h (LIB_SPEC): Call riscv_multi_lib_check if
	doing link.
	(RISCV_USE_CUSTOMISED_MULTI_LIB): New.
	* config/riscv/riscv.h (riscv_multi_lib_check): New.
	(EXTRA_SPEC_FUNCTIONS): Add riscv_multi_lib_check.
---
 gcc/common/config/riscv/riscv-common.c | 409 +++++++++++++++++++++++++
 gcc/config/riscv/elf.h                 |   6 +-
 gcc/config/riscv/riscv-subset.h        |   2 +
 gcc/config/riscv/riscv.h               |   4 +-
 4 files changed, 419 insertions(+), 2 deletions(-)

diff --git a/gcc/common/config/riscv/riscv-common.c b/gcc/common/config/riscv/riscv-common.c
index 10868fd417d..83819a7de6a 100644
--- a/gcc/common/config/riscv/riscv-common.c
+++ b/gcc/common/config/riscv/riscv-common.c
@@ -18,6 +18,7 @@ along with GCC; see the file COPYING3.  If not see
 <http://www.gnu.org/licenses/>.  */
 
 #include <sstream>
+#include <vector>
 
 #define INCLUDE_STRING
 #include "config.h"
@@ -122,6 +123,26 @@ const riscv_subset_list *riscv_current_subset_list ()
   return current_subset_list;
 }
 
+/* struct for recording multi-lib info.  */
+struct riscv_multi_lib_info_t {
+  std::string path;
+  std::string arch_str;
+  std::string abi_str;
+  std::string other_cond;
+  riscv_subset_list *subset_list;
+
+  static bool parse (struct riscv_multi_lib_info_t *,
+		     const std::string &,
+		     const std::string &);
+};
+
+/* Flag for checking if there is no suitable multi-lib found.  */
+static bool riscv_no_matched_multi_lib;
+
+/* Used for record value of -march and -mabi.  */
+static std::string riscv_current_arch_str;
+static std::string riscv_current_abi_str;
+
 riscv_subset_t::riscv_subset_t ()
   : name (), major_version (0), minor_version (0), next (NULL),
     explicit_version_p (false), implied_p (false)
@@ -147,6 +168,42 @@ riscv_subset_list::~riscv_subset_list ()
     }
 }
 
+/* Compute the match score of two arch string, return 0 if incompatible.  */
+int
+riscv_subset_list::match_score (riscv_subset_list *list) const
+{
+  riscv_subset_t *s;
+  int score = 0;
+  bool has_a_ext, list_has_a_ext;
+
+  /* Impossible to match if XLEN is different.  */
+  if (list->m_xlen != this->m_xlen)
+    return 0;
+
+  /* There is different code gen in libstdc++ and libatomic between w/ A-ext
+     and w/o A-ext, and it not work if using soft and hard atomic mechanism
+     at same time, so they are incompatible.  */
+  has_a_ext = this->lookup ("a") != NULL;
+  list_has_a_ext = list->lookup ("a") != NULL;
+
+  if (has_a_ext != list_has_a_ext)
+    return 0;
+
+
+  /* list must be subset of current this list, otherwise it not safe to
+     link.
+     TODO: We might give different weigth for each extension, but the rule could
+	   be complicated.
+     TODO: We might consider the version of each extension.  */
+  for (s = list->m_head; s != NULL; s = s->next)
+    if (this->lookup (s->name.c_str ()) != NULL)
+      score++;
+    else
+      return 0;
+
+  return score;
+}
+
 /* Get the rank for single-letter subsets, lower value meaning higher
    priority.  */
 
@@ -1054,6 +1111,358 @@ riscv_expand_arch_from_cpu (int argc ATTRIBUTE_UNUSED,
   return xasprintf ("-march=%s", arch.c_str());
 }
 
+/* Find last switch with the prefix, options are take last one in general,
+   return NULL if not found, and return the option value if found, it could
+   return empty string if the option has no value.  */
+
+static const char *
+find_last_appear_switch (
+  const struct switchstr *switches,
+  int n_switches,
+  const char *prefix)
+{
+  int i;
+  size_t len = strlen (prefix);
+
+  for (i = 0; i < n_switches; ++i) {
+    const struct switchstr *this_switch = &switches[n_switches - i - 1];
+
+    if (this_switch->live_cond & SWITCH_FALSE)
+      continue;
+
+    if (strncmp (this_switch->part1, prefix, len) == 0)
+      return this_switch->part1 + len;
+  }
+
+  return NULL;
+}
+
+/* Parse the path and cond string into riscv_multi_lib_info_t, return false
+   if parsing failed. */
+
+bool
+riscv_multi_lib_info_t::parse (
+  struct riscv_multi_lib_info_t *multi_lib_info,
+  const std::string &path,
+  const std::string &cond)
+{
+  const char *default_arch_str = STRINGIZING (TARGET_RISCV_DEFAULT_ARCH);
+  const char *default_abi_str = STRINGIZING (TARGET_RISCV_DEFAULT_ABI);
+  multi_lib_info->other_cond = cond;
+  if (path == ".")
+    {
+      multi_lib_info->arch_str = default_arch_str;
+      multi_lib_info->abi_str = default_abi_str;
+      multi_lib_info->subset_list =
+	riscv_subset_list::parse(
+	  STRINGIZING (TARGET_RISCV_DEFAULT_ARCH),
+	  input_location);
+    }
+  else
+    {
+      /* XXX: Maybe we should parse that from cond string rather than path.  */
+      /* The path rule for RISC-V multi-lib is <arch>/<abi>[/<others>].  */
+      size_t slash_pos = path.find ('/');
+
+      /* Parse failed if not found any `/`.  */
+      if (slash_pos == std::string::npos)
+	return false;
+
+      /* Seeking if there is other part in the path.  */
+      size_t end_of_abi = path.find ('/', slash_pos + 1);
+
+      multi_lib_info->arch_str = path.substr (0, slash_pos);
+      if (end_of_abi == std::string::npos) {
+	/* Only <arch>/<abi>.  */
+	multi_lib_info->abi_str = path.substr (slash_pos + 1,
+					       path.length () - 1);
+
+	/* Skip this multi-lib if this configuration is exactly same as
+	   default multi-lib settings.  */
+	if (multi_lib_info->arch_str == default_arch_str
+	    && multi_lib_info->abi_str == default_abi_str)
+	  return false;
+
+      } else
+	/* <arch>/<abi>/<others>....  */
+	multi_lib_info->abi_str = path.substr (slash_pos + 1,
+					       end_of_abi - slash_pos - 1);
+   }
+
+  multi_lib_info->subset_list =
+    riscv_subset_list::parse(multi_lib_info->arch_str.c_str (), input_location);
+
+  return true;
+}
+
+/* Report error if not found suitable multilib.  */
+const char *
+riscv_multi_lib_check (int argc ATTRIBUTE_UNUSED,
+		       const char **argv ATTRIBUTE_UNUSED)
+{
+  if (riscv_no_matched_multi_lib)
+    fatal_error (
+      input_location,
+      "Can't found suitable multilib set for %<-march=%s%>/%<-mabi=%s%>",
+      riscv_current_arch_str.c_str (),
+      riscv_current_abi_str.c_str ());
+
+  return "";
+}
+
+static bool
+riscv_check_cond (
+  const struct switchstr *switches,
+  int n_switches,
+  const std::string &arg,
+  bool not_arg)
+{
+  int i;
+  for (i = 0; i < n_switches; ++i) {
+    const struct switchstr *this_switch = &switches[n_switches - i - 1];
+
+    if ((this_switch->live_cond & SWITCH_IGNORE) != 0)
+      continue;
+
+    if (this_switch->live_cond & SWITCH_FALSE)
+      continue;
+
+    if (arg == this_switch->part1)
+      return not_arg ? false : true;
+  }
+
+  /* Not found this arg, that's ok!  */
+  return not_arg ? true : false;
+}
+
+/* Check the other cond is found or not, return    */
+
+static int
+riscv_check_other_cond (
+  const struct switchstr *switches,
+  int n_switches,
+  int match_score,
+  const std::string &other_cond)
+{
+  const char *p = other_cond.c_str ();
+  const char *this_arg;
+  std::string arg;
+  bool not_arg;
+  bool ok;
+  int ok_count = 0;
+
+  if (match_score == 0)
+    return 0;
+
+  while (*p != '\0')
+    {
+      while (*p == ' ') p++;
+      this_arg = p;
+      while (*p != ' ' && *p != '\0')
+	++p;
+
+      if (*this_arg != '!')
+	not_arg = false;
+      else
+	{
+	  not_arg = true;
+	  ++this_arg;
+	}
+
+      arg = std::string (this_arg, p - this_arg);
+
+      /* We might got empty arg when multi-lib is disabled.  */
+      if (arg.empty ())
+	continue;
+
+      ok = riscv_check_cond (switches, n_switches, arg, not_arg);
+
+      if (!ok)
+	return -1;
+
+      ok_count++;
+
+      if (*p == '\0') break;
+
+      p++;
+    }
+
+  /* 100 is magic number, it's just used for make sure this multi-lib has
+     higher priority if we found any some option is listed in the option check
+     list. */
+  return match_score + ok_count * 100;
+}
+
+/* We only override this in bare-matel toolchain.  */
+#ifdef RISCV_USE_CUSTOMISED_MULTI_LIB
+/* Implement TARGET_COMPUTE_MULTILIB.  */
+
+static const char *
+riscv_compute_multilib (
+  const struct switchstr *switches,
+  int n_switches,
+  const char *multilib_dir,
+  const char *multilib_defaults ATTRIBUTE_UNUSED,
+  const char *multilib_select,
+  const char *multilib_matches ATTRIBUTE_UNUSED,
+  const char *multilib_exclusions ATTRIBUTE_UNUSED,
+  const char *multilib_reuse ATTRIBUTE_UNUSED)
+{
+  const char *p, *tp;
+  const char *this_path;
+  const char *this_cond;
+  size_t this_path_len;
+  size_t this_cond_len;
+  size_t offset;
+  bool skip_until_blank;
+  bool result;
+  riscv_no_matched_multi_lib = false;
+  riscv_subset_list *subset_list = NULL;
+
+  std::vector<riscv_multi_lib_info_t> multilib_infos;
+  riscv_multi_lib_info_t multilib_info;
+
+  /* Already found suitable, multi-lib, just use that.  */
+  if (multilib_dir != NULL)
+    return multilib_dir;
+
+  /* Find last march.  */
+  riscv_current_arch_str =
+    find_last_appear_switch (switches, n_switches, "march=");
+  /* Find mabi.  */
+  riscv_current_abi_str =
+    find_last_appear_switch (switches, n_switches, "mabi=");
+
+  /* Failed to find -march or -mabi, but it should not happened since we have
+     set both in OPTION_DEFAULT_SPECS.  */
+  if (riscv_current_arch_str.empty () || riscv_current_abi_str.empty ())
+    return multilib_dir;
+
+  subset_list = riscv_subset_list::parse (riscv_current_arch_str.c_str (),
+					  input_location);
+
+  /* Failed to parse -march, fallback to using what gcc use.  */
+  if (subset_list == NULL)
+    return multilib_dir;
+
+  /* Parsing MULTILIB_SELECT, ignore MULTILIB_REUSE here, we have our own rules.
+     TODO: most codes are grab from gcc.c, maybe we should refine that?  */
+  p = multilib_select;
+
+  while (*p != '\0')
+    {
+      /* Ignore newlines.  */
+      if (*p == '\n')
+	{
+	  ++p;
+	  continue;
+	}
+
+      /* Get the initial path.  */
+      this_path = p;
+      while (*p != ' ')
+	{
+	  if (*p == '\0')
+	    {
+	      fatal_error (input_location, "multilib select %qs %qs is invalid",
+			   multilib_select, multilib_reuse);
+	    }
+	  ++p;
+	}
+      this_path_len = p - this_path;
+      multilib_info.path = std::string (this_path, this_path_len);
+
+      this_cond = p;
+      while (*p != ';')
+	{
+	  if (*p == '\0')
+	    {
+	      fatal_error (input_location, "multilib select %qs %qs is invalid",
+			   multilib_select, multilib_reuse);
+	    }
+	  ++p;
+	}
+
+      /* Ignore march or mabi option in cond string.  */
+      tp = this_cond;
+      skip_until_blank = false;
+
+      while (*tp != ';')
+	{
+	  offset = 0;
+	  if (*tp == '!')
+	    offset = 1;
+
+	  if (skip_until_blank && *tp == ' ')
+	    {
+	      skip_until_blank = false;
+	      this_cond = tp + 1;
+	    }
+
+	  if ((strncmp (tp + offset, "mabi", 4) == 0) ||
+	      (strncmp (tp + offset, "march", 5) == 0))
+	    skip_until_blank = true;
+
+	  ++tp;
+	}
+
+      if (skip_until_blank)
+	this_cond_len = 0;
+      else
+	this_cond_len = p - this_cond;
+
+      result =
+	riscv_multi_lib_info_t::parse (
+	  &multilib_info,
+	  std::string (this_path, this_path_len),
+	  std::string (this_cond, this_cond_len));
+
+      if (result)
+	multilib_infos.push_back (multilib_info);
+
+      p++;
+    }
+
+  int match_score = 0;
+  int max_match_score = 0;
+  int best_match_multi_lib = -1;
+  /* Try to decition which set we should used.  */
+  /* We have 3 level dection tree here, ABI, A-ext, check input arch/ABI must be
+     superset of multi-lib arch.  */
+  for (size_t i = 0; i < multilib_infos.size (); ++i)
+    {
+      /* Check ABI is same first.  */
+      if (riscv_current_abi_str != multilib_infos[i].abi_str)
+	continue;
+
+      /* Found a potential compatible multi-lib setting!
+	 Calculate the match score.  */
+      match_score = subset_list->match_score (multilib_infos[i].subset_list);
+
+      /* Checking other cond in the multi-lib setting.  */
+      match_score = riscv_check_other_cond (switches,
+					    n_switches,
+					    match_score,
+					    multilib_infos[i].other_cond);
+
+      /* Record highest match score multi-lib setting.  */
+      if (match_score > max_match_score)
+	best_match_multi_lib = i;
+    }
+
+  if (best_match_multi_lib == -1)
+    {
+      riscv_no_matched_multi_lib = true;
+      return multilib_dir;
+    }
+  else
+    return xstrdup (multilib_infos[best_match_multi_lib].path.c_str ());
+}
+
+#undef TARGET_COMPUTE_MULTILIB
+#define TARGET_COMPUTE_MULTILIB riscv_compute_multilib
+#endif
+
 
 /* Implement TARGET_OPTION_OPTIMIZATION_TABLE.  */
 static const struct default_options riscv_option_optimization_table[] =
diff --git a/gcc/config/riscv/elf.h b/gcc/config/riscv/elf.h
index 7e65e499031..cc0fd4d9de9 100644
--- a/gcc/config/riscv/elf.h
+++ b/gcc/config/riscv/elf.h
@@ -27,10 +27,14 @@ along with GCC; see the file COPYING3.  If not see
 /* Link against Newlib libraries, because the ELF backend assumes Newlib.
    Handle the circular dependence between libc and libgloss. */
 #undef  LIB_SPEC
-#define LIB_SPEC "--start-group -lc %{!specs=nosys.specs:-lgloss} --end-group"
+#define LIB_SPEC \
+  "--start-group -lc %{!specs=nosys.specs:-lgloss} --end-group " \
+  "%{!nostartfiles:%{!nodefaultlibs:%{!nolibc:%{!nostdlib:%:riscv_multi_lib_check()}}}}"
 
 #undef  STARTFILE_SPEC
 #define STARTFILE_SPEC "crt0%O%s crtbegin%O%s"
 
 #undef  ENDFILE_SPEC
 #define ENDFILE_SPEC "crtend%O%s"
+
+#define RISCV_USE_CUSTOMISED_MULTI_LIB 1
diff --git a/gcc/config/riscv/riscv-subset.h b/gcc/config/riscv/riscv-subset.h
index 793655a01f2..56bb4d0a7a1 100644
--- a/gcc/config/riscv/riscv-subset.h
+++ b/gcc/config/riscv/riscv-subset.h
@@ -88,6 +88,8 @@ public:
 
   const riscv_subset_t *begin () const {return m_head;};
   const riscv_subset_t *end () const {return NULL;};
+
+  int match_score (riscv_subset_list *) const;
 };
 
 extern const riscv_subset_list *riscv_current_subset_list (void);
diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h
index f47d5b40a66..4d8a4c76c1c 100644
--- a/gcc/config/riscv/riscv.h
+++ b/gcc/config/riscv/riscv.h
@@ -50,11 +50,13 @@ along with GCC; see the file COPYING3.  If not see
 extern const char *riscv_expand_arch (int argc, const char **argv);
 extern const char *riscv_expand_arch_from_cpu (int argc, const char **argv);
 extern const char *riscv_default_mtune (int argc, const char **argv);
+extern const char *riscv_multi_lib_check (int argc, const char **argv);
 
 # define EXTRA_SPEC_FUNCTIONS						\
   { "riscv_expand_arch", riscv_expand_arch },				\
   { "riscv_expand_arch_from_cpu", riscv_expand_arch_from_cpu },		\
-  { "riscv_default_mtune", riscv_default_mtune },
+  { "riscv_default_mtune", riscv_default_mtune },			\
+  { "riscv_multi_lib_check", riscv_multi_lib_check },
 
 /* Support for a compile-time default CPU, et cetera.  The rules are:
    --with-arch is ignored if -march or -mcpu is specified.
-- 
2.31.1


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 0/2] New target hook TARGET_COMPUTE_MULTILIB and implementation for RISC-V
  2021-07-21  9:28 [PATCH 0/2] New target hook TARGET_COMPUTE_MULTILIB and implementation for RISC-V Kito Cheng
  2021-07-21  9:28 ` [PATCH 1/2] Add TARGET_COMPUTE_MULTILIB hook to override multi-lib result Kito Cheng
  2021-07-21  9:28 ` [PATCH 2/2] RISC-V: Implement TARGET_COMPUTE_MULTILIB Kito Cheng
@ 2021-07-29 18:44 ` Kito Cheng
  2021-07-29 19:00   ` Palmer Dabbelt
  2 siblings, 1 reply; 13+ messages in thread
From: Kito Cheng @ 2021-07-29 18:44 UTC (permalink / raw)
  To: Kito Cheng; +Cc: GCC Patches, Jim Wilson

ping

On Wed, Jul 21, 2021 at 5:28 PM Kito Cheng <kito.cheng@sifive.com> wrote:
>
> This patch set allow target to use customized multi-lib mechanism rather than the built-in
> multi-lib mechanism.
>
> The motivation of this patch is RISC-V might have very complicated multi-lib re-use
> rule*, which is hard to maintain and use current multi-lib scripts,
> we even hit the "argument list too long" error when we tried to add more
> multi-lib reuse rule.
>
> * Here is an example for RISC-V multi-lib rules:
> https://gist.github.com/kito-cheng/0289cd42d9a756382e5afeb77b42b73b
>
> V2 Changes:
> - NO changes for first patch(TARGET_COMPUTE_MULTILIB part) since first version.
> - Handle option other than -march and -mabi for riscv_compute_multilib.
>
>

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 0/2] New target hook TARGET_COMPUTE_MULTILIB and implementation for RISC-V
  2021-07-29 18:44 ` [PATCH 0/2] New target hook TARGET_COMPUTE_MULTILIB and implementation for RISC-V Kito Cheng
@ 2021-07-29 19:00   ` Palmer Dabbelt
  2022-09-02  9:28     ` Kito Cheng
  0 siblings, 1 reply; 13+ messages in thread
From: Palmer Dabbelt @ 2021-07-29 19:00 UTC (permalink / raw)
  To: gcc-patches; +Cc: kito.cheng, gcc-patches

On Thu, 29 Jul 2021 11:44:09 PDT (-0700), gcc-patches@gcc.gnu.org wrote:
> ping
>
> On Wed, Jul 21, 2021 at 5:28 PM Kito Cheng <kito.cheng@sifive.com> wrote:
>>
>> This patch set allow target to use customized multi-lib mechanism rather than the built-in
>> multi-lib mechanism.
>>
>> The motivation of this patch is RISC-V might have very complicated multi-lib re-use
>> rule*, which is hard to maintain and use current multi-lib scripts,
>> we even hit the "argument list too long" error when we tried to add more
>> multi-lib reuse rule.
>>
>> * Here is an example for RISC-V multi-lib rules:
>> https://gist.github.com/kito-cheng/0289cd42d9a756382e5afeb77b42b73b
>>
>> V2 Changes:
>> - NO changes for first patch(TARGET_COMPUTE_MULTILIB part) since first version.
>> - Handle option other than -march and -mabi for riscv_compute_multilib.

This generally LGTM, but I think it's the sort of thing that should be 
looked at by a global reviewer.  There's a bit of a policy decision 
being made here in that this allows external hooks during the build 
process.

I'm fine with this, as it's just the multilib list, those are really 
specific to a specific toolchain distribution, and there's never going 
to be a way to catalog all the interested cases for the embedded 
toolchains.  I'm still not comfortable calling that a review, though, as 
these things are subtle and I don't always have the same bar for 
external bits that the rest of the GCC folks do.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 1/2] Add TARGET_COMPUTE_MULTILIB hook to override multi-lib result.
  2021-07-21  9:28 ` [PATCH 1/2] Add TARGET_COMPUTE_MULTILIB hook to override multi-lib result Kito Cheng
@ 2021-09-01  0:16   ` Jim Wilson
  0 siblings, 0 replies; 13+ messages in thread
From: Jim Wilson @ 2021-09-01  0:16 UTC (permalink / raw)
  To: Kito Cheng; +Cc: GCC Patches, Kito Cheng

On Wed, Jul 21, 2021 at 2:28 AM Kito Cheng <kito.cheng@sifive.com> wrote:

> Create a new hook to let target could override the multi-lib result,
> the motivation is RISC-V might have very complicated multi-lib re-use
> rule*, which is hard to maintain and use current multi-lib scripts,
> we even hit the "argument list too long" error when we tried to add more
> multi-lib reuse rule.
>

This looks OK to me, though I would rewrite the docs a bit.

> +DEFHOOK
> +(compute_multilib,
> + "Some target like RISC-V might have complicated multilib reuse rule
> which is\
> +  hard to implemented on current multilib scheme, this hook allow target
> to\
> +  override the result from built-in multilib mechanism.\
> +  @var{switches} is the raw option list with @var{n_switches} items;\
> +  @var{multilib_dir} is the multi-lib result which compute by the
> built-in\
> +  multi-lib mechanism;\
> +  @var{multilib_defaults} is the default options list for multi-lib; \
> +  @var{multilib_select} is the string contain the list of supported
> multi-lib, \
> +  and the option checking list. \
> +  @var{multilib_matches}, @var{multilib_exclusions}, and
> @var{multilib_reuse} \
> +  are corresponding to @var{MULTILIB_MATCHES}, @var{MULTILIB_EXCLUSIONS} \
> +  @var{MULTILIB_REUSE}. \
> +  The default definition does nothing but return @var{multilib_dir}
> directly.",
>

I'd suggest instead

"Some targets like RISC-V might have complicated multilib reuse rules
which\n\
are hard to implement with the current multilib scheme.  This hook allows\n\
targets to override the result from the built-in multilib mechanism.\n\
@var{switches} is the raw option list with @var{n_switches} items;\n\
@var{multilib_dir} is the multi-lib result which is computed by the
built-in\n\
multi-lib mechanism;\n\
@var{multilib_defaults} is the default options list for multi-lib;\n\
@var{multilib_select} is the string containing the list of supported\n\
multi-libs, and the option checking list.\n\
@var{multilib_matches}, @var{multilib_exclusions}, and
@var{multilib_reuse}\n\
are corresponding to @var{MULTILIB_MATCHES}, @var{MULTILIB_EXCLUSIONS},\n\
and @var{MULTILIB_REUSE}.\n\
The default definition does nothing but return @var{multilib_dir} directly."

Jim

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 2/2] RISC-V: Implement TARGET_COMPUTE_MULTILIB
  2021-07-21  9:28 ` [PATCH 2/2] RISC-V: Implement TARGET_COMPUTE_MULTILIB Kito Cheng
@ 2021-09-01  0:22   ` Jim Wilson
  2021-09-01  0:23     ` Jim Wilson
  2021-09-16  4:12     ` Kito Cheng
  2022-09-09  7:20   ` Andreas Schwab
  1 sibling, 2 replies; 13+ messages in thread
From: Jim Wilson @ 2021-09-01  0:22 UTC (permalink / raw)
  To: Kito Cheng; +Cc: GCC Patches, Kito Cheng

On Wed, Jul 21, 2021 at 2:28 AM Kito Cheng <kito.cheng@sifive.com> wrote:

> Use TARGET_COMPUTE_MULTILIB to search the multi-lib reuse for
> riscv*-*-elf*,
> according following rules:
>

I find the other_cond support a bit confusing.  Is this for -mcmodel
perhaps?  Why not just say that if so?

match_score:
weigth -> weight

riscv_multi_lib_info_t::parse
Calls riscv_subset_list::parse twice when path == ".", the call inside
the if looks unnecessary.

riscv_multilib_lib_check:
Can't found -> Can't find

riscv_check_other_cond:
might got -> might get

riscv_compute_multilib:
bare-matel -> bare-metal
decition -> decision
dection -> decision

It isn't clear how the loop with the comment "ignore march and mabi option
in cond string" can work.  It looks like it computes other_cond, but
assumes that there is at most one other_cond, and that it is always at the
end of the list since otherwise the length won't be computed correctly.
But it doesn't check these constraints.  Do you have examples showing how
this works?
  And maybe a little better commentary explaining what this loop does to
make it easier to understand.  It doesn't mention that it computes
other_cond for instance.

Jim

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 2/2] RISC-V: Implement TARGET_COMPUTE_MULTILIB
  2021-09-01  0:22   ` Jim Wilson
@ 2021-09-01  0:23     ` Jim Wilson
  2021-09-16  4:12     ` Kito Cheng
  1 sibling, 0 replies; 13+ messages in thread
From: Jim Wilson @ 2021-09-01  0:23 UTC (permalink / raw)
  To: Kito Cheng; +Cc: GCC Patches, Kito Cheng

On Tue, Aug 31, 2021 at 5:22 PM Jim Wilson <jimw@sifive.com> wrote:

> On Wed, Jul 21, 2021 at 2:28 AM Kito Cheng <kito.cheng@sifive.com> wrote:
>
>> Use TARGET_COMPUTE_MULTILIB to search the multi-lib reuse for
>> riscv*-*-elf*,
>> according following rules:
>>
>
> I find the other_cond support a bit confusing.  Is this for -mcmodel
> perhaps?  Why not just say that if so?
>
> match_score:
> weigth -> weight
>
> riscv_multi_lib_info_t::parse
> Calls riscv_subset_list::parse twice when path == ".", the call inside
> the if looks unnecessary.
>
> riscv_multilib_lib_check:
> Can't found -> Can't find
>
> riscv_check_other_cond:
> might got -> might get
>
> riscv_compute_multilib:
> bare-matel -> bare-metal
> decition -> decision
> dection -> decision
>
> It isn't clear how the loop with the comment "ignore march and mabi
> option in cond string" can work.  It looks like it computes other_cond,
> but assumes that there is at most one other_cond, and that it is always
> at the end of the list since otherwise the length won't be computed
> correctly.  But it doesn't check these constraints.  Do you have examples
> showing how this works?
>   And maybe a little better commentary explaining what this loop does to
> make it easier to understand.  It doesn't mention that it computes
> other_cond for instance.
>

Otherwise it looks OK to me.

Jim

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 2/2] RISC-V: Implement TARGET_COMPUTE_MULTILIB
  2021-09-01  0:22   ` Jim Wilson
  2021-09-01  0:23     ` Jim Wilson
@ 2021-09-16  4:12     ` Kito Cheng
  1 sibling, 0 replies; 13+ messages in thread
From: Kito Cheng @ 2021-09-16  4:12 UTC (permalink / raw)
  To: Jim Wilson; +Cc: Kito Cheng, GCC Patches

> I find the other_cond support a bit confusing.  Is this for -mcmodel
> perhaps?  Why not just say that if so?

I suppose we might have other multilib options other than -march,
-mabi and -mcmodel,
so I keep the flexibility here.

> riscv_multi_lib_info_t::parse
> Calls riscv_subset_list::parse twice when path == ".", the call inside
> the if looks unnecessary.

Thanks, good catch !

> It isn't clear how the loop with the comment "ignore march and mabi option
> in cond string" can work.  It looks like it computes other_cond, but
> assumes that there is at most one other_cond, and that it is always at the
> end of the list since otherwise the length won't be computed correctly.
> But it doesn't check these constraints.  Do you have examples showing how
> this works?
>   And maybe a little better commentary explaining what this loop does to
> make it easier to understand.  It doesn't mention that it computes
> other_cond for instance.

Seriously, I also spend some time remembering what they are doing...so
I rewrite that to make that easier to understand instead of copying
gcc.c if possible.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 0/2] New target hook TARGET_COMPUTE_MULTILIB and implementation for RISC-V
  2021-07-29 19:00   ` Palmer Dabbelt
@ 2022-09-02  9:28     ` Kito Cheng
  0 siblings, 0 replies; 13+ messages in thread
From: Kito Cheng @ 2022-09-02  9:28 UTC (permalink / raw)
  To: Palmer Dabbelt; +Cc: GCC Patches, Kito Cheng

Got Jim's review and approval before, but apparently we missed this
last year, rebase and committed to trunk.


On Fri, Jul 30, 2021 at 3:01 AM Palmer Dabbelt <palmer@dabbelt.com> wrote:
>
> On Thu, 29 Jul 2021 11:44:09 PDT (-0700), gcc-patches@gcc.gnu.org wrote:
> > ping
> >
> > On Wed, Jul 21, 2021 at 5:28 PM Kito Cheng <kito.cheng@sifive.com> wrote:
> >>
> >> This patch set allow target to use customized multi-lib mechanism rather than the built-in
> >> multi-lib mechanism.
> >>
> >> The motivation of this patch is RISC-V might have very complicated multi-lib re-use
> >> rule*, which is hard to maintain and use current multi-lib scripts,
> >> we even hit the "argument list too long" error when we tried to add more
> >> multi-lib reuse rule.
> >>
> >> * Here is an example for RISC-V multi-lib rules:
> >> https://gist.github.com/kito-cheng/0289cd42d9a756382e5afeb77b42b73b
> >>
> >> V2 Changes:
> >> - NO changes for first patch(TARGET_COMPUTE_MULTILIB part) since first version.
> >> - Handle option other than -march and -mabi for riscv_compute_multilib.
>
> This generally LGTM, but I think it's the sort of thing that should be
> looked at by a global reviewer.  There's a bit of a policy decision
> being made here in that this allows external hooks during the build
> process.
>
> I'm fine with this, as it's just the multilib list, those are really
> specific to a specific toolchain distribution, and there's never going
> to be a way to catalog all the interested cases for the embedded
> toolchains.  I'm still not comfortable calling that a review, though, as
> these things are subtle and I don't always have the same bar for
> external bits that the rest of the GCC folks do.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 2/2] RISC-V: Implement TARGET_COMPUTE_MULTILIB
  2021-07-21  9:28 ` [PATCH 2/2] RISC-V: Implement TARGET_COMPUTE_MULTILIB Kito Cheng
  2021-09-01  0:22   ` Jim Wilson
@ 2022-09-09  7:20   ` Andreas Schwab
  2022-09-09  9:58     ` Kito Cheng
  1 sibling, 1 reply; 13+ messages in thread
From: Andreas Schwab @ 2022-09-09  7:20 UTC (permalink / raw)
  To: Kito Cheng; +Cc: gcc-patches, kito.cheng, jimw

How did you test that?

../../gcc/common/config/riscv/riscv-common.cc: In function 'const char* riscv_multi_lib_check(int, const char**)':
../../gcc/common/config/riscv/riscv-common.cc:1451:11: error: bare apostrophe ''' in format [-Werror=format-diag]
 1451 |       "Can't find suitable multilib set for %<-march=%s%>/%<-mabi=%s%>",
      |           ^
../../gcc/common/config/riscv/riscv-common.cc:1451:7: note: if avoiding the apostrophe is not feasible, enclose it in a pair of '%<' and '%>' directives instead
 1451 |       "Can't find suitable multilib set for %<-march=%s%>/%<-mabi=%s%>",
      |       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../../gcc/common/config/riscv/riscv-common.cc: At global scope:
../../gcc/common/config/riscv/riscv-common.cc:1492:1: error: 'int riscv_check_conds(const switchstr*, int, int, const std::vector<std::__cxx11::basic_string<char> >&)' defined but not used [-Werror=unused-function]
 1492 | riscv_check_conds (
      | ^~~~~~~~~~~~~~~~~
../../gcc/common/config/riscv/riscv-common.cc:1374:1: error: 'const char* find_last_appear_switch(const switchstr*, int, const char*)' defined but not used [-Werror=unused-function]
 1374 | find_last_appear_switch (
      | ^~~~~~~~~~~~~~~~~~~~~~~
cc1plus: all warnings being treated as errors
make[3]: *** [Makefile:2442: riscv-common.o] Error 1

-- 
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 7578 EB47 D4E5 4D69 2510  2552 DF73 E780 A9DA AEC1
"And now for something completely different."

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 2/2] RISC-V: Implement TARGET_COMPUTE_MULTILIB
  2022-09-09  7:20   ` Andreas Schwab
@ 2022-09-09  9:58     ` Kito Cheng
  0 siblings, 0 replies; 13+ messages in thread
From: Kito Cheng @ 2022-09-09  9:58 UTC (permalink / raw)
  To: Andreas Schwab; +Cc: Kito Cheng, GCC Patches

Hi Andreas:

Hmmmmm, I should change my default gcc on Ubuntu, I didn't got this
when build with GCC 7, and can be reproduced by GCC 11,

Will summit patch once I test done.

On Fri, Sep 9, 2022 at 3:21 PM Andreas Schwab <schwab@linux-m68k.org> wrote:
>
> How did you test that?
>
> ../../gcc/common/config/riscv/riscv-common.cc: In function 'const char* riscv_multi_lib_check(int, const char**)':
> ../../gcc/common/config/riscv/riscv-common.cc:1451:11: error: bare apostrophe ''' in format [-Werror=format-diag]
>  1451 |       "Can't find suitable multilib set for %<-march=%s%>/%<-mabi=%s%>",
>       |           ^
> ../../gcc/common/config/riscv/riscv-common.cc:1451:7: note: if avoiding the apostrophe is not feasible, enclose it in a pair of '%<' and '%>' directives instead
>  1451 |       "Can't find suitable multilib set for %<-march=%s%>/%<-mabi=%s%>",
>       |       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> ../../gcc/common/config/riscv/riscv-common.cc: At global scope:
> ../../gcc/common/config/riscv/riscv-common.cc:1492:1: error: 'int riscv_check_conds(const switchstr*, int, int, const std::vector<std::__cxx11::basic_string<char> >&)' defined but not used [-Werror=unused-function]
>  1492 | riscv_check_conds (
>       | ^~~~~~~~~~~~~~~~~
> ../../gcc/common/config/riscv/riscv-common.cc:1374:1: error: 'const char* find_last_appear_switch(const switchstr*, int, const char*)' defined but not used [-Werror=unused-function]
>  1374 | find_last_appear_switch (
>       | ^~~~~~~~~~~~~~~~~~~~~~~
> cc1plus: all warnings being treated as errors
> make[3]: *** [Makefile:2442: riscv-common.o] Error 1
>
> --
> Andreas Schwab, schwab@linux-m68k.org
> GPG Key fingerprint = 7578 EB47 D4E5 4D69 2510  2552 DF73 E780 A9DA AEC1
> "And now for something completely different."

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH 2/2] RISC-V: Implement TARGET_COMPUTE_MULTILIB
  2020-12-01  9:29 [PATCH 1/2] Add TARGET_COMPUTE_MULTILIB hook to override multi-lib result Kito Cheng
@ 2020-12-01  9:29 ` Kito Cheng
  0 siblings, 0 replies; 13+ messages in thread
From: Kito Cheng @ 2020-12-01  9:29 UTC (permalink / raw)
  To: gcc-patches, kito.cheng, jimw; +Cc: Kito Cheng

Use TARGET_COMPUTE_MULTILIB to search the multi-lib reuse for riscv*-*-elf*,
according following rules:

 1. Check ABI is same.
 2. Check both has atomic extension or both don't have atomic extension.
    - Because mix soft and hard atomic operation doesn't make sense and
      won't work as expect.
 3. Check current arch is superset of the target multi-lib arch.
    - It might result slower performance or larger code size, but it
      safe to run.
 4. Pick most match multi-lib set if more than one multi-lib are pass
    the above checking.

Example for how to select multi-lib:
  We build code with -march=rv32imaf and -mabi=ilp32, and we have
  following 5 multi-lib set:

    1. rv32ia/ilp32
    2. rv32ima/ilp32
    3. rv32imf/ilp32
    4. rv32imaf/ilp32f
    5. rv32imafd/ilp32

  The first and second multi-lib is safe to like, 3rd multi-lib can't
  re-use becasue it don't have atomic extension, which is mismatch according
  rule 2, and the 4th multi-lib can't re-use too due to the ABI mismatch,
  the last multi-lib can't use since current arch is not superset of the
  arch of multi-lib.

And emit error if not found suitable multi-lib set, the error message
only emit when link with standard libraries.

Example for when error will be emitted:

  $ riscv64-unknown-elf-gcc -print-multi-lib
  .;
  rv32i/ilp32;@march=rv32i@mabi=ilp32
  rv32im/ilp32;@march=rv32im@mabi=ilp32
  rv32iac/ilp32;@march=rv32iac@mabi=ilp32
  rv32imac/ilp32;@march=rv32imac@mabi=ilp32
  rv32imafc/ilp32f;@march=rv32imafc@mabi=ilp32f
  rv64imac/lp64;@march=rv64imac@mabi=lp64

  // No actual linking, so no error emitted.
  $ riscv64-unknown-elf-gcc -print-multi-directory -march=rv32ia -mabi=ilp32
  .

  // Link to default libc and libgcc, so check the multi-lib, and emit
  // error because not found suitable multilib.
  $ riscv64-unknown-elf-gcc -march=rv32ia -mabi=ilp32 ~/hello.c
  riscv64-unknown-elf-gcc: fatal error: can't found suitable multilib set for '-march=rv32ia'/'-mabi=ilp32'
  compilation terminated.

  // No error emitted, because not link to stdlib.
  $ riscv64-unknown-elf-gcc -march=rv32ia -mabi=ilp32 ~/hello.c -nostdlib

  // No error emitted, because compile only.
  $ riscv64-unknown-elf-gcc -march=rv32ia -mabi=ilp32 ~/hello.c -c

gcc/ChangeLog:

	* common/config/riscv/riscv-common.c (riscv_subset_list::match_score):
	New.
	(find_last_appear_switch): Ditto.
	(struct multi_lib_info_t): Ditto.
	(riscv_no_matched_multi_lib): Ditto.
	(riscv_current_arch_str): Ditto.
	(riscv_current_abi_str): Ditto.
	(riscv_compute_multilib): Ditto.
	(TARGET_COMPUTE_MULTILIB): Defined.
	* config/riscv/elf.h (LIB_SPEC): Call riscv_multi_lib_check if
	doing link.
	(RISCV_USE_CUSTOMISED_MULTI_LIB): New.
	* config/riscv/riscv.h (riscv_multi_lib_check): New.
	(EXTRA_SPEC_FUNCTIONS): Add riscv_multi_lib_check.
---
 gcc/common/config/riscv/riscv-common.c | 253 +++++++++++++++++++++++++
 gcc/config/riscv/elf.h                 |   6 +-
 gcc/config/riscv/riscv.h               |   4 +-
 3 files changed, 261 insertions(+), 2 deletions(-)

diff --git a/gcc/common/config/riscv/riscv-common.c b/gcc/common/config/riscv/riscv-common.c
index 5e3ddcf3f81..481f0be9944 100644
--- a/gcc/common/config/riscv/riscv-common.c
+++ b/gcc/common/config/riscv/riscv-common.c
@@ -30,6 +30,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "flags.h"
 #include "diagnostic-core.h"
 #include "config/riscv/riscv-protos.h"
+#include <vector>
 
 #define RISCV_DONT_CARE_VERSION -1
 
@@ -171,12 +172,31 @@ public:
 
   static riscv_subset_list *parse (const char *, location_t);
 
+  int match_score (riscv_subset_list *) const;
 };
 
 static const char *riscv_supported_std_ext (void);
 
 static riscv_subset_list *current_subset_list = NULL;
 
+/* struct for recording multi-lib info.  */
+struct riscv_multi_lib_info_t {
+  std::string path;
+  std::string arch_str;
+  std::string abi_str;
+  riscv_subset_list *subset_list;
+
+  static bool parse (struct riscv_multi_lib_info_t *,
+		     const std::string &);
+};
+
+/* Flag for checking if there is no suitable multi-lib found.  */
+static bool riscv_no_matched_multi_lib;
+
+/* Used for record value of -march and -mabi.  */
+static std::string riscv_current_arch_str;
+static std::string riscv_current_abi_str;
+
 riscv_subset_t::riscv_subset_t ()
   : name (), major_version (0), minor_version (0), next (NULL),
     explicit_version_p (false), implied_p (false)
@@ -202,6 +222,42 @@ riscv_subset_list::~riscv_subset_list ()
     }
 }
 
+/* Compute the match score of two arch string, return 0 if incompatible.  */
+int
+riscv_subset_list::match_score (riscv_subset_list *list) const
+{
+  riscv_subset_t *s;
+  int score = 0;
+  bool has_a_ext, list_has_a_ext;
+
+  /* Impossible to match if XLEN is different.  */
+  if (list->m_xlen != this->m_xlen)
+    return 0;
+
+  /* There is different code gen in libstdc++ and libatomic between w/ A-ext
+     and w/o A-ext, and it not work if using soft and hard atomic mechanism
+     at same time, so they are incompatible.  */
+  has_a_ext = this->lookup ("a") != NULL;
+  list_has_a_ext = list->lookup ("a") != NULL;
+
+  if (has_a_ext != list_has_a_ext)
+    return 0;
+
+
+  /* list must be subset of current this list, otherwise it not safe to
+     link.
+     TODO: We might give different weigth for each extension, but the rule could
+	   be complicated.
+     TODO: We might consider the version of each extension.  */
+  for (s = list->m_head; s != NULL; s = s->next)
+    if (this->lookup (s->name.c_str ()) != NULL)
+      score++;
+    else
+      return 0;
+
+  return score;
+}
+
 /* Get the rank for single-letter subsets, lower value meaning higher
    priority.  */
 
@@ -1109,6 +1165,203 @@ riscv_expand_arch_from_cpu (int argc ATTRIBUTE_UNUSED,
   return xasprintf ("-march=%s", arch.c_str());
 }
 
+static const char *
+find_last_appear_switch (
+  const struct switchstr *switches,
+  int n_switches,
+  const char *prefix)
+{
+  int i;
+  size_t len = strlen (prefix);
+
+  for (i = 0; i < n_switches; ++i) {
+    const struct switchstr *this_switch = &switches[n_switches - i - 1];
+
+    if (this_switch->live_cond & SWITCH_FALSE)
+      continue;
+
+    if (strncmp (this_switch->part1, prefix, len) == 0)
+      return this_switch->part1 + len;
+  }
+
+  return NULL;
+}
+
+bool
+riscv_multi_lib_info_t::parse (
+  struct riscv_multi_lib_info_t *multi_lib_info,
+  const std::string &path)
+{
+  if (path == ".")
+    {
+      multi_lib_info->arch_str = STRINGIZING (TARGET_RISCV_DEFAULT_ARCH);
+      multi_lib_info->abi_str = STRINGIZING (TARGET_RISCV_DEFAULT_ABI);
+      multi_lib_info->subset_list =
+	riscv_subset_list::parse(
+	  STRINGIZING (TARGET_RISCV_DEFAULT_ARCH),
+	  input_location);
+    }
+  else
+    {
+      size_t slash_pos = path.find('/');
+
+      if (slash_pos == std::string::npos)
+	return false;
+
+      multi_lib_info->arch_str = path.substr(0, slash_pos);
+      multi_lib_info->abi_str = path.substr(slash_pos + 1, path.length() - 1);
+   }
+
+  multi_lib_info->subset_list =
+    riscv_subset_list::parse(multi_lib_info->arch_str.c_str (), input_location);
+
+  return true;
+}
+
+const char *
+riscv_multi_lib_check (int argc ATTRIBUTE_UNUSED,
+		       const char **argv ATTRIBUTE_UNUSED)
+{
+  if (riscv_no_matched_multi_lib)
+    fatal_error (
+      input_location,
+      "Can't found suitable multilib set for %<-march=%s%>/%<-mabi=%s%>",
+      riscv_current_arch_str.c_str (),
+      riscv_current_abi_str.c_str ());
+
+  return "";
+}
+
+/* We only override this in bare-matel toolchain.  */
+#ifdef RISCV_USE_CUSTOMISED_MULTI_LIB
+/* Implement TARGET_COMPUTE_MULTILIB.  */
+
+static const char *
+riscv_compute_multilib (
+  const struct switchstr *switches,
+  int n_switches,
+  const char *multilib_dir,
+  const char *multilib_defaults ATTRIBUTE_UNUSED,
+  const char *multilib_select,
+  const char *multilib_matches ATTRIBUTE_UNUSED,
+  const char *multilib_exclusions ATTRIBUTE_UNUSED,
+  const char *multilib_reuse ATTRIBUTE_UNUSED)
+{
+  const char *p;
+  const char *this_path;
+  size_t this_path_len;
+  bool result;
+  riscv_no_matched_multi_lib = false;
+  riscv_subset_list *subset_list = NULL;
+
+  std::vector<riscv_multi_lib_info_t> multilib_infos;
+  riscv_multi_lib_info_t multilib_info;
+
+  /* Already found suitable, multi-lib, just use that.  */
+  if (multilib_dir != NULL)
+    return multilib_dir;
+
+  /* Find last march.  */
+  riscv_current_arch_str =
+    find_last_appear_switch (switches, n_switches, "march=");
+  /* Find mabi.  */
+  riscv_current_abi_str =
+    find_last_appear_switch (switches, n_switches, "mabi=");
+
+  /* Failed to find -march or -mabi, but it should not happened since we have
+     set both in OPTION_DEFAULT_SPECS.  */
+  if (riscv_current_arch_str.empty () || riscv_current_abi_str.empty ())
+    return multilib_dir;
+
+  subset_list = riscv_subset_list::parse (riscv_current_arch_str.c_str (),
+					  input_location);
+
+  /* Failed to parse -march, fallback to using what gcc use.  */
+  if (subset_list == NULL)
+    return multilib_dir;
+
+  /* Parsing MULTILIB_SELECT, ignore MULTILIB_REUSE here, we have our own rules.
+     TODO: most codes are grab from gcc.c, maybe we should refine that?  */
+  p = multilib_select;
+
+  while (*p != '\0')
+    {
+      /* Ignore newlines.  */
+      if (*p == '\n')
+	{
+	  ++p;
+	  continue;
+	}
+
+      /* Get the initial path.  */
+      this_path = p;
+      while (*p != ' ')
+	{
+	  if (*p == '\0')
+	    {
+	      fatal_error (input_location, "multilib select %qs %qs is invalid",
+			   multilib_select, multilib_reuse);
+	    }
+	  ++p;
+	}
+      this_path_len = p - this_path;
+      multilib_info.path = std::string (this_path, this_path_len);
+
+      while (*p != ';')
+	{
+	  if (*p == '\0')
+	    {
+	      fatal_error (input_location, "multilib select %qs %qs is invalid",
+			   multilib_select, multilib_reuse);
+	    }
+	  ++p;
+	}
+
+      result =
+	riscv_multi_lib_info_t::parse (
+	  &multilib_info,
+	  std::string (this_path, this_path_len));
+
+      if (result)
+	multilib_infos.push_back (multilib_info);
+
+      p++;
+    }
+
+  int match_score = 0;
+  int max_match_score = 0;
+  int best_match_multi_lib = -1;
+  /* Try to decition which set we should used.  */
+  /* We have 3 level dection tree here, ABI, A-ext, check input arch/ABI must be
+     superset of multi-lib arch.  */
+  for (size_t i = 0; i < multilib_infos.size (); ++i)
+    {
+      /* Check ABI is same first.  */
+      if (riscv_current_abi_str != multilib_infos[i].abi_str)
+	continue;
+
+      /* Found a potential compatible multi-lib setting!
+	 Calculate the match score.  */
+      match_score = subset_list->match_score (multilib_infos[i].subset_list);
+
+      /* Record highest match score multi-lib setting.  */
+      if (match_score > max_match_score)
+	best_match_multi_lib = i;
+    }
+
+  if (best_match_multi_lib == -1)
+    {
+      riscv_no_matched_multi_lib = true;
+      return multilib_dir;
+    }
+  else
+    return xstrdup (multilib_infos[best_match_multi_lib].path.c_str ());
+}
+
+#undef TARGET_COMPUTE_MULTILIB
+#define TARGET_COMPUTE_MULTILIB riscv_compute_multilib
+#endif
+
 
 /* Implement TARGET_OPTION_OPTIMIZATION_TABLE.  */
 static const struct default_options riscv_option_optimization_table[] =
diff --git a/gcc/config/riscv/elf.h b/gcc/config/riscv/elf.h
index 4e2d6464d02..4aeb7d6141c 100644
--- a/gcc/config/riscv/elf.h
+++ b/gcc/config/riscv/elf.h
@@ -25,10 +25,14 @@ along with GCC; see the file COPYING3.  If not see
 /* Link against Newlib libraries, because the ELF backend assumes Newlib.
    Handle the circular dependence between libc and libgloss. */
 #undef  LIB_SPEC
-#define LIB_SPEC "--start-group -lc %{!specs=nosys.specs:-lgloss} --end-group"
+#define LIB_SPEC \
+  "--start-group -lc %{!specs=nosys.specs:-lgloss} --end-group " \
+  "%{!nostartfiles:%{!nodefaultlibs:%{!nolibc:%{!nostdlib:%:riscv_multi_lib_check()}}}}"
 
 #undef  STARTFILE_SPEC
 #define STARTFILE_SPEC "crt0%O%s crtbegin%O%s"
 
 #undef  ENDFILE_SPEC
 #define ENDFILE_SPEC "crtend%O%s"
+
+#define RISCV_USE_CUSTOMISED_MULTI_LIB 1
diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h
index df3003fbaa0..a92e0e220ad 100644
--- a/gcc/config/riscv/riscv.h
+++ b/gcc/config/riscv/riscv.h
@@ -43,11 +43,13 @@ along with GCC; see the file COPYING3.  If not see
 extern const char *riscv_expand_arch (int argc, const char **argv);
 extern const char *riscv_expand_arch_from_cpu (int argc, const char **argv);
 extern const char *riscv_default_mtune (int argc, const char **argv);
+extern const char *riscv_multi_lib_check (int argc, const char **argv);
 
 # define EXTRA_SPEC_FUNCTIONS						\
   { "riscv_expand_arch", riscv_expand_arch },				\
   { "riscv_expand_arch_from_cpu", riscv_expand_arch_from_cpu },		\
-  { "riscv_default_mtune", riscv_default_mtune },
+  { "riscv_default_mtune", riscv_default_mtune },			\
+  { "riscv_multi_lib_check", riscv_multi_lib_check },
 
 /* Support for a compile-time default CPU, et cetera.  The rules are:
    --with-arch is ignored if -march or -mcpu is specified.
-- 
2.29.2


^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2022-09-09  9:58 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-07-21  9:28 [PATCH 0/2] New target hook TARGET_COMPUTE_MULTILIB and implementation for RISC-V Kito Cheng
2021-07-21  9:28 ` [PATCH 1/2] Add TARGET_COMPUTE_MULTILIB hook to override multi-lib result Kito Cheng
2021-09-01  0:16   ` Jim Wilson
2021-07-21  9:28 ` [PATCH 2/2] RISC-V: Implement TARGET_COMPUTE_MULTILIB Kito Cheng
2021-09-01  0:22   ` Jim Wilson
2021-09-01  0:23     ` Jim Wilson
2021-09-16  4:12     ` Kito Cheng
2022-09-09  7:20   ` Andreas Schwab
2022-09-09  9:58     ` Kito Cheng
2021-07-29 18:44 ` [PATCH 0/2] New target hook TARGET_COMPUTE_MULTILIB and implementation for RISC-V Kito Cheng
2021-07-29 19:00   ` Palmer Dabbelt
2022-09-02  9:28     ` Kito Cheng
  -- strict thread matches above, loose matches on Subject: below --
2020-12-01  9:29 [PATCH 1/2] Add TARGET_COMPUTE_MULTILIB hook to override multi-lib result Kito Cheng
2020-12-01  9:29 ` [PATCH 2/2] RISC-V: Implement TARGET_COMPUTE_MULTILIB Kito Cheng

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).