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]

[gccgo] Change print/panic support to not use varargs


As noted previously, varargs does not currently work with
-fsplit-stack.  This patch changes the runtime support functions for
the predeclared functions print/println/panic/panicln to not use
varargs routines.  Instead of compiling these functions into a call to
printf, we now compile them into a series of calls, one for each
argument.  This is what the other Go compiler does as well.  This is
less space efficient and more time efficient, but these functions are
not widely used in any case.  I also changed the set of which types
may be used with these functions to match that of the other Go
compiler.

Ian

Index: gcc/go/Make-lang.in
===================================================================
--- gcc/go/Make-lang.in	(revision 155387)
+++ gcc/go/Make-lang.in	(working copy)
@@ -147,9 +147,10 @@ go/export.o: go/export.cc $(GO_SYSTEM_H)
 	$(MACHMODE_H) output.h $(TARGET_H) $(DIAGNOSTIC_H) $(GO_GOGO_H) \
 	$(GO_TYPES_H) $(GO_STATEMENTS_H) go/export.h
 go/expressions.o: go/expressions.cc $(GO_SYSTEM_H) intl.h $(TREE_H) \
-	$(GIMPLE_H) convert.h $(REAL_H) $(DIAGNOSTIC_H) $(TM_P_H) $(GO_C_H) \
-	$(GO_GOGO_H) $(GO_TYPES_H) go/export.h $(GO_IMPORT_H) \
-	go/refcount.h $(GO_STATEMENTS_H) $(GO_LEX_H) $(GO_EXPRESSIONS_H)
+	$(GIMPLE_H) tree-iterator.h convert.h $(REAL_H) $(DIAGNOSTIC_H) \
+	$(TM_P_H) $(GO_C_H) $(GO_GOGO_H) $(GO_TYPES_H) go/export.h \
+	$(GO_IMPORT_H) go/refcount.h $(GO_STATEMENTS_H) $(GO_LEX_H) \
+	$(GO_EXPRESSIONS_H)
 go/go.o: go/go.cc $(GO_SYSTEM_H) options.h $(DIAGNOSTIC_H) $(GO_C_H) \
 	$(GO_LEX_H) $(GO_PARSE_H) $(GO_GOGO_H)
 go/go-dump.o: go/go-dump.cc $(GO_SYSTEM_H) $(GO_C_H) go/go-dump.h
Index: gcc/go/expressions.cc
===================================================================
--- gcc/go/expressions.cc	(revision 155357)
+++ gcc/go/expressions.cc	(working copy)
@@ -13,6 +13,7 @@ extern "C"
 #include "intl.h"
 #include "tree.h"
 #include "gimple.h"
+#include "tree-iterator.h"
 #include "convert.h"
 #include "real.h"
 #include "diagnostic.h"
@@ -5530,8 +5531,11 @@ Builtin_call_expression::do_check_types(
 		    || type->float_type() != NULL
 		    || type->is_boolean_type()
 		    || type->points_to() != NULL
-		    || type->array_type() != NULL
-		    || type->interface_type() != NULL)
+		    || type->interface_type() != NULL
+		    || type->channel_type() != NULL
+		    || type->map_type() != NULL
+		    || type->function_type() != NULL
+		    || type->is_open_array_type())
 		  ;
 		else
 		  this->report_error(_("unsupported argument type to "
@@ -5719,173 +5723,136 @@ Builtin_call_expression::do_get_tree(Tra
 			       || this->code_ == BUILTIN_PANICLN);
 	const bool is_ln = (this->code_ == BUILTIN_PANICLN
 			    || this->code_ == BUILTIN_PRINTLN);
-	const Expression_list* call_args = this->args();
-
-	int nargs;
-	tree* args;
-	std::string format;
-	if (call_args == NULL)
-	  {
-	    if (!is_panic && !is_ln)
-	      {
-		// A call to print with no arguments.  There is nothing
-		// to do.
-		return integer_zero_node;
-	      }
-	    nargs = 1;
-	    args = new tree[1];
-	  }
-	else
-	  {
-	    nargs = call_args->size() + 1;
+	tree stmt_list = NULL_TREE;
 
-	    // We allocate extra space because we use three arguments
-	    // to print arrays.
-	    args = new tree[nargs * 3];
+	tree panic_arg = is_panic ? boolean_true_node : boolean_false_node;
 
-	    int i = 1;
+	const Expression_list* call_args = this->args();
+	if (call_args != NULL)
+	  {
 	    for (Expression_list::const_iterator p = call_args->begin();
 		 p != call_args->end();
-		 ++p, ++i)
+		 ++p)
 	      {
-		if (is_ln && i > 1)
-		  format += " ";
+		if (is_ln && p != call_args->begin())
+		  {
+		    static tree print_space_fndecl;
+		    tree call = Gogo::call_builtin(&print_space_fndecl,
+						   location,
+						   "__go_print_space",
+						   1,
+						   void_type_node,
+						   boolean_type_node,
+						   panic_arg);
+		    append_to_statement_list(call, &stmt_list);
+		  }
 
-		args[i] = (*p)->get_tree(context);
+		Type* type = (*p)->type();
 
-		if (args[i] == error_mark_node)
+		tree arg = (*p)->get_tree(context);
+		if (arg == error_mark_node)
+		  return error_mark_node;
+
+		tree* pfndecl;
+		const char* fnname;
+		if (type->is_string_type())
 		  {
-		    args[i] = integer_zero_node;
-		    format += "%d";
+		    static tree print_string_fndecl;
+		    pfndecl = &print_string_fndecl;
+		    fnname = "__go_print_string";
 		  }
-		else if ((*p)->type()->is_string_type())
+		else if (type->integer_type() != NULL
+			 && type->integer_type()->is_unsigned())
 		  {
-		    // We use a precision to print the right number of
-		    // characters.  FIXME: If the string has embedded
-		    // null bytes, it won't be printed correctly.
-		    tree string = args[i];
-		    tree len = String_type::length_tree(gogo, string);
-		    args[i] = convert_to_integer(integer_type_node, len);
-		    ++i;
-		    ++nargs;
-		    args[i] = String_type::bytes_tree(gogo, string);
-		    format += "%.*s";
+		    static tree print_uint64_fndecl;
+		    pfndecl = &print_uint64_fndecl;
+		    fnname = "__go_print_uint64";
+		    Type* itype = Type::lookup_integer_type("uint64");
+		    arg = fold_convert_loc(location, itype->get_tree(gogo),
+					   arg);
 		  }
-		else if ((*p)->type()->integer_type() != NULL)
+		else if (type->integer_type() != NULL)
 		  {
-		    const Integer_type* itype = (*p)->type()->integer_type();
-		    int bits = TYPE_PRECISION(TREE_TYPE(args[i]));
-		    if (bits <= INT_TYPE_SIZE)
-		      {
-			args[i] = fold_convert((itype->is_unsigned()
-						? unsigned_type_node
-						: integer_type_node),
-					       args[i]);
-			format += itype->is_unsigned() ? "%u" : "%d";
-		      }
-		    else if (bits <= LONG_TYPE_SIZE)
-		      {
-			args[i] = fold_convert((itype->is_unsigned()
-						? long_unsigned_type_node
-						: long_integer_type_node),
-					       args[i]);
-			format += itype->is_unsigned() ? "%lu" : "%ld";
-		      }
-		    else if (bits <= LONG_LONG_TYPE_SIZE)
-		      {
-			args[i] = fold_convert((itype->is_unsigned()
-						? long_long_unsigned_type_node
-						: long_long_integer_type_node),
-					       args[i]);
-			format += itype->is_unsigned() ? "%llu" : "%lld";
-		      }
-		    else
-		      gcc_unreachable();
+		    static tree print_int64_fndecl;
+		    pfndecl = &print_int64_fndecl;
+		    fnname = "__go_print_int64";
+		    Type* itype = Type::lookup_integer_type("int64");
+		    arg = fold_convert_loc(location, itype->get_tree(gogo),
+					   arg);
 		  }
-		else if ((*p)->type()->float_type() != NULL)
+		else if (type->float_type() != NULL)
 		  {
-		    args[i] = fold_convert(double_type_node, args[i]);
-		    format += "%.24g";
+		    static tree print_double_fndecl;
+		    pfndecl = &print_double_fndecl;
+		    fnname = "__go_print_double";
+		    arg = fold_convert_loc(location, double_type_node, arg);
 		  }
-		else if ((*p)->type()->is_boolean_type())
+		else if (type->is_boolean_type())
 		  {
-		    tree string_type = Gogo::const_char_pointer_type_tree();
-		    tree true_string = Gogo::string_constant_tree("true");
-		    true_string = build_fold_addr_expr(true_string);
-		    true_string = fold_convert(string_type, true_string);
-		    tree false_string = Gogo::string_constant_tree("false");
-		    false_string = build_fold_addr_expr(false_string);
-		    false_string = fold_convert(string_type, false_string);
-		    args[i] = fold_build3(COND_EXPR, string_type, args[i],
-					  true_string, false_string);
-		    format += "%s";
+		    static tree print_bool_fndecl;
+		    pfndecl = &print_bool_fndecl;
+		    fnname = "__go_print_bool";
 		  }
-		else if ((*p)->type()->points_to() != NULL
-			 || (*p)->type()->interface_type() != NULL)
+		else if (type->points_to() != NULL
+			 || type->interface_type() != NULL
+			 || type->channel_type() != NULL
+			 || type->map_type() != NULL
+			 || type->function_type() != NULL)
 		  {
-		    args[i] = fold_convert(ptr_type_node, args[i]);
-		    format += "%p";
+		    static tree print_pointer_fndecl;
+		    pfndecl = &print_pointer_fndecl;
+		    fnname = "__go_print_pointer";
+		    arg = fold_convert_loc(location, ptr_type_node, arg);
 		  }
-		else if ((*p)->type()->array_type() != NULL)
+		else if (type->is_open_array_type())
 		  {
-		    Array_type* at = (*p)->type()->array_type();
-		    tree v = save_expr(args[i]);
-		    args[i] = at->length_tree(gogo, v);
-		    ++i;
-		    ++nargs;
-		    args[i] = at->capacity_tree(gogo, v);
-		    ++i;
-		    ++nargs;
-		    args[i] = at->value_pointer_tree(gogo, v);
-		    format += "[%zu/%zu]%p";
+		    static tree print_slice_fndecl;
+		    pfndecl = &print_slice_fndecl;
+		    fnname = "__go_print_slice";
 		  }
 		else
-		  {
-		    args[i] = integer_zero_node;
-		    format += "%d";
-		  }
+		  gcc_unreachable();
+
+		tree call = Gogo::call_builtin(pfndecl,
+					       location,
+					       fnname,
+					       2,
+					       void_type_node,
+					       boolean_type_node,
+					       panic_arg,
+					       TREE_TYPE(arg),
+					       arg);
+		append_to_statement_list(call, &stmt_list);
 	      }
-	    gcc_assert(i == nargs);
 	  }
 
 	if (is_ln)
-	  format += "\n";
-
-	tree string_val = Gogo::string_constant_tree(format);
-	args[0] = build_fold_addr_expr(string_val);
+	  {
+	    static tree print_nl_fndecl;
+	    tree call = Gogo::call_builtin(&print_nl_fndecl,
+					   location,
+					   "__go_print_nl",
+					   1,
+					   void_type_node,
+					   boolean_type_node,
+					   panic_arg);
+	    append_to_statement_list(call, &stmt_list);
+	  }
 
-	static tree panic_fndecl;
-	static tree print_fndecl;
-	static tree* pfndecl;
 	if (is_panic)
-	  pfndecl = &panic_fndecl;
-	else
-	  pfndecl = &print_fndecl;
-	if (*pfndecl == NULL_TREE)
 	  {
-	    tree fnid = get_identifier(is_panic ? "__go_panic" : "__go_print");
-	    tree argtypes = tree_cons(NULL_TREE,
-				      Gogo::const_char_pointer_type_tree(),
-				      NULL_TREE);
-	    tree fntype = build_function_type(void_type_node, argtypes);
-
-	    *pfndecl = build_decl(BUILTINS_LOCATION, FUNCTION_DECL, fnid,
-				  fntype);
-	    Gogo::mark_fndecl_as_builtin_library(*pfndecl);
-	    if (is_panic)
-	      {
-		// Mark the function as noreturn.
-		TREE_THIS_VOLATILE(*pfndecl) = 1;
-	      }
-	    go_preserve_from_gc(*pfndecl);
+	    static tree panic_fndecl;
+	    tree call = Gogo::call_builtin(&panic_fndecl,
+					   location,
+					   "__go_panic",
+					   0,
+					   void_type_node);
+	    // Mark the function as not returning.
+	    TREE_THIS_VOLATILE(panic_fndecl) = 1;
+	    append_to_statement_list(call, &stmt_list);
 	  }
-
-	tree fnptr = build_fold_addr_expr(*pfndecl);
-	tree call = build_call_array_loc(location, void_type_node,
-					 fnptr, nargs, args);
-	delete[] args;
-
-	return call;
+	  
+	return stmt_list;
       }
 
     case BUILTIN_CLOSE:
Index: libgo/runtime/go-send-nb-small.c
===================================================================
--- libgo/runtime/go-send-nb-small.c	(revision 154387)
+++ libgo/runtime/go-send-nb-small.c	(working copy)
@@ -31,7 +31,7 @@ __go_send_nonblocking_acquire (struct __
     {
       ++channel->closed_op_count;
       if (channel->closed_op_count >= MAX_CLOSED_OPERATIONS)
-	__go_panic ("too many operations on closed channel");
+	__go_panic_msg ("too many operations on closed channel");
       i = pthread_mutex_unlock (&channel->lock);
       assert (i == 0);
       return SEND_NONBLOCKING_ACQUIRE_CLOSED;
Index: libgo/runtime/go-convert-interface.c
===================================================================
--- libgo/runtime/go-convert-interface.c	(revision 154387)
+++ libgo/runtime/go-convert-interface.c	(working copy)
@@ -93,9 +93,9 @@ __go_convert_interface (const struct __g
 		  *success = 0;
 		  return NULL;
 		}
-	      __go_panic ("interface conversion failed: no '%.*s' method",
-			  (int) (*p_lhs_method->__name)->__length,
-			  (*p_lhs_method->__name)->__data);
+	      __go_print_msg (1, "interface conversion failed: no '");
+	      __go_print_string (1, *p_lhs_method->__name);
+	      __go_panic_msg ("' method");
 	    }
 
 	  if (p_lhs_method->__hash != p_rhs_method->__hash)
@@ -105,10 +105,9 @@ __go_convert_interface (const struct __g
 		  *success = 0;
 		  return NULL;
 		}
-	      __go_panic (("interface conversion failed: "
-			   "'%.*s' method has wrong type"),
-			  (int) (*p_lhs_method->__name)->__length,
-			  (*p_lhs_method->__name)->__data);
+	      __go_print_msg (1, "interface conversion failed: '");
+	      __go_print_string (1, *p_lhs_method->__name);
+	      __go_panic_msg ("' method has wrong type");
 	    }
 
 	  methods[i] = p_rhs_method->__function;
Index: libgo/runtime/go-print.c
===================================================================
--- libgo/runtime/go-print.c	(revision 154387)
+++ libgo/runtime/go-print.c	(working copy)
@@ -4,17 +4,68 @@
    Use of this source code is governed by a BSD-style
    license that can be found in the LICENSE file.  */
 
-#include <stdarg.h>
+#include <stdint.h>
 #include <stdio.h>
 
-/* This implements __go_print which is used for the print statement.
-   FIXME: This is only for testing.  */
+#include "array.h"
+#include "go-panic.h"
+#include "go-string.h"
+
+/* This implements the various little functions which are called by
+   the predeclared functions print/println/panic/panicln.  */
+
+void
+__go_print_space (_Bool is_panic)
+{
+  putc (' ', is_panic ? stderr : stdout);
+}
+
+void
+__go_print_nl (_Bool is_panic)
+{
+  putc ('\n', is_panic ? stderr : stdout);
+}
+
+void
+__go_print_string (_Bool is_panic, const struct __go_string* val)
+{
+  fprintf (is_panic ? stderr : stdout, "%.*s", (int) val->__length,
+	   (const char *) &val->__data[0]);
+}
+
+void
+__go_print_uint64 (_Bool is_panic, uint64_t val)
+{
+  fprintf (is_panic ? stderr : stdout, "%llu", (unsigned long long) val);
+}
+
+void
+__go_print_int64 (_Bool is_panic, int64_t val)
+{
+  fprintf (is_panic ? stderr : stdout, "%lld", (long long) val);
+}
+
+void
+__go_print_double (_Bool is_panic, double val)
+{
+  fprintf (is_panic ? stderr : stdout, "%.24g", val);
+}
+
+void
+__go_print_bool (_Bool is_panic, _Bool val)
+{
+  fputs (val ? "true" : "false", is_panic ? stderr : stdout);
+}
+
+void
+__go_print_pointer (_Bool is_panic, void *val)
+{
+  fprintf (is_panic ? stderr : stdout, "%p", val);
+}
 
 void
-__go_print(const char* format, ...)
+__go_print_slice (_Bool is_panic, struct __go_open_array val)
 {
-  va_list args;
-  va_start(args, format);
-  vprintf(format, args);
-  va_end(args);
+  fprintf (is_panic ? stderr : stdout, "[%d/%d]%p",
+	   val.__count, val.__capacity, val.__values);
 }
Index: libgo/runtime/go-send-small.c
===================================================================
--- libgo/runtime/go-send-small.c	(revision 154387)
+++ libgo/runtime/go-send-small.c	(working copy)
@@ -30,7 +30,7 @@ __go_send_acquire (struct __go_channel *
 	{
 	  ++channel->closed_op_count;
 	  if (channel->closed_op_count >= MAX_CLOSED_OPERATIONS)
-	    __go_panic ("too many operations on closed channel");
+	    __go_panic_msg ("too many operations on closed channel");
 	  channel->selected_for_send = 0;
 	  __go_unlock_and_notify_selects (channel);
 	  return 0;
Index: libgo/runtime/go-type-error.c
===================================================================
--- libgo/runtime/go-type-error.c	(revision 154387)
+++ libgo/runtime/go-type-error.c	(working copy)
@@ -14,7 +14,7 @@ size_t
 __go_type_hash_error (const void *val __attribute__ ((unused)),
 		      size_t key_size __attribute__ ((unused)))
 {
-  __go_panic ("hash of type which does not support hash computations");
+  __go_panic_msg ("hash of type which does not support hash computations");
 }
 
 /* An equality function for an interface.  */
@@ -24,5 +24,5 @@ __go_type_equal_error (const void *v1 __
 		       const void *v2 __attribute__ ((unused)),
 		       size_t key_size __attribute__ ((unused)))
 {
-  __go_panic ("comparison of type which may not be compared");
+  __go_panic_msg ("comparison of type which may not be compared");
 }
Index: libgo/runtime/go-rec-nb-small.c
===================================================================
--- libgo/runtime/go-rec-nb-small.c	(revision 154387)
+++ libgo/runtime/go-rec-nb-small.c	(working copy)
@@ -36,7 +36,7 @@ __go_receive_nonblocking_acquire (struct
 	{
 	  ++channel->closed_op_count;
 	  if (channel->closed_op_count >= MAX_CLOSED_OPERATIONS)
-	    __go_panic ("too many operations on closed channel");
+	    __go_panic_msg ("too many operations on closed channel");
 	}
       channel->saw_close = 1;
       __go_unlock_and_notify_selects (channel);
Index: libgo/runtime/runtime.h
===================================================================
--- libgo/runtime/runtime.h	(revision 155391)
+++ libgo/runtime/runtime.h	(working copy)
@@ -90,13 +90,13 @@ struct	M
 #define USED(v)		((void) v)
 
 /* We map throw to panic.  */
-#define throw(s) __go_panic("%s", s)
+#define throw(s) __go_panic_msg (s)
 
 /* Mutual exclusion locks.  */
 #define lock(p) \
-  (pthread_mutex_lock(p) == 0 || (__go_panic ("lock failed"), 0))
+  (pthread_mutex_lock(p) == 0 || (__go_panic_msg ("lock failed"), 0))
 #define unlock(p) \
-  (pthread_mutex_unlock(p) == 0 || (__go_panic ("unlock failed"), 0))
+  (pthread_mutex_unlock(p) == 0 || (__go_panic_msg ("unlock failed"), 0))
 
 void	siginit(void);
 bool	sigsend(int32 sig);
Index: libgo/runtime/go-strslice.c
===================================================================
--- libgo/runtime/go-strslice.c	(revision 154460)
+++ libgo/runtime/go-strslice.c	(working copy)
@@ -18,7 +18,7 @@ __go_string_slice (const struct __go_str
   if (end == (size_t) -1)
     end = len;
   if (start > len || end < start || end > len)
-    __go_panic("string index out of bounds");
+    __go_panic_msg ("string index out of bounds");
   if (s == NULL)
     return NULL;
   len = end - start;
Index: libgo/runtime/go-panic.c
===================================================================
--- libgo/runtime/go-panic.c	(revision 154387)
+++ libgo/runtime/go-panic.c	(working copy)
@@ -4,31 +4,32 @@
    Use of this source code is governed by a BSD-style
    license that can be found in the LICENSE file.  */
 
-#include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
 
 #include "go-panic.h"
 
-/* This implements __go_panic which is used for the panic statement.
-   FIXME: This is only for testing.  */
+/* This implements __go_panic which is used for the panic
+   statement.  */
 
 void
-__go_panic(const char* format, ...)
+__go_panic ()
 {
-  if (*format == '\0')
-    fprintf(stderr, "panic");
-  else
-    {
-      fprintf(stderr, "panic: ");
-
-      va_list args;
-      va_start(args, format);
-      vfprintf(stderr, format, args);
-      va_end(args);
-    }
+  fputs ("\npanic\n", stderr);
+  abort ();
+}
 
-  fputc('\n', stderr);
+/* These are used by the runtime library.  */
 
-  abort();
+void
+__go_panic_msg (const char* msg)
+{
+  __go_print_msg (1, msg);
+  __go_panic ();
+}
+
+void
+__go_print_msg (_Bool is_panic, const char* msg)
+{
+  fputs (msg, is_panic ? stderr : stdout);
 }
Index: libgo/runtime/go-bad-index.c
===================================================================
--- libgo/runtime/go-bad-index.c	(revision 154387)
+++ libgo/runtime/go-bad-index.c	(working copy)
@@ -11,5 +11,5 @@ extern void __go_bad_index () __attribut
 void
 __go_bad_index ()
 {
-  __go_panic ("index out of range");
+  __go_panic_msg ("index out of range");
 }
Index: libgo/runtime/go-panic.h
===================================================================
--- libgo/runtime/go-panic.h	(revision 154387)
+++ libgo/runtime/go-panic.h	(working copy)
@@ -4,7 +4,13 @@
    Use of this source code is governed by a BSD-style
    license that can be found in the LICENSE file.  */
 
-extern void __go_panic(const char* format, ...)
-  __attribute__ ((format (printf, 1, 2)))
-  __attribute__ ((nonnull (1)))
+extern void __go_panic (void)
   __attribute__ ((noreturn));
+
+extern void __go_panic_msg (const char* msg)
+  __attribute__ ((noreturn));
+
+extern void __go_print_msg (_Bool is_panic, const char* msg);
+
+struct __go_string;
+extern void __go_print_string (_Bool is_panic, const struct __go_string *);
Index: libgo/runtime/go-rec-small.c
===================================================================
--- libgo/runtime/go-rec-small.c	(revision 154387)
+++ libgo/runtime/go-rec-small.c	(working copy)
@@ -127,7 +127,7 @@ __go_receive_acquire (struct __go_channe
 	    {
 	      ++channel->closed_op_count;
 	      if (channel->closed_op_count >= MAX_CLOSED_OPERATIONS)
-		__go_panic ("too many operations on closed channel");
+		__go_panic_msg ("too many operations on closed channel");
 	    }
 	  channel->saw_close = 1;
 	  channel->selected_for_receive = 0;

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