https://gcc.gnu.org/g:4ce8ad684b90606a74f0cccfd9455184046c6c4e

commit r15-7458-g4ce8ad684b90606a74f0cccfd9455184046c6c4e
Author: Tobias Burnus <tbur...@baylibre.com>
Date:   Mon Feb 10 18:24:34 2025 +0100

    [gcn] mkoffload.cc: Print fatal error if -march has no multilib but generic 
has
    
    Assume that a distro has configured, e.g., a gfx9-generic multilib but not
    for gfx902. In that case, mkoffload would fail to link with "error:
    incompatible mach".  With this commit, an error is printed suggesting to try
    the associated generic architecture instead.  The behavior is unchanged if
    there is a multilib available for the specific ISA or when there is also no
    multilib for the generic ICA.
    
    Note: The build of generic multilibs are currently not enabled by default;
    they also require the linker/assembler of LLVM 19 or newer and, in 
particular,
    for the execution a future ROCm release. (The next one? In any case, 6.3.2
    does not support generic ISAs, yet.)
    
    gcc/ChangeLog:
    
            * config/gcn/mkoffload.cc (enum elf_arch_code): Add
            EF_AMDGPU_MACH_AMDGCN_NONE.
            (elf_arch): Use enum elf_arch_code as type.
            (tool_cleanup): Silence warning by removing tailing '.' from error.
            (get_arch_name): Return enum elf_arch_code.
            (check_for_missing_lib): New; print fatal error if the multilib
            is not available but it is for the associate generic ISA.
            (main): Call it.

Diff:
---
 gcc/config/gcn/mkoffload.cc | 101 +++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 94 insertions(+), 7 deletions(-)

diff --git a/gcc/config/gcn/mkoffload.cc b/gcc/config/gcn/mkoffload.cc
index 92e8fe70c12e..fbd68a6cd8c9 100644
--- a/gcc/config/gcn/mkoffload.cc
+++ b/gcc/config/gcn/mkoffload.cc
@@ -53,6 +53,7 @@
 
 /* Extract the EF_AMDGPU_MACH_AMDGCN_GFXnnn from the def file.  */
 enum elf_arch_code {
+  EF_AMDGPU_MACH_AMDGCN_NONE = -1,  /* For generic handling.  */
 #define GCN_DEVICE(name, NAME, ELF_ARCH, ...) \
   EF_AMDGPU_MACH_AMDGCN_ ## NAME = ELF_ARCH,
 #include "gcn-devices.def"
@@ -135,9 +136,8 @@ static struct obstack files_to_cleanup;
 enum offload_abi offload_abi = OFFLOAD_ABI_UNSET;
 const char *offload_abi_host_opts = NULL;
 
-uint32_t elf_arch = EF_AMDGPU_MACH_AMDGCN_GFX900;  // Default GPU architecture.
+enum elf_arch_code elf_arch = EF_AMDGPU_MACH_AMDGCN_GFX900;  // Default GPU 
architecture.
 uint32_t elf_flags = EF_AMDGPU_FEATURE_SRAMECC_UNSUPPORTED_V4;
-
 static int gcn_stack_size = 0;  /* Zero means use default.  */
 
 /* Delete tempfiles.  */
@@ -782,7 +782,7 @@ compile_native (const char *infile, const char *outfile, 
const char *compiler,
   obstack_ptr_grow (&argv_obstack, ".c");
   if (!offload_abi_host_opts)
     fatal_error (input_location,
-                "%<-foffload-abi-host-opts%> not specified.");
+                "%<-foffload-abi-host-opts%> not specified");
   obstack_ptr_grow (&argv_obstack, offload_abi_host_opts);
   obstack_ptr_grow (&argv_obstack, infile);
   obstack_ptr_grow (&argv_obstack, "-c");
@@ -796,16 +796,15 @@ compile_native (const char *infile, const char *outfile, 
const char *compiler,
   obstack_free (&argv_obstack, NULL);
 }
 
-static int
+static enum elf_arch_code
 get_arch (const char *str, const char *with_arch_str)
 {
   /* Use the def file to map the name to the elf_arch_code.  */
   if (!str) ;
 #define GCN_DEVICE(name, NAME, ELF, ...) \
   else if (strcmp (str, #name) == 0) \
-    return ELF;
+    return (enum elf_arch_code) ELF;
 #include "gcn-devices.def"
-#undef GCN_DEVICE
 
   /* else */
   error ("unrecognized argument in option %<-march=%s%>", str);
@@ -839,7 +838,91 @@ get_arch (const char *str, const char *with_arch_str)
 
   exit (FATAL_EXIT_CODE);
 
-  return 0;
+  return EF_AMDGPU_MACH_AMDGCN_NONE;
+}
+
+static const char*
+get_arch_name (enum elf_arch_code arch_code)
+{
+  switch (arch_code)
+    {
+#define GCN_DEVICE(name, NAME, ELF, ...) \
+    case EF_AMDGPU_MACH_AMDGCN_ ## NAME: \
+      return #name;
+#include "../../gcc/config/gcn/gcn-devices.def"
+    default: return NULL;
+    }
+}
+
+/* If an generic arch exists and for the chosen arch no (multi)lib is
+   available, print a fatal error - and suggest to compile for the generic
+   version instead.  */
+
+static void
+check_for_missing_lib (enum elf_arch_code elf_arch,
+                      enum elf_arch_code default_arch)
+{
+  enum elf_arch_code generic_arch;
+  switch (elf_arch)
+    {
+#define GCN_DEVICE(name, NAME, ELF, ISA, XNACK, SRAM, WAVE64, CU, \
+                  MAX_ISA_VGPRS, GEN_VER, ARCH_FAM, GEN_MACH, ...) \
+    case EF_AMDGPU_MACH_AMDGCN_ ## NAME: \
+      generic_arch = EF_AMDGPU_MACH_AMDGCN_ ## GEN_MACH; break;
+#include "../../gcc/config/gcn/gcn-devices.def"
+    default: generic_arch = EF_AMDGPU_MACH_AMDGCN_NONE;
+    }
+
+  /* If not generic or the default arch, the library version exists.  */
+  if (generic_arch == EF_AMDGPU_MACH_AMDGCN_NONE || elf_arch == default_arch)
+    return;
+
+  /* Search gcn_arch in the multilib config, which might look like
+     "march=gfx900/march=gfx906".  */
+  const char *p = multilib_options;
+  const char *q = NULL;
+  const char *isa_name = get_arch_name (elf_arch);
+  while ((q = strstr (p, isa_name)) != NULL)
+    {
+      if (multilib_options + strlen ("march=") <= q
+         && startswith (&q[-strlen ("march=")], "march="))
+       {
+         const char r = q[strlen (isa_name)];
+         if (r != '\0' && r != '/')
+           continue;
+         break;
+       }
+      p++;
+    }
+
+  /* Specified -march= exists in the multilib.  */
+  if (q != NULL)
+    return;
+
+  /* If no lib, try to find one for the generic arch.  */
+  const char *gen_name = get_arch_name (generic_arch);
+  if (generic_arch != default_arch)
+    {
+      p = multilib_options;
+      while ((q = strstr (p, gen_name)) != NULL)
+       {
+         if (multilib_options + strlen ("march=") <= q
+             && startswith (&q[-strlen ("march=")], "march="))
+           {
+             const char r = q[strlen (gen_name)];
+             if (r != '\0' && r != '/')
+               continue;
+             break;
+           }
+         p++;
+       }
+      if (q == NULL)
+       return;
+    }
+  fatal_error (UNKNOWN_LOCATION,
+              "GCC was built without library support for %<-march=%s%>; "
+              "consider compiling for the associated generic architecture "
+              "%<-march=%s%> instead", isa_name, gen_name);
 }
 
 int
@@ -864,6 +947,7 @@ main (int argc, char **argv)
        elf_arch = get_arch (configure_default_options[0].value, NULL);
        break;
       }
+  enum elf_arch_code default_arch = elf_arch;
 
   obstack_init (&files_to_cleanup);
   if (atexit (mkoffload_cleanup) != 0)
@@ -998,6 +1082,8 @@ main (int argc, char **argv)
        }
     }
 
+  check_for_missing_lib (elf_arch, default_arch);
+
   if (!(fopenacc ^ fopenmp))
     fatal_error (input_location,
                 "either %<-fopenacc%> or %<-fopenmp%> must be set");
@@ -1056,6 +1142,7 @@ main (int argc, char **argv)
     case ELF: if (GEN_VER) SET_GENERIC_VERSION (elf_flags, GEN_VER); break;
 #include "gcn-devices.def"
 #undef GCN_DEVICE
+    case EF_AMDGPU_MACH_AMDGCN_NONE: gcc_unreachable ();
     }
 
   /* Build arguments for compiler pass.  */

Reply via email to