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] Redo builtin square root support


This patch redoes the builtin square root support in Go to be more
flexible for other math functions, and to use the builtin
functionality on the 80387 when using -fexcess-precision=standard
(which is the default for Go).  Committed to gccgo branch.

Ian


Index: libgo/go/math/sqrt.go
===================================================================
--- libgo/go/math/sqrt.go	(revision 154387)
+++ libgo/go/math/sqrt.go	(working copy)
@@ -4,6 +4,7 @@
 
 package math
 
+func libc_sqrt(float64) float64 __asm__("sqrt")
 
 /*
  *	sqrt returns the square root of its floating
@@ -30,5 +31,5 @@ func Sqrt(x float64) float64 {
 		return 0;
 	}
 
-	return __builtin_sqrt(x);
+	return libc_sqrt(x);
 }
Index: gcc/go/gogo.cc
===================================================================
--- gcc/go/gogo.cc	(revision 154387)
+++ gcc/go/gogo.cc	(working copy)
@@ -58,9 +58,8 @@ Gogo::Gogo()
 
   this->add_named_type(Type::make_float_type("float32", 32,
 					     RUNTIME_TYPE_CODE_FLOAT32));
-  Named_type* float64_type = Type::make_float_type("float64", 64,
-						   RUNTIME_TYPE_CODE_FLOAT64);
-  this->add_named_type(float64_type);
+  this->add_named_type(Type::make_float_type("float64", 64,
+					     RUNTIME_TYPE_CODE_FLOAT64));
 
   const int int_type_size = std::max(INT_TYPE_SIZE, 32);
   this->add_named_type(Type::make_integer_type("uint", true,
@@ -174,17 +173,6 @@ Gogo::Gogo()
 
   this->define_builtin_function_trees();
 
-  // For the math library.
-  Typed_identifier_list* sqrt_arg = new Typed_identifier_list();
-  sqrt_arg->push_back(Typed_identifier("x", float64_type, loc));
-  Typed_identifier_list* sqrt_result = new Typed_identifier_list();
-  sqrt_result->push_back(Typed_identifier("", float64_type, loc));
-  Function_type* sqrt_type = Type::make_function_type(NULL, sqrt_arg,
-						      sqrt_result, loc);
-  sqrt_type->set_is_builtin();
-  this->globals_->add_function_declaration("__builtin_sqrt", NULL, sqrt_type,
-					   loc);
-
   // Declare "init", to ensure that it is not defined with parameters
   // or return values.
   this->declare_function("init",
Index: gcc/go/gogo-tree.cc
===================================================================
--- gcc/go/gogo-tree.cc	(revision 154396)
+++ gcc/go/gogo-tree.cc	(working copy)
@@ -31,18 +31,35 @@ extern "C"
 #include "refcount.h"
 #include "gogo.h"
 
-// Define a builtin function.
+// Builtin functions.
+
+static std::map<std::string, tree> builtin_functions;
+
+// Define a builtin function.  BCODE is the builtin function code
+// defined by builtins.def.  NAME is the name of the builtin function.
+// LIBNAME is the name of the corresponding library function, and is
+// NULL if there isn't one.  FNTYPE is the type of the function.
+// CONST_P is true if the function has the const attribute.
 
 static void
-define_builtin(built_in_function bcode, const char* name, tree fntype,
-	       bool const_p)
+define_builtin(built_in_function bcode, const char* name, const char* libname,
+	       tree fntype, bool const_p)
 {
-  tree decl = add_builtin_function(name, fntype, bcode, BUILT_IN_NORMAL, NULL,
-				   NULL_TREE);
+  tree decl = add_builtin_function(name, fntype, bcode, BUILT_IN_NORMAL,
+				   libname, NULL_TREE);
   if (const_p)
     TREE_READONLY(decl) = 1;
   built_in_decls[bcode] = decl;
   implicit_built_in_decls[bcode] = decl;
+  builtin_functions[name] = decl;
+  if (libname != NULL)
+    {
+      decl = add_builtin_function(libname, fntype, bcode, BUILT_IN_NORMAL,
+				  NULL, NULL_TREE);
+      if (const_p)
+	TREE_READONLY(decl) = 1;
+      builtin_functions[libname] = decl;
+    }
 }
 
 // Create trees for implicit builtin functions.
@@ -54,35 +71,41 @@ Gogo::define_builtin_function_trees()
      for ++ and --.  */
   tree t = go_type_for_size(BITS_PER_UNIT, 1);
   tree p = build_pointer_type(build_qualified_type(t, TYPE_QUAL_VOLATILE));
-  define_builtin(BUILT_IN_ADD_AND_FETCH_1, "__sync_fetch_and_add_1",
+  define_builtin(BUILT_IN_ADD_AND_FETCH_1, "__sync_fetch_and_add_1", NULL,
 		 build_function_type_list(t, p, t, NULL_TREE), false);
 
   t = go_type_for_size(BITS_PER_UNIT * 2, 1);
   p = build_pointer_type(build_qualified_type(t, TYPE_QUAL_VOLATILE));
-  define_builtin (BUILT_IN_ADD_AND_FETCH_2, "__sync_fetch_and_add_2",
+  define_builtin (BUILT_IN_ADD_AND_FETCH_2, "__sync_fetch_and_add_2", NULL,
 		  build_function_type_list(t, p, t, NULL_TREE), false);
 
   t = go_type_for_size(BITS_PER_UNIT * 4, 1);
   p = build_pointer_type(build_qualified_type(t, TYPE_QUAL_VOLATILE));
-  define_builtin(BUILT_IN_ADD_AND_FETCH_4, "__sync_fetch_and_add_4",
+  define_builtin(BUILT_IN_ADD_AND_FETCH_4, "__sync_fetch_and_add_4", NULL,
 		 build_function_type_list(t, p, t, NULL_TREE), false);
 
   t = go_type_for_size(BITS_PER_UNIT * 8, 1);
   p = build_pointer_type(build_qualified_type(t, TYPE_QUAL_VOLATILE));
-  define_builtin(BUILT_IN_ADD_AND_FETCH_8, "__sync_fetch_and_add_8",
+  define_builtin(BUILT_IN_ADD_AND_FETCH_8, "__sync_fetch_and_add_8", NULL,
 		 build_function_type_list(t, p, t, NULL_TREE), false);
 
   // We use __builtin_expect for magic import functions.
-  define_builtin(BUILT_IN_EXPECT, "__builtin_expect",
+  define_builtin(BUILT_IN_EXPECT, "__builtin_expect", NULL,
 		 build_function_type_list(long_integer_type_node,
 					  long_integer_type_node,
 					  long_integer_type_node,
 					  NULL_TREE),
 		 true);
 
-  // We provide __builtin_sqrt for the math library.
-  define_builtin(BUILT_IN_SQRT, "__builtin_sqrt",
-		 build_function_type_list(double_type_node, double_type_node,
+  // We provide sqrt for the math library.
+  define_builtin(BUILT_IN_SQRT, "__builtin_sqrt", "sqrt",
+		 build_function_type_list(double_type_node,
+					  double_type_node,
+					  NULL_TREE),
+		 true);
+  define_builtin(BUILT_IN_SQRTL, "__builtin_sqrtl", "sqrtl",
+		 build_function_type_list(long_double_type_node,
+					  long_double_type_node,
 					  NULL_TREE),
 		 true);
 }
@@ -992,6 +1015,19 @@ Function_declaration::get_or_make_decl(G
 {
   if (this->fndecl_ == NULL_TREE)
     {
+      // Let Go code use an asm declaration to pick up a builtin
+      // function.
+      if (!this->asm_name_.empty())
+	{
+	  std::map<std::string, tree>::const_iterator p =
+	    builtin_functions.find(this->asm_name_);
+	  if (p != builtin_functions.end())
+	    {
+	      this->fndecl_ = p->second;
+	      return this->fndecl_;
+	    }
+	}
+
       tree functype = this->fntype_->get_tree(gogo);
       tree decl;
       if (functype == error_mark_node)
Index: gcc/go/expressions.cc
===================================================================
--- gcc/go/expressions.cc	(revision 154460)
+++ gcc/go/expressions.cc	(working copy)
@@ -5001,10 +5001,7 @@ class Builtin_call_expression : public C
       // Builtin functions from the unsafe package.
       BUILTIN_ALIGNOF,
       BUILTIN_OFFSETOF,
-      BUILTIN_SIZEOF,
-
-      // gccgo specific builtin functions.
-      BUILTIN_SQRT
+      BUILTIN_SIZEOF
     };
 
   Expression*
@@ -5056,8 +5053,6 @@ Builtin_call_expression::Builtin_call_ex
     this->code_ = BUILTIN_OFFSETOF;
   else if (name == "Sizeof")
     this->code_ = BUILTIN_SIZEOF;
-  else if (name == "__builtin_sqrt")
-    this->code_ = BUILTIN_SQRT;
   else
     gcc_unreachable();
 }
@@ -5333,9 +5328,6 @@ Builtin_call_expression::do_type()
 
     case BUILTIN_CLOSED:
       return Type::lookup_bool_type();
-
-    case BUILTIN_SQRT:
-      return Type::lookup_float_type("float64");
     }
 }
 
@@ -5347,8 +5339,6 @@ Builtin_call_expression::do_determine_ty
   this->fn()->determine_type_no_context();
 
   Type_context subcontext(NULL, true);
-  if (this->code_ == BUILTIN_SQRT)
-    subcontext.type = Type::lookup_float_type("float64");
   const Expression_list* args = this->args();
   if (args != NULL)
     {
@@ -5493,17 +5483,6 @@ Builtin_call_expression::do_check_types(
 	}
       break;
 
-    case BUILTIN_SQRT:
-      if (this->check_one_arg())
-	{
-	  Expression* arg = this->one_arg();
-	  if (arg->type()->float_type() == NULL
-	      || arg->type()->float_type()->is_abstract()
-	      || arg->type()->float_type()->bits() != 64)
-	    this->report_error(_("argument 1 has incompatible type"));
-	}
-      break;
-
     default:
       gcc_unreachable();
     }
@@ -5827,22 +5806,6 @@ Builtin_call_expression::do_get_tree(Tra
 	return ret;
       }
 
-    case BUILTIN_SQRT:
-      {
-	const Expression_list* args = this->args();
-	gcc_assert(args != NULL && args->size() == 1);
-	Expression* arg = args->front();
-	tree arg_tree = arg->get_tree(context);
-	if (arg_tree == error_mark_node)
-	  return error_mark_node;
-	tree type = Type::lookup_float_type("float64")->get_tree(gogo);
-	arg_tree = fold_convert_loc(this->location(), type, arg_tree);
-	tree fn = built_in_decls[BUILT_IN_SQRT];
-	tree call = build1(ADDR_EXPR, build_pointer_type(TREE_TYPE(fn)), fn);
-	call = build_call_nary(TREE_TYPE(TREE_TYPE(fn)), call, 1, arg_tree);
-	return fold_convert_loc(this->location(), type, call);
-      }
-
     default:
       gcc_unreachable();
     }
@@ -6438,7 +6401,39 @@ Call_expression::do_get_tree(Translate_c
   if (fn == error_mark_node || TREE_TYPE(fn) == error_mark_node)
     return error_mark_node;
 
-  tree ret = build_call_array(rettype, fn, nargs, args);
+  // This is to support builtin math functions when using 80387 math.
+  tree fndecl = fn;
+  if (TREE_CODE(fndecl) == ADDR_EXPR)
+    fndecl = TREE_OPERAND(fndecl, 0);
+  tree excess_type = NULL_TREE;
+  if (DECL_P(fndecl)
+      && DECL_IS_BUILTIN(fndecl)
+      && DECL_BUILT_IN_CLASS(fndecl) == BUILT_IN_NORMAL
+      && nargs > 0
+      && SCALAR_FLOAT_TYPE_P(rettype)
+      && SCALAR_FLOAT_TYPE_P(TREE_TYPE(args[0])))
+    {
+      excess_type = excess_precision_type(TREE_TYPE(args[0]));
+      if (excess_type != NULL_TREE)
+	{
+	  tree excess_fndecl = mathfn_built_in(excess_type,
+					       DECL_FUNCTION_CODE(fndecl));
+	  if (excess_fndecl == NULL_TREE)
+	    excess_type = NULL_TREE;
+	  else
+	    {
+	      fn = build_fold_addr_expr_loc(location, excess_fndecl);
+	      for (int i = 0; i < nargs; ++i)
+		{
+		  if (SCALAR_FLOAT_TYPE_P(TREE_TYPE(args[i])))
+		    args[i] = convert_to_real(excess_type, args[i]);
+		}
+	    }
+	}
+    }
+
+  tree ret = build_call_array(excess_type != NULL_TREE ? excess_type : rettype,
+			      fn, nargs, args);
   delete[] args;
 
   SET_EXPR_LOCATION(ret, location);
@@ -6450,6 +6445,13 @@ Call_expression::do_get_tree(Translate_c
 	CALL_EXPR_STATIC_CHAIN(ret) = closure_tree;
     }
 
+  if (excess_type != NULL_TREE)
+    {
+      // Calling convert_to_real here can undo our excess precision
+      // change.  That may or may not be a bug in convert_to_real.
+      ret = build1(NOP_EXPR, rettype, ret);
+    }
+
   // If there is more than one result, we will refer to the call
   // multiple times.
   if (fntype->results() != NULL && fntype->results()->size() > 1)

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