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]

[PTX] Another libcall patch


I've committed this further cleanup of function decl recording. We were recording libcalls during call expansion, but recording other calls during call outputting. This moves all recording to the call outputting. The recording helpers were a little confusing -- for intsance 'record_fndecl', was really 'maybe_record_fndecl', and in some cases the caller checked preconditions (like being an actual fnddecl) whereas other cases the helper did the checking. I've moved things around so that the caller always does the prechecking. I broke the libcall hash manipulation out into a helper, in line with the other helpers, and added a helper to deal with looking through symbol refs.

Finally expand_movdi had no need to register an fndecl itself -- it's already calling maybe_convert_symbolic_operand, which does that.

nathan
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"

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