2015-11-27  Nathan Sidwell  <nathan@acm.org>

	* config/nvptx/nvptx-protos.h (nvptx_record_needed_decl): Don't
	declaree.
	* config/nvptx/nvptx.c (write_func_decl_from_insn): Move earlier.
	(nvptx_record_fndecl): Don't return value, remove force
	argyment. Require fndecl.
	(nvptx_record_libfunc): New.
	(nvptx_record_needed_decl): Deteermine how to record decl here.
	(nvptx_maybe_record_fnsym): New.
	(nvptx_expand_call): Don't record libfuncs here,
	(nvptx_maybe_convert_symbolic_operand): Use
	nvptx_maye_record_fnsym.
	(nvptx_assemble_integer): Reimplement with single switch.
	(nvptx_output_call_insn): Register libfuncs here.
	(nvptx_file_end): Adjust  nvptx_record_fndecl call.
	* config/nvptx/nvptx.md (expand_movdi): Don't call
	nvptx_record_needed_decl.

Index: config/nvptx/nvptx-protos.h
===================================================================
--- config/nvptx/nvptx-protos.h	(revision 231012)
+++ config/nvptx/nvptx-protos.h	(working copy)
@@ -24,7 +24,6 @@
 extern void nvptx_declare_function_name (FILE *, const char *, const_tree decl);
 extern void nvptx_declare_object_name (FILE *file, const char *name,
 				       const_tree decl);
-extern void nvptx_record_needed_fndecl (tree decl);
 extern void nvptx_function_end (FILE *);
 extern void nvptx_output_skip (FILE *, unsigned HOST_WIDE_INT);
 extern void nvptx_output_ascii (FILE *, const char *, unsigned HOST_WIDE_INT);
Index: config/nvptx/nvptx.c
===================================================================
--- config/nvptx/nvptx.c	(revision 231012)
+++ config/nvptx/nvptx.c	(working copy)
@@ -452,6 +452,55 @@ write_function_decl_and_comment (std::st
   s << ";\n";
 }
 
+/* Construct a function declaration from a call insn.  This can be
+   necessary for two reasons - either we have an indirect call which
+   requires a .callprototype declaration, or we have a libcall
+   generated by emit_library_call for which no decl exists.  */
+
+static void
+write_func_decl_from_insn (std::stringstream &s, const char *name,
+			   rtx result, rtx pat)
+{
+  if (!name)
+    {
+      s << "\t.callprototype ";
+      name = "_";
+    }
+  else
+    {
+      s << "\n// BEGIN GLOBAL FUNCTION DECL: " << name << "\n";
+      s << "\t.extern .func ";
+    }
+
+  if (result != NULL_RTX)
+    s << "(.param"
+      << nvptx_ptx_type_from_mode (arg_promotion (GET_MODE (result)), false)
+      << " %rval) ";
+
+  s << name;
+
+  const char *sep = " (";
+  int arg_end = XVECLEN (pat, 0);
+  for (int i = 1; i < arg_end; i++)
+    {
+      /* We don't have to deal with mode splitting here, as that was
+	 already done when generating the call sequence.  */
+      machine_mode mode = GET_MODE (XEXP (XVECEXP (pat, 0, i), 0));
+
+      s << sep
+	<< ".param"
+	<< nvptx_ptx_type_from_mode (mode, false)
+	<< " %arg"
+	<< i;
+      if (mode == QImode || mode == HImode)
+	s << "[1]";
+      sep = ", ";
+    }
+  if (arg_end != 1)
+    s << ")";
+  s << ";\n";
+}
+
 /* Check NAME for special function names and redirect them by returning a
    replacement.  This applies to malloc, free and realloc, for which we
    want to use libgcc wrappers, and call, which triggers a bug in ptxas.  */
@@ -470,20 +519,13 @@ nvptx_name_replacement (const char *name
   return name;
 }
 
-/* If DECL is a FUNCTION_DECL, check the hash table to see if we
-   already encountered it, and if not, insert it and write a ptx
-   declarations that will be output at the end of compilation.  */
+/* DECL is an external FUNCTION_DECL, make sure its in the fndecl hash
+   table and and write a ptx prototype.  These are emitted at end of
+   compilation.  */
 
-static bool
-nvptx_record_fndecl (tree decl, bool force = false)
+static void
+nvptx_record_fndecl (tree decl)
 {
-  if (decl == NULL_TREE || TREE_CODE (decl) != FUNCTION_DECL
-      || !DECL_EXTERNAL (decl))
-    return true;
-
-  if (!force && TYPE_ARG_TYPES (TREE_TYPE (decl)) == NULL_TREE)
-    return false;
-
   tree *slot = declared_fndecls_htab->find_slot (decl, INSERT);
   if (*slot == NULL)
     {
@@ -492,22 +534,53 @@ nvptx_record_fndecl (tree decl, bool for
       name = nvptx_name_replacement (name);
       write_function_decl_and_comment (func_decls, name, decl);
     }
-  return true;
 }
 
-/* Record that we need to emit a ptx decl for DECL.  Either do it now, or
-   record it for later in case we have no argument information at this
-   point.  */
+/* Record a libcall or unprototyped external function. CALLEE is the
+   SYMBOL_REF.  Insert into the libfunc hash table and emit a ptx
+   declaration for it.  */
+
+static void
+nvptx_record_libfunc (rtx callee, rtx retval, rtx pat)
+{
+  rtx *slot = declared_libfuncs_htab->find_slot (callee, INSERT);
+  if (*slot == NULL)
+    {
+      *slot = callee;
+
+      const char *name = XSTR (callee, 0);
+      name = nvptx_name_replacement (name);
+      write_func_decl_from_insn (func_decls, name, retval, pat);
+    }
+}
+
+/* DECL is an external FUNCTION_DECL, that we're referencing.  If it
+   is prototyped, record it now.  Otherwise record it as needed at end
+   of compilation, when we might have more information about it.  */
 
 void
 nvptx_record_needed_fndecl (tree decl)
 {
-  if (nvptx_record_fndecl (decl))
-    return;
+  if (TYPE_ARG_TYPES (TREE_TYPE (decl)) == NULL_TREE)
+    {
+      tree *slot = needed_fndecls_htab->find_slot (decl, INSERT);
+      if (*slot == NULL)
+	*slot = decl;
+    }
+  else
+    nvptx_record_fndecl (decl);
+}
 
-  tree *slot = needed_fndecls_htab->find_slot (decl, INSERT);
-  if (*slot == NULL)
-    *slot = decl;
+/* SYM is a SYMBOL_REF.  If it refers to an external function, record
+   it as needed.  */
+
+static void
+nvptx_maybe_record_fnsym (rtx sym)
+{
+  tree decl = SYMBOL_REF_DECL (sym);
+  
+  if (decl && TREE_CODE (decl) == FUNCTION_DECL && DECL_EXTERNAL (decl))
+    nvptx_record_needed_fndecl (decl);
 }
 
 /* Emit code to initialize the REGNO predicate register to indicate
@@ -713,55 +786,6 @@ nvptx_output_return (void)
   return "ret;";
 }
 
-/* Construct a function declaration from a call insn.  This can be
-   necessary for two reasons - either we have an indirect call which
-   requires a .callprototype declaration, or we have a libcall
-   generated by emit_library_call for which no decl exists.  */
-
-static void
-write_func_decl_from_insn (std::stringstream &s, const char *name,
-			   rtx result, rtx pat)
-{
-  if (!name)
-    {
-      s << "\t.callprototype ";
-      name = "_";
-    }
-  else
-    {
-      s << "\n// BEGIN GLOBAL FUNCTION DECL: " << name << "\n";
-      s << "\t.extern .func ";
-    }
-
-  if (result != NULL_RTX)
-    s << "(.param"
-      << nvptx_ptx_type_from_mode (arg_promotion (GET_MODE (result)), false)
-      << " %rval) ";
-
-  s << name;
-
-  const char *sep = " (";
-  int arg_end = XVECLEN (pat, 0);
-  for (int i = 1; i < arg_end; i++)
-    {
-      /* We don't have to deal with mode splitting here, as that was
-	 already done when generating the call sequence.  */
-      machine_mode mode = GET_MODE (XEXP (XVECEXP (pat, 0, i), 0));
-
-      s << sep
-	<< ".param"
-	<< nvptx_ptx_type_from_mode (mode, false)
-	<< " %arg"
-	<< i;
-      if (mode == QImode || mode == HImode)
-	s << "[1]";
-      sep = ", ";
-    }
-  if (arg_end != 1)
-    s << ")";
-  s << ";\n";
-}
-
 /* Terminate a function by writing a closing brace to FILE.  */
 
 void
@@ -830,9 +854,7 @@ nvptx_expand_call (rtx retval, rtx addre
   rtx callee = XEXP (address, 0);
   rtx pat, t;
   rtvec vec;
-  bool external_decl = false;
   rtx varargs = NULL_RTX;
-  tree decl_type = NULL_TREE;
   unsigned parallel = 0;
 
   for (t = cfun->machine->call_args; t; t = XEXP (t, 1))
@@ -849,11 +871,9 @@ nvptx_expand_call (rtx retval, rtx addre
       tree decl = SYMBOL_REF_DECL (callee);
       if (decl != NULL_TREE)
 	{
-	  decl_type = TREE_TYPE (decl);
 	  if (DECL_STATIC_CHAIN (decl))
 	    cfun->machine->has_call_with_sc = true;
-	  if (DECL_EXTERNAL (decl))
-	    external_decl = true;
+
 	  tree attr = get_oacc_fn_attrib (decl);
 	  if (attr)
 	    {
@@ -913,26 +933,6 @@ nvptx_expand_call (rtx retval, rtx addre
 
   gcc_assert (vec_pos = XVECLEN (pat, 0));
 
-  /* If this is a libcall, decl_type is NULL. For a call to a non-libcall
-     undeclared function, we'll have an external decl without arg types.
-     In either case we have to try to construct a ptx declaration from one of
-     the calls to the function.  */
-  if (!REG_P (callee)
-      && (decl_type == NULL_TREE
-	  || (external_decl && TYPE_ARG_TYPES (decl_type) == NULL_TREE)))
-    {
-      rtx *slot = declared_libfuncs_htab->find_slot (callee, INSERT);
-      if (*slot == NULL)
-	{
-	  *slot = callee;
-
-	  const char *name = XSTR (callee, 0);
-	  if (decl_type)
-	    name = nvptx_name_replacement (name);
-	  write_func_decl_from_insn (func_decls, name, retval, pat);
-	}
-    }
-
   nvptx_emit_forking (parallel, true);
   emit_call_insn (pat);
   nvptx_emit_joining (parallel, true);
@@ -1354,10 +1354,9 @@ nvptx_gen_wcast (rtx reg, propagate_mask
 }
 
 /* When loading an operand ORIG_OP, verify whether an address space
-   conversion to generic is required, and if so, perform it.  Also
-   check for SYMBOL_REFs for function decls and call
-   nvptx_record_needed_fndecl as needed.
-   Return either the original operand, or the converted one.  */
+   conversion to generic is required, and if so, perform it.  Check
+   for SYMBOL_REFs and record them if needed.  Return either the
+   original operand, or the converted one.  */
 
 rtx
 nvptx_maybe_convert_symbolic_operand (rtx orig_op)
@@ -1371,13 +1370,8 @@ nvptx_maybe_convert_symbolic_operand (rt
   if (GET_CODE (op) != SYMBOL_REF)
     return orig_op;
 
-  tree decl = SYMBOL_REF_DECL (op);
-  if (decl && TREE_CODE (decl) == FUNCTION_DECL)
-    {
-      nvptx_record_needed_fndecl (decl);
-      return orig_op;
-    }
-
+  nvptx_maybe_record_fnsym (op);
+  
   addr_space_t as = nvptx_addr_space_from_address (op);
   if (as == ADDR_SPACE_GENERIC)
     return orig_op;
@@ -1570,48 +1564,43 @@ nvptx_assemble_value (HOST_WIDE_INT val,
 static bool
 nvptx_assemble_integer (rtx x, unsigned int size, int ARG_UNUSED (aligned_p))
 {
-  if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == CONST)
+  HOST_WIDE_INT val = 0;
+
+  switch (GET_CODE (x))
     {
+    default:
+      gcc_unreachable ();
+
+    case CONST_INT:
+      val = INTVAL (x);
+      nvptx_assemble_value (val, size);
+      break;
+
+    case CONST:
+      x = XEXP (x, 0);
+      gcc_assert (GET_CODE (x) == PLUS);
+      val = INTVAL (XEXP (x, 1));
+      x = XEXP (x, 0);
+      gcc_assert (GET_CODE (x) == SYMBOL_REF);
+      /* FALLTHROUGH */
+
+    case SYMBOL_REF:
       gcc_assert (size = decl_chunk_size);
       if (decl_offset % decl_chunk_size != 0)
 	sorry ("cannot emit unaligned pointers in ptx assembly");
       decl_offset += size;
       begin_decl_field ();
 
-      HOST_WIDE_INT off = 0;
-      if (GET_CODE (x) == CONST)
-	x = XEXP (x, 0);
-      if (GET_CODE (x) == PLUS)
-	{
-	  off = INTVAL (XEXP (x, 1));
-	  x = XEXP (x, 0);
-	}
-      if (GET_CODE (x) == SYMBOL_REF)
-	{
-	  nvptx_record_needed_fndecl (SYMBOL_REF_DECL (x));
-	  fprintf (asm_out_file, "generic(");
-	  output_address (VOIDmode, x);
-	  fprintf (asm_out_file, ")");
-	}
-      if (off != 0)
-	fprintf (asm_out_file, " + " HOST_WIDE_INT_PRINT_DEC, off);
-      return true;
-    }
+      nvptx_maybe_record_fnsym (x);
+      fprintf (asm_out_file, "generic(");
+      output_address (VOIDmode, x);
+      fprintf (asm_out_file, ")");
 
-  HOST_WIDE_INT val;
-  switch (GET_CODE (x))
-    {
-    case CONST_INT:
-      val = INTVAL (x);
-      break;
-    case CONST_DOUBLE:
-      gcc_unreachable ();
+      if (val)
+	fprintf (asm_out_file, " + " HOST_WIDE_INT_PRINT_DEC, val);
       break;
-    default:
-      gcc_unreachable ();
     }
 
-  nvptx_assemble_value (val, size);
   return true;
 }
 
@@ -1793,7 +1782,10 @@ nvptx_output_call_insn (rtx_insn *insn,
   if (GET_CODE (callee) == SYMBOL_REF)
     {
       decl = SYMBOL_REF_DECL (callee);
-      if (decl && DECL_EXTERNAL (decl))
+      if (!decl
+	  || (DECL_EXTERNAL (decl) && !TYPE_ARG_TYPES (TREE_TYPE (decl))))
+	nvptx_record_libfunc (callee, result, pat);
+      else if (DECL_EXTERNAL (decl))
 	nvptx_record_fndecl (decl);
     }
 
@@ -3889,7 +3881,7 @@ nvptx_file_end (void)
   hash_table<tree_hasher>::iterator iter;
   tree decl;
   FOR_EACH_HASH_TABLE_ELEMENT (*needed_fndecls_htab, decl, tree, iter)
-    nvptx_record_fndecl (decl, true);
+    nvptx_record_fndecl (decl);
   fputs (func_decls.str().c_str(), asm_out_file);
 
   if (worker_bcast_size)
Index: config/nvptx/nvptx.md
===================================================================
--- config/nvptx/nvptx.md	(revision 231012)
+++ config/nvptx/nvptx.md	(working copy)
@@ -391,8 +391,6 @@
       emit_move_insn (operands[0], tmp);
       DONE;
     }
-  if (GET_CODE (operands[1]) == SYMBOL_REF)
-    nvptx_record_needed_fndecl (SYMBOL_REF_DECL (operands[1]));
 })
 
 (define_insn "highpartscsf2"
