This patch is part of the following series (not yet in mainline);
this patch depends on the first one, but only makes sense if both are in:

* "[gcn] Add gfx9-generic and generic-associated gfx*"
  (email subject: "Re: [Patch] [GCN] Handle generic ISA names in libgomp's 
plugin-gcn.c";
   this thread), 
https://gcc.gnu.org/pipermail/gcc-patches/2025-February/675259.html

* "[Patch] [GCN] Handle generic ISA names in libgomp's plugin-gcn.c",
  https://gcc.gnu.org/pipermail/gcc-patches/2025-February/675274.html

* * *

This patch handles the following case (in mkoffload.cc):

* If for the specified specific device, no (multi)lib is available but for
  its generic ISA, automatically choose the generic ISA (with a warning).

Due to the double condition (not available for specified, available for
generic), it shouldn't cause surprises. Additionally, when not using
mkoffload, i.e. when compiling directly with the GCN compiler, the
specific ISA is still used.

As currently no one will build a multilib for gfx*generic and ship it,
the change should not cause surprises to users. And once ROCm supports
it, rebuilding GCC with the added multilib is enough.

Thus, like the libgomp change, it make GCC future proof and aid
deployment by Linux distros.

OK for mainline?

Tobias
[gcn] mkoffload.cc: Automatically use gfx*-generic 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, mkoffload would fail to link - hence, automatically.

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.
	(elf_arch_generic_update): New; replace specific device by
	generic device if only the latter has a multilib.
	(main): Call it; replace -march= as needed.

 gcc/config/gcn/mkoffload.cc | 115 ++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 105 insertions(+), 10 deletions(-)

diff --git a/gcc/config/gcn/mkoffload.cc b/gcc/config/gcn/mkoffload.cc
index 92e8fe70c12..39be6630fd0 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,92 @@ 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, default to the generic version, if that has a (multi)lib
+   configured for.  */
+
+static enum elf_arch_code
+elf_arch_generic_update (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 elf_arch;
+
+  /* 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 elf_arch;
+
+  /* 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 elf_arch;
+    }
+  warning (0,
+	   "using associated generic architecture %<-march=%s%> instead of "
+	   "%<-march=%s%> as GCC was only built with a multilib for the former",
+	   gen_name, isa_name);
+  return generic_arch;
 }
 
 int
@@ -864,6 +948,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 +1083,9 @@ main (int argc, char **argv)
 	}
     }
 
+  enum elf_arch_code orig_arch = elf_arch;
+  elf_arch = elf_arch_generic_update (elf_arch, default_arch);
+
   if (!(fopenacc ^ fopenmp))
     fatal_error (input_location,
 		 "either %<-fopenacc%> or %<-fopenmp%> must be set");
@@ -1056,6 +1144,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.  */
@@ -1072,12 +1161,15 @@ main (int argc, char **argv)
   obstack_ptr_grow (&cc_argv_obstack, "-xlto");
   if (fopenmp)
     obstack_ptr_grow (&cc_argv_obstack, "-mgomp");
-
+  if (orig_arch != elf_arch)
+    obstack_ptr_grow (&cc_argv_obstack,
+		      concat ("-march=", get_arch_name (elf_arch), NULL));
   for (int ix = 1; ix != argc; ix++)
     {
       if (!strcmp (argv[ix], "-o") && ix + 1 != argc)
 	outname = argv[++ix];
-      else
+      else if (orig_arch == elf_arch
+	       || !startswith (argv[ix], "-march"))
 	obstack_ptr_grow (&cc_argv_obstack, argv[ix]);
     }
 
@@ -1195,9 +1287,12 @@ main (int argc, char **argv)
       for (int i = 1; i < argc; i++)
 	if (startswith (argv[i], "-l")
 	    || startswith (argv[i], "-Wl")
-	    || startswith (argv[i], "-march"))
+	    || (orig_arch == elf_arch && startswith (argv[i], "-march")))
 	  obstack_ptr_grow (&ld_argv_obstack, argv[i]);
 
+      if (orig_arch != elf_arch)
+	obstack_ptr_grow (&ld_argv_obstack,
+			  concat ("-march=", get_arch_name (elf_arch), NULL));
       obstack_ptr_grow (&cc_argv_obstack, "-dumpdir");
       obstack_ptr_grow (&cc_argv_obstack, "");
       obstack_ptr_grow (&cc_argv_obstack, "-dumpbase");

Reply via email to