]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/config/nvptx/mkoffload.c
Wrap option names in gcc internal messages with %< and %>.
[thirdparty/gcc.git] / gcc / config / nvptx / mkoffload.c
index 739aee8af85a7a46a5343969e01ba88b4b6310b1..3770f7295af6b18035d2b3833fb9a468671bfaa4 100644 (file)
@@ -1,6 +1,6 @@
 /* Offload image generation tool for PTX.
 
-   Copyright (C) 2014-2015 Free Software Foundation, Inc.
+   Copyright (C) 2014-2019 Free Software Foundation, Inc.
 
    Contributed by Nathan Sidwell <nathan@codesourcery.com> and
    Bernd Schmidt <bernds@codesourcery.com>.
    This is not a complete assembler.  We presume the source is well
    formed from the compiler and can die horribly if it is not.  */
 
+#define IN_TARGET_CODE 1
+
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
-#include "intl.h"
-#include <libgen.h>
 #include "obstack.h"
 #include "diagnostic.h"
+#include "intl.h"
+#include <libgen.h>
 #include "collect-utils.h"
 #include "gomp-constants.h"
 
@@ -41,84 +43,12 @@ const char tool_name[] = "nvptx mkoffload";
 
 #define COMMENT_PREFIX "#"
 
-typedef enum Kind
-{
-  /* 0-ff used for single char tokens */
-  K_symbol = 0x100, /* a symbol */
-  K_label,  /* a label defn (i.e. symbol:) */
-  K_ident,  /* other ident */
-  K_dotted, /* dotted identifier */
-  K_number,
-  K_string,
-  K_comment
-} Kind;
-
-typedef struct Token
-{
-  unsigned short kind : 12;
-  unsigned short space : 1; /* preceded by space */
-  unsigned short end : 1;   /* succeeded by end of line */
-  /* Length of token */
-  unsigned short len;
-
-  /* Token itself */
-  char const *ptr;
-} Token;
-
-/* statement info */
-typedef enum Vis
-{
-  V_dot = 0,  /* random pseudo */
-  V_var = 1,  /* var decl/defn */
-  V_func = 2, /* func decl/defn */
-  V_insn = 3, /* random insn */
-  V_label = 4, /* label defn */
-  V_comment = 5,
-  V_pred = 6,  /* predicate */
-  V_mask = 0x7,
-  V_global = 0x08, /* globalize */
-  V_weak = 0x10,   /* weakly globalize */
-  V_no_eol = 0x20, /* no end of line */
-  V_prefix_comment = 0x40 /* prefixed comment */
-} Vis;
-
-typedef struct Stmt
-{
-  struct Stmt *next;
-  Token *tokens;
-  unsigned char vis;
-  unsigned len : 12;
-  unsigned sym : 12;
-} Stmt;
-
 struct id_map
 {
   id_map *next;
   char *ptx_name;
 };
 
-static const char *read_file (FILE *);
-static Token *tokenize (const char *);
-
-static void write_token (FILE *, const Token *);
-static void write_tokens (FILE *, const Token *, unsigned, int);
-
-static Stmt *alloc_stmt (unsigned, Token *, Token *, const Token *);
-#define alloc_comment(S,E) alloc_stmt (V_comment, S, E, 0)
-#define append_stmt(V, S) ((S)->next = *(V), *(V) = (S))
-static Stmt *rev_stmts (Stmt *);
-static void write_stmt (FILE *, const Stmt *);
-static void write_stmts (FILE *, const Stmt *);
-
-static Token *parse_insn (Token *);
-static Token *parse_list_nosemi (Token *);
-static Token *parse_init (Token *);
-static Token *parse_file (Token *);
-
-static Stmt *decls;
-static Stmt *vars;
-static Stmt *fns;
-
 static id_map *func_ids, **funcs_tail = &func_ids;
 static id_map *var_ids, **vars_tail = &var_ids;
 
@@ -126,28 +56,40 @@ static id_map *var_ids, **vars_tail = &var_ids;
 static const char *ptx_name;
 static const char *ptx_cfile_name;
 
+enum offload_abi offload_abi = OFFLOAD_ABI_UNSET;
+
 /* Delete tempfiles.  */
 
-/* Unlink a temporary file unless requested otherwise.  */
+void
+tool_cleanup (bool from_signal ATTRIBUTE_UNUSED)
+{
+  if (ptx_cfile_name)
+    maybe_unlink (ptx_cfile_name);
+  if (ptx_name)
+    maybe_unlink (ptx_name);
+}
+
+static void
+mkoffload_cleanup (void)
+{
+  tool_cleanup (false);
+}
+
+/* Unlink FILE unless requested otherwise.  */
 
 void
 maybe_unlink (const char *file)
 {
-  if (! debug)
+  if (!save_temps)
     {
       if (unlink_if_ordinary (file)
          && errno != ENOENT)
        fatal_error (input_location, "deleting file %s: %m", file);
     }
-  else
+  else if (verbose)
     fprintf (stderr, "[Leaving %s]\n", file);
 }
 
-void
-tool_cleanup (bool)
-{
-}
-
 /* Add or change the value of an environment variable, outputting the
    change to standard error if in verbose mode.  */
 static void
@@ -181,7 +123,7 @@ record_id (const char *p1, id_map ***where)
    remember, there could be a NUL in the file itself.  */
 
 static const char *
-read_file (FILE *stream)
+read_file (FILE *stream, size_t *plen)
 {
   size_t alloc = 16384;
   size_t base = 0;
@@ -211,592 +153,205 @@ read_file (FILE *stream)
        }
     }
   buffer[base] = 0;
+  *plen = base;
   return buffer;
 }
 
-/* Read a token, advancing ptr.
-   If we read a comment, append it to the comments block. */
-
-static Token *
-tokenize (const char *ptr)
-{
-  unsigned alloc = 1000;
-  unsigned num = 0;
-  Token *toks = XNEWVEC (Token, alloc);
-  int in_comment = 0;
-  int not_comment = 0;
-
-  for (;; num++)
-    {
-      const char *base;
-      unsigned kind;
-      int ws = 0;
-      int eol = 0;
-
-    again:
-      base = ptr;
-      if (in_comment)
-       goto block_comment;
-      switch (kind = *ptr++)
-       {
-       default:
-         break;
-
-       case '\n':
-         eol = 1;
-         /* Fall through */
-       case ' ':
-       case '\t':
-       case '\r':
-       case '\v':
-         /* White space */
-         ws = not_comment;
-         goto again;
-
-       case '/':
-         {
-           if (*ptr == '/')
-             {
-               /* line comment.  Do not include trailing \n */
-               base += 2;
-               for (; *ptr; ptr++)
-                 if (*ptr == '\n')
-                   break;
-               kind = K_comment;
-             }
-           else if (*ptr == '*')
-             {
-               /* block comment */
-               base += 2;
-               ptr++;
-
-             block_comment:
-               eol = in_comment;
-               in_comment = 1;
-               for (; *ptr; ptr++)
-                 {
-                   if (*ptr == '\n')
-                     {
-                       ptr++;
-                       break;
-                     }
-                   if (ptr[0] == '*' && ptr[1] == '/')
-                     {
-                       in_comment = 2;
-                       ptr += 2;
-                       break;
-                     }
-                 }
-               kind = K_comment;
-             }
-           else
-             break;
-         }
-         break;
-
-       case '"':
-         /* quoted string */
-         kind = K_string;
-         while (*ptr)
-           if (*ptr == '"')
-             {
-               ptr++;
-               break;
-             }
-           else if (*ptr++ == '\\')
-             ptr++;
-         break;
-
-       case '.':
-         if (*ptr < '0' || *ptr > '9')
-           {
-             kind = K_dotted;
-             ws = not_comment;
-             goto ident;
-           }
-         /* FALLTHROUGH */
-       case '0'...'9':
-         kind = K_number;
-         goto ident;
-         break;
-
-       case '$':  /* local labels.  */
-       case '%':  /* register names, pseudoes etc */
-         kind = K_ident;
-         goto ident;
-
-       case 'a'...'z':
-       case 'A'...'Z':
-       case '_':
-         kind = K_symbol; /* possible symbol name */
-       ident:
-         for (; *ptr; ptr++)
-           {
-             if (*ptr >= 'A' && *ptr <= 'Z')
-               continue;
-             if (*ptr >= 'a' && *ptr <= 'z')
-               continue;
-             if (*ptr >= '0' && *ptr <= '9')
-               continue;
-             if (*ptr == '_' || *ptr == '$')
-               continue;
-             if (*ptr == '.' && kind != K_dotted)
-               /* Idents starting with a dot, cannot have internal dots. */
-               continue;
-             if ((*ptr == '+' || *ptr == '-')
-                 && kind == K_number
-                 && (ptr[-1] == 'e' || ptr[-1] == 'E'
-                     || ptr[-1] == 'p' || ptr[-1] == 'P'))
-               /* exponent */
-               continue;
-             break;
-           }
-         if (*ptr == ':')
-           {
-             ptr++;
-             kind = K_label;
-           }
-         break;
-       }
-
-      if (alloc == num)
-       {
-         alloc *= 2;
-         toks = XRESIZEVEC (Token, toks, alloc);
-       }
-      Token *tok = toks + num;
-
-      tok->kind = kind;
-      tok->space = ws;
-      tok->end = 0;
-      tok->ptr = base;
-      tok->len = ptr - base - in_comment;
-      in_comment &= 1;
-      not_comment = kind != K_comment;
-      if (eol && num)
-       tok[-1].end = 1;
-      if (!kind)
-       break;
-    }
-
-  return toks;
-}
-
-/* Write an encoded token. */
-
-static void
-write_token (FILE *out, Token const *tok)
-{
-  if (tok->space)
-    fputc (' ', out);
-
-  switch (tok->kind)
-    {
-    case K_string:
-      {
-       const char *c = tok->ptr + 1;
-       size_t len = tok->len - 2;
-
-       fputs ("\\\"", out);
-       while (len)
-         {
-           const char *bs = (const char *)memchr (c, '\\', len);
-           size_t l = bs ? bs - c : len;
-
-           fprintf (out, "%.*s", (int)l, c);
-           len -= l;
-           c += l;
-           if (bs)
-             {
-               fputs ("\\\\", out);
-               len--, c++;
-             }
-         }
-       fputs ("\\\"", out);
-      }
-      break;
-
-    default:
-      /* All other tokens shouldn't have anything magic in them */
-      fprintf (out, "%.*s", tok->len, tok->ptr);
-      break;
-    }
-  if (tok->end)
-    fputs ("\\n", out);
-}
-
-static void
-write_tokens (FILE *out, Token const *toks, unsigned len, int spc)
-{
-  fputs ("\t\"", out);
-  for (; len--; toks++)
-    write_token (out, toks);
-  if (spc)
-    fputs (" ", out);
-  fputs ("\"", out);
-}
-
-static Stmt *
-alloc_stmt (unsigned vis, Token *tokens, Token *end, Token const *sym)
+/* Parse STR, saving found tokens into PVALUES and return their number.
+   Tokens are assumed to be delimited by ':'.  */
+static unsigned
+parse_env_var (const char *str, char ***pvalues)
 {
-  static unsigned alloc = 0;
-  static Stmt *heap = 0;
+  const char *curval, *nextval;
+  char **values;
+  unsigned num = 1, i;
 
-  if (!alloc)
+  curval = strchr (str, ':');
+  while (curval)
     {
-      alloc = 1000;
-      heap = XNEWVEC (Stmt, alloc);
+      num++;
+      curval = strchr (curval + 1, ':');
     }
 
-  Stmt *stmt = heap++;
-  alloc--;
-
-  tokens->space = 0;
-  stmt->next = 0;
-  stmt->vis = vis;
-  stmt->tokens = tokens;
-  stmt->len = end - tokens;
-  stmt->sym = sym ? sym - tokens : ~0;
-
-  return stmt;
-}
-
-static Stmt *
-rev_stmts (Stmt *stmt)
-{
-  Stmt *prev = 0;
-  Stmt *next;
+  values = (char **) xmalloc (num * sizeof (char *));
+  curval = str;
+  nextval = strchr (curval, ':');
+  if (nextval == NULL)
+    nextval = strchr (curval, '\0');
 
-  while (stmt)
+  for (i = 0; i < num; i++)
     {
-      next = stmt->next;
-      stmt->next = prev;
-      prev = stmt;
-      stmt = next;
+      int l = nextval - curval;
+      values[i] = (char *) xmalloc (l + 1);
+      memcpy (values[i], curval, l);
+      values[i][l] = 0;
+      curval = nextval + 1;
+      nextval = strchr (curval, ':');
+      if (nextval == NULL)
+       nextval = strchr (curval, '\0');
     }
-
-  return prev;
+  *pvalues = values;
+  return num;
 }
 
+/* Auxiliary function that frees elements of PTR and PTR itself.
+   N is number of elements to be freed.  If PTR is NULL, nothing is freed.
+   If an element is NULL, subsequent elements are not freed.  */
 static void
-write_stmt (FILE *out, const Stmt *stmt)
+free_array_of_ptrs (void **ptr, unsigned n)
 {
-  if ((stmt->vis & V_mask) != V_comment)
+  unsigned i;
+  if (!ptr)
+    return;
+  for (i = 0; i < n; i++)
     {
-      write_tokens (out, stmt->tokens, stmt->len,
-                   (stmt->vis & V_mask) == V_pred);
-      fputs (stmt->vis & V_no_eol ? "\t" : "\n", out);
+      if (!ptr[i])
+       break;
+      free (ptr[i]);
     }
+  free (ptr);
+  return;
 }
 
-static void
-write_stmts (FILE *out, const Stmt *stmts)
-{
-  for (; stmts; stmts = stmts->next)
-    write_stmt (out, stmts);
-}
-
-static Token *
-parse_insn (Token *tok)
+/* Check whether NAME can be accessed in MODE.  This is like access,
+   except that it never considers directories to be executable.  */
+static int
+access_check (const char *name, int mode)
 {
-  unsigned depth = 0;
-
-  do
+  if (mode == X_OK)
     {
-      Stmt *stmt;
-      Token *sym = 0;
-      unsigned s = V_insn;
-      Token *start = tok;
-
-      switch (tok++->kind)
-       {
-       case K_comment:
-         while (tok->kind == K_comment)
-           tok++;
-         stmt = alloc_comment (start, tok);
-         append_stmt (&fns, stmt);
-         continue;
-
-       case '{':
-         depth++;
-         break;
-
-       case '}':
-         depth--;
-         break;
-
-       case K_label:
-         if (tok[-1].ptr[0] != '$')
-           sym = tok - 1;
-         tok[-1].end = 1;
-         s = V_label;
-         break;
-
-       case '@':
-         tok->space = 0;
-         if (tok->kind == '!')
-           tok++;
-         if (tok->kind == K_symbol)
-           sym = tok;
-         tok++;
-         s = V_pred;
-         break;
-
-       default:
-         for (; tok->kind != ';'; tok++)
-           {
-             if (tok->kind == ',')
-               tok[1].space = 0;
-             else if (tok->kind == K_symbol)
-               sym = tok;
-           }
-         tok++->end = 1;
-         break;
-       }
-
-      stmt = alloc_stmt (s, start, tok, sym);
-      append_stmt (&fns, stmt);
+      struct stat st;
 
-      if (!tok[-1].end && tok[0].kind == K_comment)
-       {
-         stmt->vis |= V_no_eol;
-         stmt = alloc_comment (tok, tok + 1);
-         append_stmt (&fns, stmt);
-         tok++;
-       }
+      if (stat (name, &st) < 0 || S_ISDIR (st.st_mode))
+       return -1;
     }
-  while (depth);
-
-  return tok;
-}
-
-/* comma separated list of tokens */
-
-static Token *
-parse_list_nosemi (Token *tok)
-{
-  Token *start = tok;
-
-  do
-    if (!(++tok)->kind)
-      break;
-  while ((++tok)->kind == ',');
-
-  tok[-1].end = 1;
-  Stmt *stmt = alloc_stmt (V_dot, start, tok, 0);
-  append_stmt (&decls, stmt);
 
-  return tok;
+  return access (name, mode);
 }
 
-#define is_keyword(T,S) \
-  (sizeof (S) == (T)->len && !memcmp ((T)->ptr + 1, (S), (T)->len - 1))
-
-static Token *
-parse_init (Token *tok)
-{
-  for (;;)
-    {
-      Token *start = tok;
-      Token const *sym = 0;
-      Stmt *stmt;
-
-      if (tok->kind == K_comment)
-       {
-         while (tok->kind == K_comment)
-           tok++;
-         stmt = alloc_comment (start, tok);
-         append_stmt (&vars, stmt);
-         start = tok;
-       }
-
-      if (tok->kind == '{')
-       tok[1].space = 0;
-      for (; tok->kind != ',' && tok->kind != ';'; tok++)
-       if (tok->kind == K_symbol)
-         sym = tok;
-      tok[1].space = 0;
-      int end = tok++->kind == ';';
-      stmt = alloc_stmt (V_insn, start, tok, sym);
-      append_stmt (&vars, stmt);
-      if (!tok[-1].end && tok->kind == K_comment)
-       {
-         stmt->vis |= V_no_eol;
-         stmt = alloc_comment (tok, tok + 1);
-         append_stmt (&vars, stmt);
-         tok++;
-       }
-      if (end)
-       break;
-    }
-  return tok;
-}
-
-static Token *
-parse_file (Token *tok)
+static void
+process (FILE *in, FILE *out)
 {
-  Stmt *comment = 0;
-
-  if (tok->kind == K_comment)
+  size_t len = 0;
+  const char *input = read_file (in, &len);
+  const char *comma;
+  id_map const *id;
+  unsigned obj_count = 0;
+  unsigned ix;
+
+  /* Dump out char arrays for each PTX object file.  These are
+     terminated by a NUL.  */
+  for (size_t i = 0; i != len;)
     {
-      Token *start = tok;
-
-      while (tok->kind == K_comment)
-       {
-         if (strncmp (tok->ptr, ":VAR_MAP ", 9) == 0)
-           record_id (tok->ptr + 9, &vars_tail);
-         if (strncmp (tok->ptr, ":FUNC_MAP ", 10) == 0)
-           record_id (tok->ptr + 10, &funcs_tail);
-         tok++;
-       }
-      comment = alloc_comment (start, tok);
-      comment->vis |= V_prefix_comment;
-    }
+      char c;
 
-  if (tok->kind == K_dotted)
-    {
-      if (is_keyword (tok, "version")
-         || is_keyword (tok, "target")
-         || is_keyword (tok, "address_size"))
-       {
-         if (comment)
-           append_stmt (&decls, comment);
-         tok = parse_list_nosemi (tok);
-       }
-      else
+      fprintf (out, "static const char ptx_code_%u[] =\n\t\"", obj_count++);
+      while ((c = input[i++]))
        {
-         unsigned vis = 0;
-         const Token *def = 0;
-         unsigned is_decl = 0;
-         Token *start;
-
-         for (start = tok;
-              tok->kind && tok->kind != '=' && tok->kind != K_comment
-                && tok->kind != '{' && tok->kind != ';'; tok++)
-           {
-             if (is_keyword (tok, "global")
-                 || is_keyword (tok, "const"))
-               vis |= V_var;
-             else if (is_keyword (tok, "func")
-                      || is_keyword (tok, "entry"))
-               vis |= V_func;
-             else if (is_keyword (tok, "visible"))
-               vis |= V_global;
-             else if (is_keyword (tok, "extern"))
-               is_decl = 1;
-             else if (is_keyword (tok, "weak"))
-               vis |= V_weak;
-             if (tok->kind == '(')
-               {
-                 tok[1].space = 0;
-                 tok[0].space = 1;
-               }
-             else if (tok->kind == ')' && tok[1].kind != ';')
-               tok[1].space = 1;
-
-             if (tok->kind == K_symbol)
-               def = tok;
-           }
-
-         if (!tok->kind)
-           {
-             /* end of file */
-             if (comment)
-               append_stmt (&fns, comment);
-           }
-         else if (tok->kind == '{'
-                  || tok->kind == K_comment)
-           {
-             /* function defn */
-             Stmt *stmt = alloc_stmt (vis, start, tok, def);
-             if (comment)
-               {
-                 append_stmt (&fns, comment);
-                 stmt->vis |= V_prefix_comment;
-               }
-             append_stmt (&fns, stmt);
-             tok = parse_insn (tok);
-           }
-         else
+         switch (c)
            {
-             int assign = tok->kind == '=';
-
-             tok++->end = 1;
-             if ((vis & V_mask) == V_var && !is_decl)
+           case '\r':
+             continue;
+           case '\n':
+             fprintf (out, "\\n\"\n\t\"");
+             /* Look for mappings on subsequent lines.  */
+             while (strncmp (input + i, "//:", 3) == 0)
                {
-                 /* variable */
-                 Stmt *stmt = alloc_stmt (vis, start, tok, def);
-                 if (comment)
-                   {
-                     append_stmt (&vars, comment);
-                     stmt->vis |= V_prefix_comment;
-                   }
-                 append_stmt (&vars, stmt);
-                 if (assign)
-                   tok = parse_init (tok);
-               }
-             else
-               {
-                 /* declaration */
-                 Stmt *stmt = alloc_stmt (vis, start, tok, 0);
-                 if (comment)
-                   {
-                     append_stmt (&decls, comment);
-                     stmt->vis |= V_prefix_comment;
-                   }
-                 append_stmt (&decls, stmt);
+                 i += 3;
+
+                 if (strncmp (input + i, "VAR_MAP ", 8) == 0)
+                   record_id (input + i + 8, &vars_tail);
+                 else if (strncmp (input + i, "FUNC_MAP ", 9) == 0)
+                   record_id (input + i + 9, &funcs_tail);
+                 else
+                   abort ();
+                 /* Skip to next line. */
+                 while (input[i++] != '\n')
+                   continue;
                }
+             continue;
+           case '"':
+           case '\\':
+             putc ('\\', out);
+             break;
+           default:
+             break;
            }
+         putc (c, out);
        }
+      fprintf (out, "\";\n\n");
     }
-  else
-    {
-      /* Something strange.  Ignore it.  */
-      if (comment)
-       append_stmt (&fns, comment);
 
-      while (tok->kind && !tok->end)
-       tok++;
-    }
-  return tok;
-}
+  /* Dump out array of pointers to ptx object strings.  */
+  fprintf (out, "static const struct ptx_obj {\n"
+          "  const char *code;\n"
+          "  __SIZE_TYPE__ size;\n"
+          "} ptx_objs[] = {");
+  for (comma = "", ix = 0; ix != obj_count; comma = ",", ix++)
+    fprintf (out, "%s\n\t{ptx_code_%u, sizeof (ptx_code_%u)}", comma, ix, ix);
+  fprintf (out, "\n};\n\n");
+
+  /* Dump out variable idents.  */
+  fprintf (out, "static const char *const var_mappings[] = {");
+  for (comma = "", id = var_ids; id; comma = ",", id = id->next)
+    fprintf (out, "%s\n\t%s", comma, id->ptx_name);
+  fprintf (out, "\n};\n\n");
+
+  /* Dump out function idents.  */
+  fprintf (out, "static const struct nvptx_fn {\n"
+          "  const char *name;\n"
+          "  unsigned short dim[%d];\n"
+          "} func_mappings[] = {\n", GOMP_DIM_MAX);
+  for (comma = "", id = func_ids; id; comma = ",", id = id->next)
+    fprintf (out, "%s\n\t{%s}", comma, id->ptx_name);
+  fprintf (out, "\n};\n\n");
+
+  fprintf (out,
+          "static const struct nvptx_tdata {\n"
+          "  const struct ptx_obj *ptx_objs;\n"
+          "  unsigned ptx_num;\n"
+          "  const char *const *var_names;\n"
+          "  unsigned var_num;\n"
+          "  const struct nvptx_fn *fn_names;\n"
+          "  unsigned fn_num;\n"
+          "} target_data = {\n"
+          "  ptx_objs, sizeof (ptx_objs) / sizeof (ptx_objs[0]),\n"
+          "  var_mappings,"
+          "  sizeof (var_mappings) / sizeof (var_mappings[0]),\n"
+          "  func_mappings,"
+          "  sizeof (func_mappings) / sizeof (func_mappings[0])\n"
+          "};\n\n");
+
+  fprintf (out, "#ifdef __cplusplus\n"
+          "extern \"C\" {\n"
+          "#endif\n");
+
+  fprintf (out, "extern void GOMP_offload_register_ver"
+          " (unsigned, const void *, int, const void *);\n");
+  fprintf (out, "extern void GOMP_offload_unregister_ver"
+          " (unsigned, const void *, int, const void *);\n");
+
+  fprintf (out, "#ifdef __cplusplus\n"
+          "}\n"
+          "#endif\n");
+
+  fprintf (out, "extern const void *const __OFFLOAD_TABLE__[];\n\n");
+
+  fprintf (out, "static __attribute__((constructor)) void init (void)\n"
+          "{\n"
+          "  GOMP_offload_register_ver (%#x, __OFFLOAD_TABLE__,"
+          " %d/*NVIDIA_PTX*/, &target_data);\n"
+          "};\n",
+          GOMP_VERSION_PACK (GOMP_VERSION, GOMP_VERSION_NVIDIA_PTX),
+          GOMP_DEVICE_NVIDIA_PTX);
 
-static void
-process (FILE *in, FILE *out)
-{
-  const char *input = read_file (in);
-  Token *tok = tokenize (input);
-
-  do
-    tok = parse_file (tok);
-  while (tok->kind);
-
-  fprintf (out, "static const char ptx_code[] = \n");
-  write_stmts (out, rev_stmts (decls));
-  write_stmts (out, rev_stmts (vars));
-  write_stmts (out, rev_stmts (fns));
-  fprintf (out, ";\n\n");
-  fprintf (out, "static const char *var_mappings[] = {\n");
-  for (id_map *id = var_ids; id; id = id->next)
-    fprintf (out, "\t\"%s\"%s\n", id->ptx_name, id->next ? "," : "");
-  fprintf (out, "};\n\n");
-  fprintf (out, "static const char *func_mappings[] = {\n");
-  for (id_map *id = func_ids; id; id = id->next)
-    fprintf (out, "\t\"%s\"%s\n", id->ptx_name, id->next ? "," : "");
-  fprintf (out, "};\n\n");
-
-  fprintf (out, "static const void *target_data[] = {\n");
-  fprintf (out, "  ptx_code, var_mappings, func_mappings\n");
-  fprintf (out, "};\n\n");
-
-  fprintf (out, "extern void GOMP_offload_register (const void *, int, void *);\n");
-
-  fprintf (out, "extern void *__OFFLOAD_TABLE__[];\n\n");
-  fprintf (out, "static __attribute__((constructor)) void init (void)\n{\n");
-  fprintf (out, "  GOMP_offload_register (__OFFLOAD_TABLE__, %d,\n",
+  fprintf (out, "static __attribute__((destructor)) void fini (void)\n"
+          "{\n"
+          "  GOMP_offload_unregister_ver (%#x, __OFFLOAD_TABLE__,"
+          " %d/*NVIDIA_PTX*/, &target_data);\n"
+          "};\n",
+          GOMP_VERSION_PACK (GOMP_VERSION, GOMP_VERSION_NVIDIA_PTX),
           GOMP_DEVICE_NVIDIA_PTX);
-  fprintf (out, "                         &target_data);\n");
-  fprintf (out, "};\n");
 }
 
 static void
@@ -810,6 +365,21 @@ compile_native (const char *infile, const char *outfile, const char *compiler)
   struct obstack argv_obstack;
   obstack_init (&argv_obstack);
   obstack_ptr_grow (&argv_obstack, compiler);
+  if (save_temps)
+    obstack_ptr_grow (&argv_obstack, "-save-temps");
+  if (verbose)
+    obstack_ptr_grow (&argv_obstack, "-v");
+  switch (offload_abi)
+    {
+    case OFFLOAD_ABI_LP64:
+      obstack_ptr_grow (&argv_obstack, "-m64");
+      break;
+    case OFFLOAD_ABI_ILP32:
+      obstack_ptr_grow (&argv_obstack, "-m32");
+      break;
+    default:
+      gcc_unreachable ();
+    }
   obstack_ptr_grow (&argv_obstack, infile);
   obstack_ptr_grow (&argv_obstack, "-c");
   obstack_ptr_grow (&argv_obstack, "-o");
@@ -831,6 +401,9 @@ main (int argc, char **argv)
   progname = "mkoffload";
   diagnostic_initialize (global_dc, 0);
 
+  if (atexit (mkoffload_cleanup) != 0)
+    fatal_error (input_location, "atexit failed");
+
   char *collect_gcc = getenv ("COLLECT_GCC");
   if (collect_gcc == NULL)
     fatal_error (input_location, "COLLECT_GCC must be set.");
@@ -852,16 +425,93 @@ main (int argc, char **argv)
     driver_used = sprintf (driver, "%s/", gcc_path);
   sprintf (driver + driver_used, "%s", GCC_INSTALL_NAME);
 
+  bool found = false;
+  if (gcc_path == NULL)
+    found = true;
+  else if (access_check (driver, X_OK) == 0)
+    found = true;
+  else
+    {
+      /* Don't use alloca pointer with XRESIZEVEC.  */
+      driver = NULL;
+      /* Look in all COMPILER_PATHs for GCC_INSTALL_NAME.  */
+      char **paths = NULL;
+      unsigned n_paths;
+      n_paths = parse_env_var (getenv ("COMPILER_PATH"), &paths);
+      for (unsigned i = 0; i < n_paths; i++)
+       {
+         len = strlen (paths[i]) + 1 + strlen (GCC_INSTALL_NAME) + 1;
+         driver = XRESIZEVEC (char, driver, len);
+         sprintf (driver, "%s/%s", paths[i], GCC_INSTALL_NAME);
+         if (access_check (driver, X_OK) == 0)
+           {
+             found = true;
+             break;
+           }
+       }
+      free_array_of_ptrs ((void **) paths, n_paths);
+    }
+
+  if (!found)
+    fatal_error (input_location,
+                "offload compiler %s not found (consider using '-B')",
+                GCC_INSTALL_NAME);
+
   /* We may be called with all the arguments stored in some file and
      passed with @file.  Expand them into argv before processing.  */
   expandargv (&argc, &argv);
 
+  /* Scan the argument vector.  */
+  bool fopenmp = false;
+  bool fopenacc = false;
+  for (int i = 1; i < argc; i++)
+    {
+#define STR "-foffload-abi="
+      if (strncmp (argv[i], STR, strlen (STR)) == 0)
+       {
+         if (strcmp (argv[i] + strlen (STR), "lp64") == 0)
+           offload_abi = OFFLOAD_ABI_LP64;
+         else if (strcmp (argv[i] + strlen (STR), "ilp32") == 0)
+           offload_abi = OFFLOAD_ABI_ILP32;
+         else
+           fatal_error (input_location,
+                        "unrecognizable argument of option " STR);
+       }
+#undef STR
+      else if (strcmp (argv[i], "-fopenmp") == 0)
+       fopenmp = true;
+      else if (strcmp (argv[i], "-fopenacc") == 0)
+       fopenacc = true;
+      else if (strcmp (argv[i], "-save-temps") == 0)
+       save_temps = true;
+      else if (strcmp (argv[i], "-v") == 0)
+       verbose = true;
+    }
+  if (!(fopenacc ^ fopenmp))
+    fatal_error (input_location, "either %<-fopenacc%> or %<-fopenmp%> "
+                "must be set");
+
   struct obstack argv_obstack;
   obstack_init (&argv_obstack);
   obstack_ptr_grow (&argv_obstack, driver);
+  if (save_temps)
+    obstack_ptr_grow (&argv_obstack, "-save-temps");
+  if (verbose)
+    obstack_ptr_grow (&argv_obstack, "-v");
   obstack_ptr_grow (&argv_obstack, "-xlto");
-  obstack_ptr_grow (&argv_obstack, "-m64");
-  obstack_ptr_grow (&argv_obstack, "-S");
+  switch (offload_abi)
+    {
+    case OFFLOAD_ABI_LP64:
+      obstack_ptr_grow (&argv_obstack, "-m64");
+      break;
+    case OFFLOAD_ABI_ILP32:
+      obstack_ptr_grow (&argv_obstack, "-m32");
+      break;
+    default:
+      gcc_unreachable ();
+    }
+  if (fopenmp)
+    obstack_ptr_grow (&argv_obstack, "-mgomp");
 
   for (int ix = 1; ix != argc; ix++)
     {
@@ -871,42 +521,46 @@ main (int argc, char **argv)
        obstack_ptr_grow (&argv_obstack, argv[ix]);
     }
 
-  ptx_name = make_temp_file (".mkoffload");
-  obstack_ptr_grow (&argv_obstack, "-o");
-  obstack_ptr_grow (&argv_obstack, ptx_name);
-  obstack_ptr_grow (&argv_obstack, NULL);
-  const char **new_argv = XOBFINISH (&argv_obstack, const char **);
-
-  char *execpath = getenv ("GCC_EXEC_PREFIX");
-  char *cpath = getenv ("COMPILER_PATH");
-  char *lpath = getenv ("LIBRARY_PATH");
-  unsetenv ("GCC_EXEC_PREFIX");
-  unsetenv ("COMPILER_PATH");
-  unsetenv ("LIBRARY_PATH");
-
-  fork_execute (new_argv[0], CONST_CAST (char **, new_argv), true);
-  obstack_free (&argv_obstack, NULL);
-
-  xputenv (concat ("GCC_EXEC_PREFIX=", execpath, NULL));
-  xputenv (concat ("COMPILER_PATH=", cpath, NULL));
-  xputenv (concat ("LIBRARY_PATH=", lpath, NULL));
-
-  in = fopen (ptx_name, "r");
-  if (!in)
-    fatal_error (input_location, "cannot open intermediate ptx file");
-
   ptx_cfile_name = make_temp_file (".c");
 
   out = fopen (ptx_cfile_name, "w");
   if (!out)
     fatal_error (input_location, "cannot open '%s'", ptx_cfile_name);
 
-  process (in, out);
+  /* PR libgomp/65099: Currently, we only support offloading in 64-bit
+     configurations.  */
+  if (offload_abi == OFFLOAD_ABI_LP64)
+    {
+      ptx_name = make_temp_file (".mkoffload");
+      obstack_ptr_grow (&argv_obstack, "-o");
+      obstack_ptr_grow (&argv_obstack, ptx_name);
+      obstack_ptr_grow (&argv_obstack, NULL);
+      const char **new_argv = XOBFINISH (&argv_obstack, const char **);
+
+      char *execpath = getenv ("GCC_EXEC_PREFIX");
+      char *cpath = getenv ("COMPILER_PATH");
+      char *lpath = getenv ("LIBRARY_PATH");
+      unsetenv ("GCC_EXEC_PREFIX");
+      unsetenv ("COMPILER_PATH");
+      unsetenv ("LIBRARY_PATH");
+
+      fork_execute (new_argv[0], CONST_CAST (char **, new_argv), true);
+      obstack_free (&argv_obstack, NULL);
+
+      xputenv (concat ("GCC_EXEC_PREFIX=", execpath, NULL));
+      xputenv (concat ("COMPILER_PATH=", cpath, NULL));
+      xputenv (concat ("LIBRARY_PATH=", lpath, NULL));
+
+      in = fopen (ptx_name, "r");
+      if (!in)
+       fatal_error (input_location, "cannot open intermediate ptx file");
+
+      process (in, out);
+    }
+
   fclose (out);
 
   compile_native (ptx_cfile_name, outname, collect_gcc);
 
-  utils_cleanup (false);
-
   return 0;
 }