diff mbox

Go patch committed: Use backend interface for function code exprs

Message ID mcrmwmfbgfm.fsf@iant-glaptop.roam.corp.google.com
State New
Headers show

Commit Message

Ian Lance Taylor Oct. 11, 2013, 10:17 p.m. UTC
This patch by Chris Manghane changes the Go frontend to use the backend
interface for function code expressions.  Bootstrapped and ran Go
testsuite on x86_64-unknown-linux-gnu.  Committed to mainline.

Ian


2013-10-11  Chris Manghane  <cmang@google.com>

	* go-gcc.cc (Gcc_backend::function_code_expression): New
	function.
diff mbox

Patch

Index: gcc/go/gofrontend/gogo.h
===================================================================
--- gcc/go/gofrontend/gogo.h	(revision 203403)
+++ gcc/go/gofrontend/gogo.h	(working copy)
@@ -1090,8 +1090,8 @@  class Function
     this->descriptor_ = descriptor;
   }
 
-  // Return the function's decl given an identifier.
-  tree
+  // Return the backend representation.
+  Bfunction*
   get_or_make_decl(Gogo*, Named_object*);
 
   // Return the function's decl after it has been built.
@@ -1262,8 +1262,8 @@  class Function_declaration
   has_descriptor() const
   { return this->descriptor_ != NULL; }
 
-  // Return a decl for the function given an identifier.
-  tree
+  // Return a backend representation.
+  Bfunction*
   get_or_make_decl(Gogo*, Named_object*);
 
   // If there is a descriptor, build it into the backend
Index: gcc/go/gofrontend/gogo-tree.cc
===================================================================
--- gcc/go/gofrontend/gogo-tree.cc	(revision 203403)
+++ gcc/go/gofrontend/gogo-tree.cc	(working copy)
@@ -1089,7 +1089,7 @@  Named_object::get_tree(Gogo* gogo, Named
     case NAMED_OBJECT_FUNC:
       {
 	Function* func = this->u_.func_value;
-	decl = func->get_or_make_decl(gogo, this);
+	decl = function_to_tree(func->get_or_make_decl(gogo, this));
 	if (decl != error_mark_node)
 	  {
 	    if (func->block() != NULL)
@@ -1214,83 +1214,9 @@  Variable::get_init_block(Gogo* gogo, Nam
   return block_tree;
 }
 
-// Get a tree for a function decl.
+// Get the backend representation.
 
-tree
-Function::get_or_make_decl(Gogo* gogo, Named_object* no)
-{
-  if (this->fndecl_ == NULL)
-    {
-      std::string asm_name;
-      bool is_visible = false;
-      if (no->package() != NULL)
-        ;
-      else if (this->enclosing_ != NULL || Gogo::is_thunk(no))
-        ;
-      else if (Gogo::unpack_hidden_name(no->name()) == "init"
-               && !this->type_->is_method())
-        ;
-      else if (Gogo::unpack_hidden_name(no->name()) == "main"
-               && gogo->is_main_package())
-        is_visible = true;
-      // Methods have to be public even if they are hidden because
-      // they can be pulled into type descriptors when using
-      // anonymous fields.
-      else if (!Gogo::is_hidden_name(no->name())
-               || this->type_->is_method())
-        {
-          is_visible = true;
-          std::string pkgpath = gogo->pkgpath_symbol();
-          if (this->type_->is_method()
-              && Gogo::is_hidden_name(no->name())
-              && Gogo::hidden_name_pkgpath(no->name()) != gogo->pkgpath())
-            {
-              // This is a method we created for an unexported
-              // method of an imported embedded type.  We need to
-              // use the pkgpath of the imported package to avoid
-              // a possible name collision.  See bug478 for a test
-              // case.
-              pkgpath = Gogo::hidden_name_pkgpath(no->name());
-              pkgpath = Gogo::pkgpath_for_symbol(pkgpath);
-            }
-
-          asm_name = pkgpath;
-          asm_name.append(1, '.');
-          asm_name.append(Gogo::unpack_hidden_name(no->name()));
-          if (this->type_->is_method())
-            {
-              asm_name.append(1, '.');
-              Type* rtype = this->type_->receiver()->type();
-              asm_name.append(rtype->mangled_name(gogo));
-            }
-        }
-
-      // If a function calls the predeclared recover function, we
-      // can't inline it, because recover behaves differently in a
-      // function passed directly to defer.  If this is a recover
-      // thunk that we built to test whether a function can be
-      // recovered, we can't inline it, because that will mess up
-      // our return address comparison.
-      bool is_inlinable = !(this->calls_recover_ || this->is_recover_thunk_);
-
-      // If this is a thunk created to call a function which calls
-      // the predeclared recover function, we need to disable
-      // stack splitting for the thunk.
-      bool disable_split_stack = this->is_recover_thunk_;
-
-      Btype* functype = this->type_->get_backend_fntype(gogo);
-      this->fndecl_ =
-          gogo->backend()->function(functype, no->get_id(gogo), asm_name,
-                                    is_visible, false, is_inlinable,
-                                    disable_split_stack,
-                                    this->in_unique_section_, this->location());
-    }
-  return function_to_tree(this->fndecl_);
-}
-
-// Get a tree for a function declaration.
-
-tree
+Bfunction*
 Function_declaration::get_or_make_decl(Gogo* gogo, Named_object* no)
 {
   if (this->fndecl_ == NULL)
@@ -1304,7 +1230,7 @@  Function_declaration::get_or_make_decl(G
 	  if (p != builtin_functions.end())
 	    {
 	      this->fndecl_ = tree_to_function(p->second);
-	      return p->second;
+	      return this->fndecl_;
 	    }
 	}
 
@@ -1331,7 +1257,7 @@  Function_declaration::get_or_make_decl(G
                                     this->location());
     }
 
-  return function_to_tree(this->fndecl_);
+  return this->fndecl_;
 }
 
 // Return the function's decl after it has been built.
@@ -2202,14 +2128,14 @@  Gogo::interface_method_table_for_type(co
       go_assert(m != NULL);
 
       Named_object* no = m->named_object();
-      tree fndecl;
+      Bfunction* bf;
       if (no->is_function())
-	fndecl = no->func_value()->get_or_make_decl(this, no);
+	bf = no->func_value()->get_or_make_decl(this, no);
       else if (no->is_function_declaration())
-	fndecl = no->func_declaration_value()->get_or_make_decl(this, no);
+	bf = no->func_declaration_value()->get_or_make_decl(this, no);
       else
 	go_unreachable();
-      fndecl = build_fold_addr_expr(fndecl);
+      tree fndecl = build_fold_addr_expr(function_to_tree(bf));
 
       elt = pointers->quick_push(empty);
       elt->index = size_int(i);
Index: gcc/go/gofrontend/gogo.cc
===================================================================
--- gcc/go/gofrontend/gogo.cc	(revision 203403)
+++ gcc/go/gofrontend/gogo.cc	(working copy)
@@ -3819,6 +3819,80 @@  Function::import_func(Import* imp, std::
   *presults = results;
 }
 
+// Get the backend representation.
+
+Bfunction*
+Function::get_or_make_decl(Gogo* gogo, Named_object* no)
+{
+  if (this->fndecl_ == NULL)
+    {
+      std::string asm_name;
+      bool is_visible = false;
+      if (no->package() != NULL)
+        ;
+      else if (this->enclosing_ != NULL || Gogo::is_thunk(no))
+        ;
+      else if (Gogo::unpack_hidden_name(no->name()) == "init"
+               && !this->type_->is_method())
+        ;
+      else if (Gogo::unpack_hidden_name(no->name()) == "main"
+               && gogo->is_main_package())
+        is_visible = true;
+      // Methods have to be public even if they are hidden because
+      // they can be pulled into type descriptors when using
+      // anonymous fields.
+      else if (!Gogo::is_hidden_name(no->name())
+               || this->type_->is_method())
+        {
+          is_visible = true;
+          std::string pkgpath = gogo->pkgpath_symbol();
+          if (this->type_->is_method()
+              && Gogo::is_hidden_name(no->name())
+              && Gogo::hidden_name_pkgpath(no->name()) != gogo->pkgpath())
+            {
+              // This is a method we created for an unexported
+              // method of an imported embedded type.  We need to
+              // use the pkgpath of the imported package to avoid
+              // a possible name collision.  See bug478 for a test
+              // case.
+              pkgpath = Gogo::hidden_name_pkgpath(no->name());
+              pkgpath = Gogo::pkgpath_for_symbol(pkgpath);
+            }
+
+          asm_name = pkgpath;
+          asm_name.append(1, '.');
+          asm_name.append(Gogo::unpack_hidden_name(no->name()));
+          if (this->type_->is_method())
+            {
+              asm_name.append(1, '.');
+              Type* rtype = this->type_->receiver()->type();
+              asm_name.append(rtype->mangled_name(gogo));
+            }
+        }
+
+      // If a function calls the predeclared recover function, we
+      // can't inline it, because recover behaves differently in a
+      // function passed directly to defer.  If this is a recover
+      // thunk that we built to test whether a function can be
+      // recovered, we can't inline it, because that will mess up
+      // our return address comparison.
+      bool is_inlinable = !(this->calls_recover_ || this->is_recover_thunk_);
+
+      // If this is a thunk created to call a function which calls
+      // the predeclared recover function, we need to disable
+      // stack splitting for the thunk.
+      bool disable_split_stack = this->is_recover_thunk_;
+
+      Btype* functype = this->type_->get_backend_fntype(gogo);
+      this->fndecl_ =
+          gogo->backend()->function(functype, no->get_id(gogo), asm_name,
+                                    is_visible, false, is_inlinable,
+                                    disable_split_stack,
+                                    this->in_unique_section_, this->location());
+    }
+  return this->fndecl_;
+}
+
 // Class Block.
 
 Block::Block(Block* enclosing, Location location)
Index: gcc/go/gofrontend/expressions.cc
===================================================================
--- gcc/go/gofrontend/expressions.cc	(revision 203454)
+++ gcc/go/gofrontend/expressions.cc	(working copy)
@@ -1219,7 +1219,7 @@  Func_expression::do_type()
 
 // Get the tree for the code of a function expression.
 
-tree
+Bexpression*
 Func_expression::get_code_pointer(Gogo* gogo, Named_object* no, Location loc)
 {
   Function_type* fntype;
@@ -1237,10 +1237,10 @@  Func_expression::get_code_pointer(Gogo*
       error_at(loc,
 	       "invalid use of special builtin function %qs; must be called",
 	       no->message_name().c_str());
-      return error_mark_node;
+      return gogo->backend()->error_expression();
     }
 
-  tree fndecl;
+  Bfunction* fndecl;
   if (no->is_function())
     fndecl = no->func_value()->get_or_make_decl(gogo, no);
   else if (no->is_function_declaration())
@@ -1248,10 +1248,7 @@  Func_expression::get_code_pointer(Gogo*
   else
     go_unreachable();
 
-  if (fndecl == error_mark_node)
-    return error_mark_node;
-
-  return build_fold_addr_expr_loc(loc.gcc_location(), fndecl);
+  return gogo->backend()->function_code_expression(fndecl, loc);
 }
 
 // Get the tree for a function expression.  This is used when we take
@@ -1488,8 +1485,10 @@  class Func_code_reference_expression : p
 tree
 Func_code_reference_expression::do_get_tree(Translate_context* context)
 {
-  return Func_expression::get_code_pointer(context->gogo(), this->function_,
-					   this->location());
+  Bexpression* ret =
+      Func_expression::get_code_pointer(context->gogo(), this->function_,
+                                        this->location());
+  return expr_to_tree(ret);
 }
 
 // Make a reference to the code of a function.
@@ -9846,7 +9845,7 @@  Call_expression::do_get_tree(Translate_c
   if (func != NULL)
     {
       Named_object* no = func->named_object();
-      fn = Func_expression::get_code_pointer(gogo, no, location);
+      fn = expr_to_tree(Func_expression::get_code_pointer(gogo, no, location));
       if (!has_closure)
 	closure_tree = NULL_TREE;
       else
Index: gcc/go/gofrontend/expressions.h
===================================================================
--- gcc/go/gofrontend/expressions.h	(revision 203292)
+++ gcc/go/gofrontend/expressions.h	(working copy)
@@ -1514,8 +1514,8 @@  class Func_expression : public Expressio
   closure()
   { return this->closure_; }
 
-  // Return a tree for the code for a function.
-  static tree
+  // Return a backend expression for the code of a function.
+  static Bexpression*
   get_code_pointer(Gogo*, Named_object* function, Location loc);
 
  protected:
Index: gcc/go/gofrontend/backend.h
===================================================================
--- gcc/go/gofrontend/backend.h	(revision 203403)
+++ gcc/go/gofrontend/backend.h	(working copy)
@@ -266,6 +266,11 @@  class Backend
   virtual Bexpression*
   convert_expression(Btype* type, Bexpression* expr, Location) = 0;
 
+  // Create an expression for the address of a function.  This is used to
+  // get the address of the code for a function.
+  virtual Bexpression*
+  function_code_expression(Bfunction*, Location) = 0;
+
   // Statements.
 
   // Create an error statement.  This is used for cases which should
Index: gcc/go/go-gcc.cc
===================================================================
--- gcc/go/go-gcc.cc	(revision 203403)
+++ gcc/go/go-gcc.cc	(working copy)
@@ -232,6 +232,9 @@  class Gcc_backend : public Backend
   Bexpression*
   convert_expression(Btype* type, Bexpression* expr, Location);
 
+  Bexpression*
+  function_code_expression(Bfunction*, Location);
+
   // Statements.
 
   Bstatement*
@@ -981,6 +984,19 @@  Gcc_backend::convert_expression(Btype* t
   return tree_to_expr(ret);
 }
 
+// Get the address of a function.
+
+Bexpression*
+Gcc_backend::function_code_expression(Bfunction* bfunc, Location location)
+{
+  tree func = bfunc->get_tree();
+  if (func == error_mark_node)
+    return this->error_expression();
+
+  tree ret = build_fold_addr_expr_loc(location.gcc_location(), func);
+  return this->make_expression(ret);
+}
+
 // An expression as a statement.
 
 Bstatement*