This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Go patch committed: Use backend interface for function code exprs
- From: Ian Lance Taylor <iant at google dot com>
- To: gcc-patches at gcc dot gnu dot org, gofrontend-dev at googlegroups dot com
- Date: Fri, 11 Oct 2013 15:17:49 -0700
- Subject: Go patch committed: Use backend interface for function code exprs
- Authentication-results: sourceware.org; auth=none
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.
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*