From 73efb4cc50a221ed45a4d44c06157fcf9124e320 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Cl=C3=A9ment=20Chigot?= <clement.chigot@atos.net>
Date: Mon, 12 Oct 2020 11:37:13 +0200
Subject: [PATCH] gcc: implement multilib fallbacks
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Some targets needs to be able to fallback from multilib A to
multilib B if multilib A isn't available at runtime.
Currently, the searched paths generated by gcc only include a single
multilib suffix and the default library.
This patch adds MULTILIB_FALLBACK macro to allow targets to get extra
multlib suffixes in these paths.

gcc/ChangeLog:

2020-10-12  Clément Chigot  <clement.chigot@atos.net>

	* config/rs6000/aix.h (MULTILIB_FALLBACK): New Define
	* gcc.c	(for_each_path): Allow several multilib suffixes
	to be tried, based on MULTILIB_FALLBACK macro.
---
 gcc/config/rs6000/aix.h | 21 +++++++++++++++
 gcc/gcc.c               | 60 ++++++++++++++++++++++++++++++-----------
 2 files changed, 66 insertions(+), 15 deletions(-)

diff --git a/gcc/config/rs6000/aix.h b/gcc/config/rs6000/aix.h
index edd6fdb0ec2..9cff6a67e1c 100644
--- a/gcc/config/rs6000/aix.h
+++ b/gcc/config/rs6000/aix.h
@@ -280,3 +280,24 @@
 /* Use standard DWARF numbering for DWARF debugging information.  */
 #define RS6000_USE_DWARF_NUMBERING
 
+/* Threaded programs must be able to fallback on pthread FAT library
+   if their architecture directory isn't present.  This is happening
+   when a 32bit program built with a 64-bit gcc is running on a 32bit
+   runtime.  */
+#define MULTILIB_FALLBACK(CURR_MULTILIB)				\
+  do									\
+    {									\
+      if (!strcmp (CURR_MULTILIB, "pthread/ppc64")			\
+	  || !(strcmp (CURR_MULTILIB, "pthread/ppc32")))		\
+	{								\
+	  free (CONST_CAST (char *, CURR_MULTILIB));			\
+	  CURR_MULTILIB = XNEWVEC (char, strlen ("pthread") + 1);	\
+	  strcpy (CURR_MULTILIB, "pthread");				\
+	}								\
+      else								\
+	{								\
+	  free (CONST_CAST (char *, CURR_MULTILIB));			\
+	  CURR_MULTILIB = NULL;						\
+	}								\
+    }									\
+  while (0)
diff --git a/gcc/gcc.c b/gcc/gcc.c
index ff7b6c4a320..6bee64dbec9 100644
--- a/gcc/gcc.c
+++ b/gcc/gcc.c
@@ -2683,11 +2683,12 @@ clear_failure_queue (void)
 
 /* Call CALLBACK for each path in PATHS, breaking out early if CALLBACK
    returns non-NULL.
-   If DO_MULTI is true iterate over the paths twice, first with multilib
-   suffix then without, otherwise iterate over the paths once without
-   adding a multilib suffix.  When DO_MULTI is true, some attempt is made
-   to avoid visiting the same path twice, but we could do better.  For
-   instance, /usr/lib/../lib is considered different from /usr/lib.
+   If DO_MULTI is true iterate over the paths at least twice, first with
+   multilib suffixes then without any, otherwise iterate over the paths
+   once without adding a multilib suffix.  When DO_MULTI is true, some
+   attempt is made to avoid visiting the same path twice, but we could
+   do better.  For instance, /usr/lib/../lib is considered different
+   from /usr/lib.
    At least EXTRA_SPACE chars past the end of the path passed to
    CALLBACK are available for use by the callback.
    CALLBACK_INFO allows extra parameters to be passed to CALLBACK.
@@ -2712,11 +2713,18 @@ for_each_path (const struct path_prefix *paths,
   bool skip_multi_dir = false;
   bool skip_multi_os_dir = false;
 
+  char *curr_multilib_dir = NULL;
+  if (do_multi && multilib_dir)
+    {
+      curr_multilib_dir = XNEWVEC (char, strlen (multilib_dir));
+      strcpy (curr_multilib_dir, multilib_dir);
+    }
+
   multi_suffix = machine_suffix;
   just_multi_suffix = just_machine_suffix;
-  if (do_multi && multilib_dir && strcmp (multilib_dir, ".") != 0)
+  if (do_multi && curr_multilib_dir && strcmp (curr_multilib_dir, ".") != 0)
     {
-      multi_dir = concat (multilib_dir, dir_separator_str, NULL);
+      multi_dir = concat (curr_multilib_dir, dir_separator_str, NULL);
       multi_suffix = concat (multi_suffix, multi_dir, NULL);
       just_multi_suffix = concat (just_multi_suffix, multi_dir, NULL);
     }
@@ -2819,17 +2827,39 @@ for_each_path (const struct path_prefix *paths,
       if (multi_dir == NULL && multi_os_dir == NULL)
 	break;
 
-      /* Run through the paths again, this time without multilibs.
+      /* Run through the paths again, this time with a new
+	 multilib suffix or without any.
 	 Don't repeat any we have already seen.  */
       if (multi_dir)
 	{
-	  free (CONST_CAST (char *, multi_dir));
-	  multi_dir = NULL;
-	  free (CONST_CAST (char *, multi_suffix));
-	  multi_suffix = machine_suffix;
-	  free (CONST_CAST (char *, just_multi_suffix));
-	  just_multi_suffix = just_machine_suffix;
-	}
+
+#ifdef MULTILIB_FALLBACK
+	  /* Retrieve the next multilib to be tried.  */
+	  if (curr_multilib_dir)
+	    MULTILIB_FALLBACK (curr_multilib_dir);
+#else
+	  free (curr_multilib_dir);
+	  curr_multilib_dir = NULL;
+#endif
+	  if (curr_multilib_dir)
+	    {
+	      free (CONST_CAST (char *, multi_dir));
+	      multi_dir = concat (curr_multilib_dir, dir_separator_str, NULL);
+	      free (CONST_CAST (char *, multi_suffix));
+	      multi_suffix = concat (machine_suffix, multi_dir, NULL);
+	      free (CONST_CAST (char *, just_multi_suffix));
+	      just_multi_suffix = concat (just_machine_suffix, multi_dir, NULL);
+	    }
+	  else
+	    {
+	      free (CONST_CAST (char *, multi_dir));
+	      multi_dir = NULL;
+	      free (CONST_CAST (char *, multi_suffix));
+	      multi_suffix = machine_suffix;
+	      free (CONST_CAST (char *, just_multi_suffix));
+	      just_multi_suffix = just_machine_suffix;
+	    }
+  }
       else
 	skip_multi_dir = true;
       if (multi_os_dir)
-- 
2.25.1

