This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

The nvptx port [11/11] More tools.


This is a "bonus" optional patch which adds ar, ranlib, as and ld to the ptx port. This is not proper binutils; ar and ranlib are just linked to the host versions, and the other two tools have the following functions:

* nvptx-as is required to convert the compiler output to actual valid
  ptx assembly, primarily by reordering declarations and definitions.
  Believe me when I say that I've tried to make that work in the
  compiler itself and it's pretty much impossible without some really
  invasive changes.
* nvptx-ld is just a pseudo linker that works by concatenating ptx
  input files and separating them with nul characters. Actual linking
  is something that happens later, when calling CUDA library functions,
  but existing build system make it useful to have something called
  "ld" which is able to bundle everything that's needed into a single
  file, and this seemed to be the simplest way of achieving this.

There's a toplevel configure.ac change necessary to make ar/ranlib useable by the libgcc build. Having some tools built like this has some precedent in t-vmsnative, but as Thomas noted it does make feature tests in gcc's configure somewhat ugly (but everything works well enough to build the compiler). The alternative here is to bundle all these files into a separate nvptx-tools package which users would have to download - something that would be nice to avoid.

These tools currently require GNU extensions - something I probably ought to fix if we decide to add them to the gcc build itself.


Bernd

	* configure.ac (AR_FOR_TARGET, RANLIB_FOR_TARGET): If nvptx-*,
	look for them in the gcc build directory.
	* configure: Regenerate.

	gcc/
	* config.gcc (nvptx-*): Define extra_programs.
	* config/nvptx/nvptx-as.c: New file.
	* config/nvptx/nvptx-ld.c: New file.
	* config/nvptx/t-nvptx (nvptx-ld.o, nvptx-as.o, collect-ld$(exeext),
	as$(exeext), ar$(exeext), ranlib$(exeext): New rules.

Index: git/gcc/config.gcc
===================================================================
--- git.orig/gcc/config.gcc
+++ git/gcc/config.gcc
@@ -2154,6 +2154,7 @@ nios2-*-*)
 nvptx-*)
 	tm_file="${tm_file} newlib-stdint.h"
 	tmake_file="nvptx/t-nvptx"
+	extra_programs="collect-ld\$(exeext) as\$(exeext) ar\$(exeext) ranlib\$(exeext)"
 	;;
 pdp11-*-*)
 	tm_file="${tm_file} newlib-stdint.h"
Index: git/gcc/config/nvptx/nvptx-as.c
===================================================================
--- /dev/null
+++ git/gcc/config/nvptx/nvptx-as.c
@@ -0,0 +1,961 @@
+/* An "assembler" for ptx.
+   Copyright (C) 2014 Free Software Foundation, Inc.
+   Contributed by Nathan Sidwell <nathan@codesourcery.com>
+   Contributed by Bernd Schmidt <bernds@codesourcery.com>
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published
+   by the Free Software Foundation; either version 3, or (at your
+   option) any later version.
+
+   GCC is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+   License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GCC; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+/* Munges gcc-generated PTX assembly so that it becomes acceptable for ptxas.
+
+   This is not a complete assembler.  We presume the source is well
+   formed from the compiler and can die horribly if it is not.  */
+
+#include <getopt.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <wait.h>
+#include <unistd.h>
+#include <errno.h>
+#define obstack_chunk_alloc malloc
+#define obstack_chunk_free free
+#include <obstack.h>
+#define HAVE_DECL_BASENAME 1
+#include <libiberty.h>
+#include <hashtab.h>
+
+#include <list>
+
+static const char *outname = NULL;
+
+static void __attribute__ ((format (printf, 1, 2)))
+fatal_error (const char * cmsgid, ...)
+{
+  va_list ap;
+
+  va_start (ap, cmsgid);
+  fprintf (stderr, "nvptx-as: ");
+  vfprintf (stderr, cmsgid, ap);
+  fprintf (stderr, "\n");
+  va_end (ap);
+
+  unlink (outname);
+  exit (1);
+}
+
+struct Stmt;
+
+class symbol
+{
+ public:
+  symbol (const char *k) : key (k), stmts (0), pending (0), emitted (0)
+    { }
+
+  /* The name of the symbol.  */
+  const char *key;
+  /* A linked list of dependencies for the initializer.  */
+  std::list<symbol *> deps;
+  /* The statement in which it is defined.  */
+  struct Stmt *stmts;
+  bool pending;
+  bool emitted;
+};
+
+/* Hash and comparison functions for these hash tables.  */
+
+static int hash_string_eq (const void *, const void *);
+static hashval_t hash_string_hash (const void *);
+
+static int
+hash_string_eq (const void *s1_p, const void *s2_p)
+{
+  const char *const *s1 = (const char *const *) s1_p;
+  const char *s2 = (const char *) s2_p;
+  return strcmp (*s1, s2) == 0;
+}
+
+static hashval_t
+hash_string_hash (const void *s_p)
+{
+  const char *const *s = (const char *const *) s_p;
+  return (*htab_hash_string) (*s);
+}
+
+static htab_t symbol_table;
+
+/* Look up an entry in the symbol hash table.  */
+
+static symbol *
+symbol_hash_lookup (const char *string)
+{
+  void **e;
+  e = htab_find_slot_with_hash (symbol_table, string,
+                                (*htab_hash_string) (string),
+                                INSERT);
+  if (e == NULL)
+    return NULL;
+  if (*e == NULL)
+    *e = new symbol (string);
+
+  return (symbol *) *e;
+}
+
+#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;
+  symbol *sym;
+  unsigned char vis;
+  unsigned len : 12;
+} Stmt;
+
+struct id_map
+{
+  id_map *next;
+  char *ptx_name;
+};
+
+#define alloc_comment(S,E) alloc_stmt (V_comment, S, E, 0)
+#define append_stmt(V, S) ((S)->next = *(V), *(V) = (S))
+
+static Stmt *decls;
+static Stmt *fns;
+
+static id_map *func_ids, **funcs_tail = &func_ids;
+static id_map *var_ids, **vars_tail = &var_ids;
+
+static void
+record_id (const char *p1, id_map ***where)
+{
+  const char *end = strchr (p1, '\n');
+  if (!end)
+    fatal_error ("malformed ptx file");
+
+  id_map *v = XNEW (id_map);
+  size_t len = end - p1;
+  v->ptx_name = XNEWVEC (char, len + 1);
+  memcpy (v->ptx_name, p1, len);
+  v->ptx_name[len] = '\0';
+  v->next = NULL;
+  id_map **tail = *where;
+  *tail = v;
+  *where = &v->next;
+}
+
+/* Read the whole input file.  It will be NUL terminated (but
+   remember, there could be a NUL in the file itself.  */
+
+static const char *
+read_file (FILE *stream)
+{
+  size_t alloc = 16384;
+  size_t base = 0;
+  char *buffer;
+
+  if (!fseek (stream, 0, SEEK_END))
+    {
+      /* Get the file size.  */
+      long s = ftell (stream);
+      if (s >= 0)
+	alloc = s + 100;
+      fseek (stream, 0, SEEK_SET);
+    }
+  buffer = XNEWVEC (char, alloc);
+
+  for (;;)
+    {
+      size_t n = fread (buffer + base, 1, alloc - base - 1, stream);
+
+      if (!n)
+	break;
+      base += n;
+      if (base + 1 == alloc)
+	{
+	  alloc *= 2;
+	  buffer = XRESIZEVEC (char, buffer, alloc);
+	}
+    }
+  buffer[base] = 0;
+  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 Stmt *
+alloc_stmt (unsigned vis, Token *tokens, Token *end, symbol *sym)
+{
+  static unsigned alloc = 0;
+  static Stmt *heap = 0;
+
+  if (!alloc)
+    {
+      alloc = 1000;
+      heap = XNEWVEC (Stmt, alloc);
+    }
+
+  Stmt *stmt = heap++;
+  alloc--;
+
+  tokens->space = 0;
+  stmt->next = 0;
+  stmt->vis = vis;
+  stmt->tokens = tokens;
+  stmt->len = end - tokens;
+  stmt->sym = sym;
+
+  return stmt;
+}
+
+static Stmt *
+rev_stmts (Stmt *stmt)
+{
+  Stmt *prev = 0;
+  Stmt *next;
+
+  while (stmt)
+    {
+      next = stmt->next;
+      stmt->next = prev;
+      prev = stmt;
+      stmt = next;
+    }
+
+  return prev;
+}
+
+static void
+write_stmt (FILE *out, const Stmt *stmt)
+{
+  for (int i = 0; i < stmt->len; i++)
+    {
+      if ((stmt->vis & V_mask) == V_comment)
+	fprintf (out, "//");
+      write_token (out, stmt->tokens + i);
+      if ((stmt->vis & V_mask) == V_pred)
+	fputc (' ', out);
+    }
+}
+
+static void
+write_stmts (FILE *out, const Stmt *stmts)
+{
+  for (; stmts; stmts = stmts->next)
+    write_stmt (out, stmts);
+}
+
+static Token *
+parse_insn (Token *tok)
+{
+  unsigned depth = 0;
+
+  do
+    {
+      Stmt *stmt;
+      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:
+	  tok[-1].end = 1;
+	  s = V_label;
+	  break;
+
+	case '@':
+	  tok->space = 0;
+	  if (tok->kind == '!')
+	    tok++;
+	  tok++;
+	  s = V_pred;
+	  break;
+
+	default:
+	  for (; tok->kind != ';'; tok++)
+	    {
+	      if (tok->kind == ',')
+		tok[1].space = 0;
+	    }
+	  tok++->end = 1;
+	  break;
+	}
+
+      stmt = alloc_stmt (s, start, tok, 0);
+      append_stmt (&fns, stmt);
+
+      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++;
+	}
+    }
+  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;
+}
+
+#define is_keyword(T,S) \
+  (sizeof (S) == (T)->len && !memcmp ((T)->ptr + 1, (S), (T)->len - 1))
+
+static Token *
+parse_init (Token *tok, symbol *sym)
+{
+  for (;;)
+    {
+      Token *start = tok;
+      Token *def_tok = 0;
+      Stmt *stmt;
+
+      if (tok->kind == K_comment)
+	{
+	  while (tok->kind == K_comment)
+	    tok++;
+	  stmt = alloc_comment (start, tok);
+	  append_stmt (&sym->stmts, stmt);
+	  start = tok;
+	}
+
+      if (tok->kind == '{')
+	tok[1].space = 0;
+      /* Find the last symbol before the next comma.  This allows us
+	 to do the right thing for constructs like "generic (sym)".  */
+      for (; tok->kind != ',' && tok->kind != ';'; tok++)
+	if (tok->kind == K_symbol || tok->kind == K_ident)
+	  def_tok = tok;
+      if (def_tok)
+	sym->deps.push_back (symbol_hash_lookup (xstrndup (def_tok->ptr,
+							   def_tok->len)));
+      tok[1].space = 0;
+      int end = tok++->kind == ';';
+      stmt = alloc_stmt (V_insn, start, tok, 0);
+      append_stmt (&sym->stmts, stmt);
+      if (!tok[-1].end && tok->kind == K_comment)
+	{
+	  stmt->vis |= V_no_eol;
+	  stmt = alloc_comment (tok, tok + 1);
+	  append_stmt (&sym->stmts, stmt);
+	  tok++;
+	}
+      if (end)
+	break;
+    }
+  return tok;
+}
+
+static Token *
+parse_file (Token *tok)
+{
+  Stmt *comment = 0;
+
+  if (tok->kind == K_comment)
+    {
+      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;
+    }
+
+  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
+	{
+	  unsigned vis = 0;
+	  symbol *def = 0;
+	  unsigned is_decl = 0;
+	  Token *start, *def_token = 0;
+
+	  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 || tok->kind == K_ident)
+		def_token = tok;
+	    }
+	  if (def_token)
+	    def = symbol_hash_lookup (xstrndup (def_token->ptr, def_token->len));
+
+	  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
+	    {
+	      int assign = tok->kind == '=';
+
+	      tok++->end = 1;
+	      if ((vis & V_mask) == V_var && !is_decl)
+		{
+		  /* variable */
+		  Stmt *stmt = alloc_stmt (vis, start, tok, def);
+		  if (comment)
+		    {
+		      append_stmt (&def->stmts, comment);
+		      stmt->vis |= V_prefix_comment;
+		    }
+		  append_stmt (&def->stmts, stmt);
+		  if (assign)
+		    tok = parse_init (tok, def);
+		}
+	      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);
+		}
+	    }
+	}
+    }
+  else
+    {
+      /* Something strange.  Ignore it.  */
+      if (comment)
+	append_stmt (&fns, comment);
+
+      while (tok->kind && !tok->end)
+	tok++;
+      if (tok->kind)
+	tok++;
+    }
+  return tok;
+}
+
+static void
+output_symbol (FILE *out, symbol *e)
+{
+  if (e->emitted)
+    return;
+  if (e->pending)
+    fatal_error ("circular reference in variable initializers");
+  e->pending = true;
+  std::list<symbol *>::iterator i;
+  for (i = e->deps.begin (); i != e->deps.end (); i++)
+    output_symbol (out, *i);
+  e->pending = false;
+  write_stmts (out, rev_stmts (e->stmts));
+  e->emitted = true;
+}
+
+static int
+traverse (void **slot, void *data)
+{
+  symbol *e = *(symbol **)slot;
+  output_symbol ((FILE *)data, e);
+  return 1;
+}
+
+static void
+process (FILE *in, FILE *out)
+{
+  symbol_table = htab_create (500, hash_string_hash, hash_string_eq,
+                              NULL);
+
+  const char *input = read_file (in);
+  Token *tok = tokenize (input);
+
+  do
+    tok = parse_file (tok);
+  while (tok->kind);
+
+  write_stmts (out, rev_stmts (decls));
+  htab_traverse (symbol_table, traverse, (void *)out);
+  write_stmts (out, rev_stmts (fns));
+}
+
+/* Wait for a process to finish, and exit if a nonzero status is found.  */
+
+int
+collect_wait (const char *prog, struct pex_obj *pex)
+{
+  int status;
+
+  if (!pex_get_status (pex, 1, &status))
+    fatal_error ("can't get program status: %m");
+  pex_free (pex);
+
+  if (status)
+    {
+      if (WIFSIGNALED (status))
+	{
+	  int sig = WTERMSIG (status);
+	  fatal_error ("%s terminated with signal %d [%s]%s",
+		       prog, sig, strsignal(sig),
+		       WCOREDUMP(status) ? ", core dumped" : "");
+	}
+
+      if (WIFEXITED (status))
+	return WEXITSTATUS (status);
+    }
+  return 0;
+}
+
+static void
+do_wait (const char *prog, struct pex_obj *pex)
+{
+  int ret = collect_wait (prog, pex);
+  if (ret != 0)
+    {
+      fatal_error ("%s returned %d exit status", prog, ret);
+    }
+}
+
+
+/* Execute a program, and wait for the reply.  */
+static void
+fork_execute (const char *prog, char *const *argv)
+{
+  struct pex_obj *pex = pex_init (0, "nvptx-as", NULL);
+  if (pex == NULL)
+    fatal_error ("pex_init failed: %m");
+
+  int err;
+  const char *errmsg;
+
+  errmsg = pex_run (pex, PEX_LAST | PEX_SEARCH, argv[0], argv, NULL,
+		    NULL, &err);
+  if (errmsg != NULL)
+    {
+      if (err != 0)
+	{
+	  errno = err;
+	  fatal_error ("%s: %m", errmsg);
+	}
+      else
+	fatal_error (errmsg);
+    }
+  do_wait (prog, pex);
+}
+
+static struct option long_options[] = {
+  {"traditional-format",     no_argument, 0,  0 },
+  {"save-temps",  no_argument,       0,  0 },
+  {"no-verify",  no_argument,       0,  0 },
+  {0,         0,                 0,  0 }
+};
+
+int
+main (int argc, char **argv)
+{
+  FILE *in = stdin;
+  FILE *out = stdout;
+  bool verbose __attribute__((unused)) = false;
+  bool verify = true;
+
+  int o;
+  int option_index = 0;
+  while ((o = getopt_long (argc, argv, "o:I:v", long_options, &option_index)) != -1)
+    {
+      switch (o)
+	{
+	case 0:
+	  if (option_index == 2)
+	    verify = false;
+	  break;
+	case 'v':
+	  verbose = true;
+	  break;
+	case 'o':
+	  if (outname != NULL)
+	    {
+	      fprintf (stderr, "multiple output files specified\n");
+	      exit (1);
+	    }
+	  outname = optarg;
+	  break;
+	case 'I':
+	  /* Ignore include paths.  */
+	  break;
+	default:
+	  break;
+	}
+    }
+
+  if (optind + 1 != argc)
+    fatal_error ("not exactly one input file specified");
+
+  out = fopen (outname, "w");
+  if (!out)
+    fatal_error ("cannot open '%s'", outname);
+
+  in = fopen (argv[optind], "r");
+  if (!in)
+    fatal_error ("cannot open input ptx file");
+
+  process (in, out);
+  fclose (out);
+
+  if (verify)
+    {
+      struct obstack argv_obstack;
+      obstack_init (&argv_obstack);
+      obstack_ptr_grow (&argv_obstack, "ptxas");
+      obstack_ptr_grow (&argv_obstack, "-c");
+      obstack_ptr_grow (&argv_obstack, "-o");
+      obstack_ptr_grow (&argv_obstack, "/dev/null");
+      obstack_ptr_grow (&argv_obstack, outname);
+      obstack_ptr_grow (&argv_obstack, "--gpu-name");
+      obstack_ptr_grow (&argv_obstack, "sm_30");
+      obstack_ptr_grow (&argv_obstack, NULL);
+      char *const *new_argv = XOBFINISH (&argv_obstack, char *const *);
+      fork_execute (new_argv[0], new_argv);
+    }
+  return 0;
+}
Index: git/gcc/config/nvptx/nvptx-ld.c
===================================================================
--- /dev/null
+++ git/gcc/config/nvptx/nvptx-ld.c
@@ -0,0 +1,498 @@
+/* An "linker" for ptx.
+   Copyright (C) 2014 Free Software Foundation, Inc.
+   Contributed by Bernd Schmidt <bernds@codesourcery.com>
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published
+   by the Free Software Foundation; either version 3, or (at your
+   option) any later version.
+
+   GCC is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+   License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GCC; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <getopt.h>
+#include <unistd.h>
+#include <assert.h>
+
+#include "hashtab.h"
+#include "obstack.h"
+#define HAVE_DECL_BASENAME 1
+#include "libiberty.h"
+
+#include <list>
+#include <string>
+#include <iostream>
+
+struct file_hash_entry;
+
+typedef struct symbol_hash_entry
+{
+  /* The name of the symbol.  */
+  const char *key;
+  /* A linked list of unresolved referenced symbols.  */
+  struct symbol_hash_entry **pprev, *next;
+  /* The file in which it is defined.  */
+  struct file_hash_entry *def;
+  int included;
+  int referenced;
+} symbol;
+
+typedef struct file_hash_entry
+{
+  struct file_hash_entry **pprev, *next;
+  const char *name;
+  const char *arname;
+  const char *data;
+  size_t len;
+} file;
+
+/* Hash and comparison functions for these hash tables.  */
+
+static int hash_string_eq (const void *, const void *);
+static hashval_t hash_string_hash (const void *);
+
+static int
+hash_string_eq (const void *s1_p, const void *s2_p)
+{
+  const char *const *s1 = (const char *const *) s1_p;
+  const char *s2 = (const char *) s2_p;
+  return strcmp (*s1, s2) == 0;
+}
+
+static hashval_t
+hash_string_hash (const void *s_p)
+{
+  const char *const *s = (const char *const *) s_p;
+  return (*htab_hash_string) (*s);
+}
+
+static htab_t symbol_table;
+
+/* Look up an entry in the symbol hash table.  */
+
+static struct symbol_hash_entry *
+symbol_hash_lookup (const char *string, int create)
+{
+  void **e;
+  e = htab_find_slot_with_hash (symbol_table, string,
+                                (*htab_hash_string) (string),
+                                create ? INSERT : NO_INSERT);
+  if (e == NULL)
+    return NULL;
+  if (*e == NULL)
+    {
+      struct symbol_hash_entry *v;
+      *e = v = XCNEW (struct symbol_hash_entry);
+      v->key = string;
+    }
+  return (struct symbol_hash_entry *) *e;
+}
+
+static struct file_hash_entry *
+file_hash_new (const char *data, size_t len, const char *arname, const char *name)
+{
+  struct file_hash_entry *v = XCNEW (struct file_hash_entry);
+  v->data = data;
+  v->len = len;
+  v->name = xstrdup (name);
+  v->arname = xstrdup (arname);
+  return v;
+}
+
+using namespace std;
+
+#define ARMAG  "!<arch>\012"    /* For COFF and a.out archives.  */
+#define SARMAG 8
+#define ARFMAG "`\012"
+
+struct ar_hdr
+{
+  char ar_name[16];             /* Name of this member.  */
+  char ar_date[12];             /* File mtime.  */
+  char ar_uid[6];               /* Owner uid; printed as decimal.  */
+  char ar_gid[6];               /* Owner gid; printed as decimal.  */
+  char ar_mode[8];              /* File mode, printed as octal.   */
+  char ar_size[10];             /* File size, printed as decimal.  */
+  char ar_fmag[2];              /* Should contain ARFMAG.  */
+};
+
+class archive
+{
+  FILE *f;
+  off_t flen;
+  off_t off;
+
+  char name[17];
+  char *contents;
+  size_t len;
+
+ public:
+  archive () : f (NULL), contents (NULL) { }
+  ~archive ()
+  {
+    discard_contents ();
+  }
+  void discard_contents ()
+  {
+    if (contents)
+      delete[] contents;
+    contents = NULL;
+  }
+  bool init (FILE *file)
+  {
+    char magic[SARMAG];
+    if (fread (magic, 1, SARMAG, file) != SARMAG)
+      return false;
+    if (memcmp (magic, ARMAG, SARMAG) != 0)
+      return false;
+    f = file;
+    fseek (f, 0, SEEK_END);
+    flen = ftell (f);
+    fseek (f, SARMAG, SEEK_SET);
+    off = SARMAG;
+
+    struct ar_hdr hdr;
+    if (fread (&hdr, sizeof hdr, 1, f) != 1)
+      return false;
+    if (hdr.ar_name[0] == '/' || hdr.ar_name[0] == ' ')
+      {
+	off += sizeof hdr;
+	long l = atol (hdr.ar_size);
+	if (l < 0 || off + l > flen)
+	  return false;
+	off += l;
+      }
+
+    fseek (f, off, SEEK_SET);
+    return true;
+  }
+
+  bool at_end ()
+  {
+    return off == flen;
+  }
+
+  bool next_file ()
+  {
+    discard_contents ();
+
+    struct ar_hdr hdr;
+    if (fread (&hdr, sizeof hdr, 1, f) != 1)
+      return false;
+    off += sizeof hdr;
+    long l = atol (hdr.ar_size);
+    if (l <= 0 || l > flen)
+      return false;
+    size_t read_len = l + (l & 1);
+    len = l;
+    contents = new char[read_len];
+    if (contents == NULL)
+      return false;
+    if (fread (contents, 1, read_len, f) != read_len)
+      return false;
+    off += read_len;
+    memcpy (name, hdr.ar_name, sizeof hdr.ar_name);
+    name[16] = '\0';
+    return true;
+  }
+  const char *get_contents () { return contents; }
+  const char *get_name () { return name; }
+  size_t get_len () { return len; }
+};
+
+FILE *
+path_open (const char *filename, list<string> &paths)
+{
+  FILE *f = fopen (filename, "r");
+  if (f)
+    return f;
+  if (strchr (filename, '/') != NULL)
+    return NULL;
+
+  for (list<string>::const_iterator iterator = paths.begin(), end = paths.end();
+       iterator != end;
+       ++iterator)
+    {
+      string tmp = *iterator;
+      tmp += '/';
+      tmp += filename;
+      FILE *f = fopen (tmp.c_str (), "r");
+      if (f)
+	return f;
+    }
+  return NULL;
+}
+
+static struct symbol_hash_entry *unresolved;
+
+static void
+enqueue_as_unresolved (struct symbol_hash_entry *e)
+{
+  e->pprev = &unresolved;
+  e->next = unresolved;
+  if (e->next)
+    e->next->pprev = &e->next;
+  unresolved = e;
+  e->referenced = true;
+}
+
+static void
+dequeue_unresolved (struct symbol_hash_entry *e)
+{
+  if (e->pprev != NULL)
+    {
+      if (e->next)
+	e->next->pprev = e->pprev;
+      *e->pprev = e->next;
+    }
+  e->pprev = NULL;
+}
+
+static void
+process_refs_defs (file *f, const char *ptx)
+{
+  while (*ptx != '\0')
+    {
+      if (strncmp (ptx, "\n// BEGIN GLOBAL ", 17) == 0)
+	{
+	  int type = 0;
+	  ptx += 17;
+	  if (strncmp (ptx, "VAR DEF: ", 9) == 0)
+	    {
+	      type = 1;
+	      ptx += 9;
+	    }
+	  else if (strncmp (ptx, "FUNCTION DEF: ", 14) == 0)
+	    {
+	      type = 1;
+	      ptx += 14;
+	    }
+	  if (strncmp (ptx, "VAR DECL: ", 10) == 0)
+	    {
+	      type = 2;
+	      ptx += 10;
+	    }
+	  else if (strncmp (ptx, "FUNCTION DECL: ", 15) == 0)
+	    {
+	      type = 2;
+	      ptx += 15;
+	    }
+	  if (type == 0)
+	    continue;
+	  const char *end = strchr (ptx, '\n');
+	  if (end == 0)
+	    end = ptx + strlen (ptx);
+	  if ((end - ptx == 6 && memcmp (ptx, "malloc", 6) == 0)
+	      || (end - ptx == 4 && memcmp (ptx, "free", 4) == 0)
+	      || (end - ptx == 7 && memcmp (ptx, "vprintf", 7) == 0))
+	    continue;
+	  const char *sym = xstrndup (ptx, end - ptx);
+	  struct symbol_hash_entry *e = symbol_hash_lookup (sym, 1);
+
+	  if (!e->included)
+	    {
+	      if (type == 1)
+		{
+		  if (f == NULL)
+		    {
+		      e->included = true;
+		      dequeue_unresolved (e);
+		    }
+		  else
+		    e->def = f;
+		}
+	      else
+		{
+		  if (f == NULL)
+		    {
+		      if (!e->referenced)
+			enqueue_as_unresolved (e);
+		    }
+		}
+	    }
+	}
+      ptx++;
+    }
+}
+
+int
+main (int argc, char **argv)
+{
+  const char *outname = NULL;
+  list<string> libraries;
+  list<string> libpaths;
+  bool verbose = false;
+
+  int o;
+  while ((o = getopt (argc, argv, "L:l:o:v")) != -1)
+    {
+      switch (o)
+	{
+	case 'v':
+	  verbose = true;
+	  break;
+	case 'o':
+	  if (outname != NULL)
+	    {
+	      cerr << "multiple output files specified\n";
+	      exit (1);
+	    }
+	  outname = optarg;
+	  break;
+	case 'l':
+	  libraries.push_back (optarg);
+	  break;
+	case 'L':
+	  libpaths.push_back (optarg);
+	  break;
+	default:
+	  break;
+	}
+    }
+
+  libraries.sort ();
+  libraries.unique ();
+  libpaths.unique ();
+
+  if (outname == NULL)
+    outname = "a.out";
+
+  symbol_table = htab_create (500, hash_string_hash, hash_string_eq,
+                              NULL);
+
+  FILE *outfile = fopen (outname, "w");
+  if (outfile == NULL)
+    {
+      cerr << "error opening output file\n";
+      exit (1);
+    }
+  list<string> inputfiles;
+  while (optind < argc)
+    inputfiles.push_back (argv[optind++]);
+
+  int idx = 0;
+  for (list<string>::const_iterator iterator = inputfiles.begin(), end = inputfiles.end();
+       iterator != end;
+       ++iterator)
+    {
+      const string &name = *iterator;
+      FILE *f = path_open (name.c_str (), libpaths);
+      if (f == NULL)
+	{
+	  cerr << "error opening " << name << "\n";
+	  goto error_out;
+	}
+      fseek (f, 0, SEEK_END);
+      off_t len = ftell (f);
+      fseek (f, 0, SEEK_SET);
+      char *buf = new char[len + 1];
+      fread (buf, 1, len, f);
+      buf[len] = '\0';
+      if (ferror (f))
+	{
+	  cerr << "error reading " << name << "\n";
+	  goto error_out;
+	}
+      size_t out = fwrite (buf, 1, len, outfile);
+      if (out != len)
+	{
+	  cerr << "error writing to output file\n";
+	  goto error_out;
+	}
+      process_refs_defs (NULL, buf);
+      free (buf);
+      if (verbose)
+	cout << "Linking " << name << " as " << idx++ << "\n";
+      fputc ('\0', outfile);
+    }
+  for (list<string>::const_iterator iterator = libraries.begin(), end = libraries.end();
+       iterator != end;
+       ++iterator)
+    {
+      const string &name = "lib" + *iterator + ".a";
+      if (verbose)
+	cout << "trying lib " << name << "\n";
+      FILE *f = path_open (name.c_str (), libpaths);
+      if (f == NULL)
+	{
+	  cerr << "error opening " << name << "\n";
+	  goto error_out;
+	}
+      archive ar;
+      if (!ar.init (f))
+	{
+	  cerr << name << " is not a valid archive\n";
+	  goto error_out;
+	}
+      while (!ar.at_end ())
+	{
+	  if (!ar.next_file ())
+	    {
+	      cerr << "error reading from archive " << name << "\n";
+	      goto error_out;
+	    }
+	  const char *p = xstrdup (ar.get_contents ());
+	  size_t len = ar.get_len ();
+	  file *f = file_hash_new (p, len, name.c_str (), ar.get_name ());
+	  process_refs_defs (f, p);
+	}
+    }
+
+  while (unresolved)
+    {
+      struct file_hash_entry *to_add = NULL;
+      struct symbol_hash_entry *e;
+      for (e = unresolved; e; e = e->next)
+	{
+	  struct file_hash_entry *f = e->def;
+	  if (!f)
+	    {
+	      cerr << "unresolved symbol " << e->key << "\n";
+	      goto error_out;
+	    }
+	  if (verbose)
+	    cout << "Resolving " << e->key << "\n";
+	  if (!f->pprev)
+	    {
+	      f->pprev = &to_add;
+	      f->next = to_add;
+	      to_add = f;
+	    }
+	  e->included = true;
+	  e->pprev = NULL;
+	}
+      unresolved = NULL;
+      assert (to_add != NULL);
+      struct file_hash_entry *f;
+      for (f = to_add; f; f = f->next)
+	{
+	  f->pprev = NULL;
+	  if (verbose)
+	    cout << "Linking " << f->arname << "::" << f->name << " as " << idx++ << "\n";
+	  if (fwrite (f->data, 1, f->len, outfile) != f->len)
+	    {
+	      cerr << "error writing to output file\n";
+	      goto error_out;
+	    }
+	  fputc ('\0', outfile);
+	  process_refs_defs (NULL, f->data);
+	}
+    }
+  return 0;
+
+ error_out:
+  fclose (outfile);
+  unlink (outname);
+  return 1;
+}
Index: git/gcc/config/nvptx/t-nvptx
===================================================================
--- git.orig/gcc/config/nvptx/t-nvptx
+++ git/gcc/config/nvptx/t-nvptx
@@ -1,2 +1,27 @@
 #
 
+nvptx-ld.o: $(srcdir)/config/nvptx/nvptx-ld.c
+	$(COMPILE) $<
+	$(POSTCOMPILE)
+
+collect-ld$(exeext): nvptx-ld.o $(LIBIBERTY)
+	+$(LINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) -o $@ \
+	  nvptx-ld.o $(LIBIBERTY)
+
+nvptx-as.o: $(srcdir)/config/nvptx/nvptx-as.c
+	$(COMPILE) $<
+	$(POSTCOMPILE)
+
+as$(exeext): nvptx-as.o $(LIBIBERTY)
+	+$(LINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) -o $@ \
+	  nvptx-as.o $(LIBIBERTY)
+
+ar$(exeext):
+	echo -e "#! /bin/sh\n$(AR) \"$$""@\"" >$@
+	chmod a+x $@
+
+ranlib$(exeext):
+	echo -e "#! /bin/sh\n$(RANLIB) \"$$""@\"" >$@
+	chmod a+x $@
+
+
Index: git/configure
===================================================================
--- git.orig/configure
+++ git/configure
@@ -13607,7 +13607,95 @@ fi
 
 RAW_CXX_FOR_TARGET="$CXX_FOR_TARGET"
 
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking where to find the target ar" >&5
+case "${target}" in
+  nvptx-*)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking where to find the target ar" >&5
+$as_echo_n "checking where to find the target ar... " >&6; }
+if test "x${build}" != "x${host}" ; then
+  if expr "x$AR_FOR_TARGET" : "x/" > /dev/null; then
+    # We already found the complete path
+    ac_dir=`dirname $AR_FOR_TARGET`
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: pre-installed in $ac_dir" >&5
+$as_echo "pre-installed in $ac_dir" >&6; }
+  else
+    # Canadian cross, just use what we found
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: pre-installed" >&5
+$as_echo "pre-installed" >&6; }
+  fi
+else
+  ok=yes
+  case " ${configdirs} " in
+    *" gcc "*) ;;
+    *) ok=no ;;
+  esac
+
+  if test $ok = yes; then
+    # An in-tree tool is available and we can use it
+    AR_FOR_TARGET='$$r/$(HOST_SUBDIR)/gcc/ar'
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: just compiled" >&5
+$as_echo "just compiled" >&6; }
+  elif expr "x$AR_FOR_TARGET" : "x/" > /dev/null; then
+    # We already found the complete path
+    ac_dir=`dirname $AR_FOR_TARGET`
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: pre-installed in $ac_dir" >&5
+$as_echo "pre-installed in $ac_dir" >&6; }
+  elif test "x$target" = "x$host"; then
+    # We can use an host tool
+    AR_FOR_TARGET='$(AR)'
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: host tool" >&5
+$as_echo "host tool" >&6; }
+  else
+    # We need a cross tool
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: pre-installed" >&5
+$as_echo "pre-installed" >&6; }
+  fi
+fi
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking where to find the target ranlib" >&5
+$as_echo_n "checking where to find the target ranlib... " >&6; }
+if test "x${build}" != "x${host}" ; then
+  if expr "x$RANLIB_FOR_TARGET" : "x/" > /dev/null; then
+    # We already found the complete path
+    ac_dir=`dirname $RANLIB_FOR_TARGET`
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: pre-installed in $ac_dir" >&5
+$as_echo "pre-installed in $ac_dir" >&6; }
+  else
+    # Canadian cross, just use what we found
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: pre-installed" >&5
+$as_echo "pre-installed" >&6; }
+  fi
+else
+  ok=yes
+  case " ${configdirs} " in
+    *" gcc "*) ;;
+    *) ok=no ;;
+  esac
+
+  if test $ok = yes; then
+    # An in-tree tool is available and we can use it
+    RANLIB_FOR_TARGET='$$r/$(HOST_SUBDIR)/gcc/ranlib'
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: just compiled" >&5
+$as_echo "just compiled" >&6; }
+  elif expr "x$RANLIB_FOR_TARGET" : "x/" > /dev/null; then
+    # We already found the complete path
+    ac_dir=`dirname $RANLIB_FOR_TARGET`
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: pre-installed in $ac_dir" >&5
+$as_echo "pre-installed in $ac_dir" >&6; }
+  elif test "x$target" = "x$host"; then
+    # We can use an host tool
+    RANLIB_FOR_TARGET='$(RANLIB)'
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: host tool" >&5
+$as_echo "host tool" >&6; }
+  else
+    # We need a cross tool
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: pre-installed" >&5
+$as_echo "pre-installed" >&6; }
+  fi
+fi
+
+    ;;
+  *)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking where to find the target ar" >&5
 $as_echo_n "checking where to find the target ar... " >&6; }
 if test "x${build}" != "x${host}" ; then
   if expr "x$AR_FOR_TARGET" : "x/" > /dev/null; then
@@ -13649,6 +13737,50 @@ $as_echo "pre-installed" >&6; }
   fi
 fi
 
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking where to find the target ranlib" >&5
+$as_echo_n "checking where to find the target ranlib... " >&6; }
+if test "x${build}" != "x${host}" ; then
+  if expr "x$RANLIB_FOR_TARGET" : "x/" > /dev/null; then
+    # We already found the complete path
+    ac_dir=`dirname $RANLIB_FOR_TARGET`
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: pre-installed in $ac_dir" >&5
+$as_echo "pre-installed in $ac_dir" >&6; }
+  else
+    # Canadian cross, just use what we found
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: pre-installed" >&5
+$as_echo "pre-installed" >&6; }
+  fi
+else
+  ok=yes
+  case " ${configdirs} " in
+    *" binutils "*) ;;
+    *) ok=no ;;
+  esac
+
+  if test $ok = yes; then
+    # An in-tree tool is available and we can use it
+    RANLIB_FOR_TARGET='$$r/$(HOST_SUBDIR)/binutils/ranlib'
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: just compiled" >&5
+$as_echo "just compiled" >&6; }
+  elif expr "x$RANLIB_FOR_TARGET" : "x/" > /dev/null; then
+    # We already found the complete path
+    ac_dir=`dirname $RANLIB_FOR_TARGET`
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: pre-installed in $ac_dir" >&5
+$as_echo "pre-installed in $ac_dir" >&6; }
+  elif test "x$target" = "x$host"; then
+    # We can use an host tool
+    RANLIB_FOR_TARGET='$(RANLIB)'
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: host tool" >&5
+$as_echo "host tool" >&6; }
+  else
+    # We need a cross tool
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: pre-installed" >&5
+$as_echo "pre-installed" >&6; }
+  fi
+fi
+
+    ;;
+esac
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking where to find the target as" >&5
 $as_echo_n "checking where to find the target as... " >&6; }
 if test "x${build}" != "x${host}" ; then
@@ -14193,48 +14325,6 @@ $as_echo "pre-installed in $ac_dir" >&6;
     { $as_echo "$as_me:${as_lineno-$LINENO}: result: host tool" >&5
 $as_echo "host tool" >&6; }
   else
-    # We need a cross tool
-    { $as_echo "$as_me:${as_lineno-$LINENO}: result: pre-installed" >&5
-$as_echo "pre-installed" >&6; }
-  fi
-fi
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking where to find the target ranlib" >&5
-$as_echo_n "checking where to find the target ranlib... " >&6; }
-if test "x${build}" != "x${host}" ; then
-  if expr "x$RANLIB_FOR_TARGET" : "x/" > /dev/null; then
-    # We already found the complete path
-    ac_dir=`dirname $RANLIB_FOR_TARGET`
-    { $as_echo "$as_me:${as_lineno-$LINENO}: result: pre-installed in $ac_dir" >&5
-$as_echo "pre-installed in $ac_dir" >&6; }
-  else
-    # Canadian cross, just use what we found
-    { $as_echo "$as_me:${as_lineno-$LINENO}: result: pre-installed" >&5
-$as_echo "pre-installed" >&6; }
-  fi
-else
-  ok=yes
-  case " ${configdirs} " in
-    *" binutils "*) ;;
-    *) ok=no ;;
-  esac
-
-  if test $ok = yes; then
-    # An in-tree tool is available and we can use it
-    RANLIB_FOR_TARGET='$$r/$(HOST_SUBDIR)/binutils/ranlib'
-    { $as_echo "$as_me:${as_lineno-$LINENO}: result: just compiled" >&5
-$as_echo "just compiled" >&6; }
-  elif expr "x$RANLIB_FOR_TARGET" : "x/" > /dev/null; then
-    # We already found the complete path
-    ac_dir=`dirname $RANLIB_FOR_TARGET`
-    { $as_echo "$as_me:${as_lineno-$LINENO}: result: pre-installed in $ac_dir" >&5
-$as_echo "pre-installed in $ac_dir" >&6; }
-  elif test "x$target" = "x$host"; then
-    # We can use an host tool
-    RANLIB_FOR_TARGET='$(RANLIB)'
-    { $as_echo "$as_me:${as_lineno-$LINENO}: result: host tool" >&5
-$as_echo "host tool" >&6; }
-  else
     # We need a cross tool
     { $as_echo "$as_me:${as_lineno-$LINENO}: result: pre-installed" >&5
 $as_echo "pre-installed" >&6; }
Index: git/configure.ac
===================================================================
--- git.orig/configure.ac
+++ git/configure.ac
@@ -3271,7 +3271,16 @@ ACX_CHECK_INSTALLED_TARGET_TOOL(WINDMC_F
 
 RAW_CXX_FOR_TARGET="$CXX_FOR_TARGET"
 
-GCC_TARGET_TOOL(ar, AR_FOR_TARGET, AR, [binutils/ar])
+case "${target}" in
+  nvptx-*)
+    GCC_TARGET_TOOL(ar, AR_FOR_TARGET, AR, [gcc/ar])
+    GCC_TARGET_TOOL(ranlib, RANLIB_FOR_TARGET, RANLIB, [gcc/ranlib])
+    ;;
+  *)
+    GCC_TARGET_TOOL(ar, AR_FOR_TARGET, AR, [binutils/ar])
+    GCC_TARGET_TOOL(ranlib, RANLIB_FOR_TARGET, RANLIB, [binutils/ranlib])
+    ;;
+esac
 GCC_TARGET_TOOL(as, AS_FOR_TARGET, AS, [gas/as-new])
 GCC_TARGET_TOOL(cc, CC_FOR_TARGET, CC, [gcc/xgcc -B$$r/$(HOST_SUBDIR)/gcc/])
 dnl see comments for CXX_FOR_TARGET_FLAG_TO_PASS
@@ -3293,7 +3302,6 @@ GCC_TARGET_TOOL(ld, LD_FOR_TARGET, LD, [
 GCC_TARGET_TOOL(lipo, LIPO_FOR_TARGET, LIPO)
 GCC_TARGET_TOOL(nm, NM_FOR_TARGET, NM, [binutils/nm-new])
 GCC_TARGET_TOOL(objdump, OBJDUMP_FOR_TARGET, OBJDUMP, [binutils/objdump])
-GCC_TARGET_TOOL(ranlib, RANLIB_FOR_TARGET, RANLIB, [binutils/ranlib])
 GCC_TARGET_TOOL(readelf, READELF_FOR_TARGET, READELF, [binutils/readelf])
 GCC_TARGET_TOOL(strip, STRIP_FOR_TARGET, STRIP, [binutils/strip-new])
 GCC_TARGET_TOOL(windres, WINDRES_FOR_TARGET, WINDRES, [binutils/windres])

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]