diff mbox

[PTX] prologue emission

Message ID 56619E4A.90103@acm.org
State New
Headers show

Commit Message

Nathan Sidwell Dec. 4, 2015, 2:08 p.m. UTC
The PTX backend has to emit PTX function prototypes and prologues in addition to 
the regular argument marshalling machinery.  And of course these all have to 
agree with each other.  The first two are done by two different pieces of code,

This patch changes things so that prototype and prologue argument emission is 
done by the same piece of code.  A slight wart there is that prototype emission 
uses a C++ stdstream where as prologue emission (mainly) used ye olde FILE *. 
The patch extends the latter's use of stdstream a little further.

You'll notice that argument promotion is slightly different in the two paths. 
I've not changed that behaviour, but I suspect it may be an error.  Will relook 
at that when I'm done reducing the duplication in the function calling machinery.

nathan
diff mbox

Patch

2015-12-04  Nathan Sidwell  <nathan@acm.org>

	* config/nvptx/nvptx.c (write_one_arg): Deal with prologue
	emission too. Change 'no_arg_types' to 'prototyped'.
	(write_fn_proto):  Use write_one_arg for stdarg, static chain &
	main.
	(nvptx_declare_function_name): Use write_one_arg for prologue copies.

Index: config/nvptx/nvptx.c
===================================================================
--- config/nvptx/nvptx.c	(revision 231265)
+++ config/nvptx/nvptx.c	(working copy)
@@ -389,38 +389,67 @@  arg_promotion (machine_mode mode)
   return mode;
 }
 
-/* Write the declaration of a function arg of TYPE to S.  I is the index
-   of the argument, MODE its mode.  NO_ARG_TYPES is true if this is for
-   a decl with zero TYPE_ARG_TYPES, i.e. an old-style C decl.  */
+/* Process function parameter TYPE, either emitting in a prototype
+   argument, or as a copy a in a function prologue.  ARGNO is the
+   index of this argument in the PTX function.  FOR_REG is negative,
+   if we're emitting the PTX prototype.  It is zero if we're copying
+   to an argument register and it is greater than zero if we're
+   copying to a specific hard register.  PROTOTYPED is true, if this
+   is a prototyped function, rather than an old-style C declaration.
+
+   The behaviour here must match the regular GCC function parameter
+   marshalling machinery.  */
 
 static int
-write_one_arg (std::stringstream &s, const char *sep, int i,
-	       tree type, machine_mode mode, bool no_arg_types)
+write_one_arg (std::stringstream &s, int for_reg, int argno,
+	       tree type, bool prototyped)
 {
+  machine_mode mode = TYPE_MODE (type);
+
   if (!PASS_IN_REG_P (mode, type))
     mode = Pmode;
 
   machine_mode split = maybe_split_mode (mode);
   if (split != VOIDmode)
     {
-      i = write_one_arg (s, sep, i, TREE_TYPE (type), split, false);
-      sep = ", ";
       mode = split;
+      argno = write_one_arg (s, for_reg, argno,
+			     TREE_TYPE (type), prototyped);
     }
 
-  if (no_arg_types && !AGGREGATE_TYPE_P (type))
+  if (!prototyped && !AGGREGATE_TYPE_P (type))
     {
       if (mode == SFmode)
 	mode = DFmode;
       mode = arg_promotion (mode);
     }
 
-  s << sep;
-  s << ".param" << nvptx_ptx_type_from_mode (mode, false) << " %in_ar"
-    << i << (mode == QImode || mode == HImode ? "[1]" : "");
-  if (mode == BLKmode)
-    s << "[" << int_size_in_bytes (type) << "]";
-  return i + 1;
+  if (for_reg < 0)
+    {
+      /* Writing PTX prototype.  */
+      s << (argno ? ", " : " (");
+      s << ".param" << nvptx_ptx_type_from_mode (mode, false)
+	<< " %in_ar" << argno;
+      if (mode == QImode || mode == HImode)
+	s << "[1]";
+    }
+  else
+    {
+      mode = arg_promotion (mode);
+      s << "\t.reg" << nvptx_ptx_type_from_mode (mode, false) << " ";
+      if (for_reg)
+	s << reg_names[for_reg];
+      else
+	s << "%ar" << argno;
+      s << ";\n";
+      s << "\tld.param" << nvptx_ptx_type_from_mode (mode, false) << " ";
+      if (for_reg)
+	s << reg_names[for_reg];
+      else
+	s << "%ar" << argno;
+      s<< ", [%in_ar" << argno << "];\n";
+    }
+  return argno + 1;
 }
 
 /* Look for attributes in ATTRS that would indicate we must write a function
@@ -507,16 +536,11 @@  write_fn_proto (std::stringstream &s, bo
 
   s << name;
 
-  const char *sep = " (";
-  int i = 0;
+  int argno = 0;
 
   /* Emit argument list.  */
   if (return_in_mem)
-    {
-      s << sep << ".param.u" << GET_MODE_BITSIZE (Pmode) << " %in_ar0";
-      sep  = ", ";
-      i++;
-    }
+    argno = write_one_arg (s, -1, argno, ptr_type_node, true);
 
   /* We get:
      NULL in TYPE_ARG_TYPES, for old-style functions
@@ -524,46 +548,34 @@  write_fn_proto (std::stringstream &s, bo
        declaration.
      So we have to pick the best one we have.  */
   tree args = TYPE_ARG_TYPES (fntype);
-  bool null_type_args = !args;
-  if (null_type_args)
-    args = DECL_ARGUMENTS (decl);
+  bool prototyped = true;
+  if (!args)
+    {
+      args = DECL_ARGUMENTS (decl);
+      prototyped = false;
+    }
 
   for (; args; args = TREE_CHAIN (args))
     {
-      tree type = null_type_args ? TREE_TYPE (args) : TREE_VALUE (args);
-      machine_mode mode = TYPE_MODE (type);
+      tree type = prototyped ? TREE_VALUE (args) : TREE_TYPE (args);
 
-      if (mode == VOIDmode)
-	break;
-      i = write_one_arg (s, sep, i, type, mode, null_type_args);
-      sep = ", ";
+      if (type != void_type_node)
+	argno = write_one_arg (s, -1, argno, type, prototyped);
     }
 
   if (stdarg_p (fntype))
-    {
-      s << sep << ".param.u" << GET_MODE_BITSIZE (Pmode) << " %in_argp";
-      i++;
-      sep = ", ";
-    }
+    argno = write_one_arg (s, -1, argno, ptr_type_node, true);
 
   if (DECL_STATIC_CHAIN (decl))
-    {
-      s << sep << ".reg.u" << GET_MODE_BITSIZE (Pmode)
-	<< reg_names [STATIC_CHAIN_REGNUM];
-      i++;
-      sep = ", ";
-    }
+    argno = write_one_arg (s, -1, argno, ptr_type_node, true);
 
-  if (!i && strcmp (name, "main") == 0)
+  if (!argno && strcmp (name, "main") == 0)
     {
-      s << sep
-	<< ".param.u32 %argc, .param.u" << GET_MODE_BITSIZE (Pmode)
-	<< " %argv";
-      i++;
-      sep = ", ";
+      argno = write_one_arg (s, -1, argno, integer_type_node, true);
+      argno = write_one_arg (s, -1, argno, ptr_type_node, true);
     }
 
-  if (i)
+  if (argno)
     s << ")";
 
   s << (is_defn ? "\n" : ";\n");
@@ -705,63 +717,43 @@  nvptx_declare_function_name (FILE *file,
 {
   tree fntype = TREE_TYPE (decl);
   tree result_type = TREE_TYPE (fntype);
-  int argno  = 0;
+  int argno = 0;
 
+  /* We construct the initial part of the function into a string
+     stream, in order to share the prototype writing code.  */
   std::stringstream s;
   write_fn_proto (s, true, name, decl);
-  fprintf (file, "%s", s.str().c_str());
-  fprintf (file, "{\n");
+  s << "{\n";
 
   bool return_in_mem = (TYPE_MODE (result_type) != VOIDmode
 			&& !RETURN_IN_REG_P (TYPE_MODE (result_type)));
   if (return_in_mem)
-    {
-      fprintf (file, "\t.reg.u%d %%ar%d;\n", GET_MODE_BITSIZE (Pmode), argno);
-      fprintf (file, "\tld.param.u%d %%ar%d, [%%in_ar%d];\n",
-	       GET_MODE_BITSIZE (Pmode), argno, argno);
-      argno++;
-    }
-
+    argno = write_one_arg (s, 0, argno, ptr_type_node, true);
+  
   /* Declare and initialize incoming arguments.  */
-  tree args = DECL_ARGUMENTS (decl);
-  bool prototyped = false;
-  if (TYPE_ARG_TYPES (fntype))
+  tree args = TYPE_ARG_TYPES (fntype);
+  bool prototyped = true;
+  if (!args)
     {
-      args = TYPE_ARG_TYPES (fntype);
-      prototyped = true;
+      args = DECL_ARGUMENTS (decl);
+      prototyped = false;
     }
 
   for (; args != NULL_TREE; args = TREE_CHAIN (args))
     {
       tree type = prototyped ? TREE_VALUE (args) : TREE_TYPE (args);
-      machine_mode mode = TYPE_MODE (type);
-      int count = 1;
 
-      if (mode == VOIDmode)
-	break;
+      if (type != void_type_node)
+	argno = write_one_arg (s, 0, argno, type, prototyped);
+    }
 
-      if (!PASS_IN_REG_P (mode, type))
-	mode = Pmode;
+  if (stdarg_p (fntype))
+    argno = write_one_arg (s, ARG_POINTER_REGNUM, argno, ptr_type_node, true);
 
-      machine_mode split = maybe_split_mode (mode);
-      if (split != VOIDmode)
-	{
-	  count = 2;
-	  mode = split;
-	}
-      else if (!prototyped && !AGGREGATE_TYPE_P (type) && mode == SFmode)
-	mode = DFmode;
+  if (DECL_STATIC_CHAIN (decl))
+    argno = write_one_arg (s, STATIC_CHAIN_REGNUM, argno, ptr_type_node, true);
 
-      mode = arg_promotion (mode);
-      while (count--)
-	{
-	  fprintf (file, "\t.reg%s %%ar%d;\n",
-		   nvptx_ptx_type_from_mode (mode, false), argno);
-	  fprintf (file, "\tld.param%s %%ar%d, [%%in_ar%d];\n",
-		   nvptx_ptx_type_from_mode (mode, false), argno, argno);
-	  argno++;
-	}
-    }
+  fprintf (file, "%s", s.str().c_str());
 
   /* C++11 ABI causes us to return a reference to the passed in
      pointer for return_in_mem.  */
@@ -773,16 +765,9 @@  nvptx_declare_function_name (FILE *file,
 	       nvptx_ptx_type_from_mode (mode, false));
     }
 
-  if (stdarg_p (fntype))
-    {
-      fprintf (file, "\t.reg.u%d %%argp;\n", GET_MODE_BITSIZE (Pmode));
-      fprintf (file, "\tld.param.u%d %%argp, [%%in_argp];\n",
-	       GET_MODE_BITSIZE (Pmode));
-    }
-
   fprintf (file, "\t.reg.u%d %s;\n", GET_MODE_BITSIZE (Pmode),
 	   reg_names[OUTGOING_STATIC_CHAIN_REGNUM]);
-
+  
   /* Declare the pseudos we have as ptx registers.  */
   int maxregs = max_reg_num ();
   for (int i = LAST_VIRTUAL_REGISTER + 1; i < maxregs; i++)