compiler: Use backend interface for function code expressions.
* go-gcc.cc (Gcc_backend::function_code_expression): New function. From-SVN: r203467
This commit is contained in:
parent
ef3cfba23d
commit
b7d93b468a
8 changed files with 135 additions and 110 deletions
|
@ -1,26 +1,31 @@
|
|||
2013-10-11 Chris Manghane <cmang@google.com>
|
||||
|
||||
* go-gcc.cc (Gcc_backend::function_code_expression): New
|
||||
function.
|
||||
|
||||
2013-10-10 Chris Manghane <cmang@google.com>
|
||||
|
||||
* go-gcc.cc (Backend::error_function): New function.
|
||||
(Backend::function): New function.
|
||||
(Backend::make_function): New function.
|
||||
* go-gcc.cc (Gcc_backend::error_function): New function.
|
||||
(Gcc_backend::function): New function.
|
||||
(Gcc_backend::make_function): New function.
|
||||
(function_to_tree): New function.
|
||||
|
||||
2013-10-04 Chris Manghane <cmang@google.com>
|
||||
|
||||
* go-gcc.cc (Backend::convert_expression): New function.
|
||||
* go-gcc.cc (Gcc_backend::convert_expression): New function.
|
||||
|
||||
2013-10-02 Chris Manghane <cmang@google.com>
|
||||
|
||||
* go-gcc.cc: Include "real.h" and "realmpfr.h".
|
||||
(Backend::integer_constant_expression): New function.
|
||||
(Backend::float_constant_expression): New function.
|
||||
(Backend::complex_constant_expression): New function.
|
||||
(Gcc_backend::integer_constant_expression): New function.
|
||||
(Gcc_backend::float_constant_expression): New function.
|
||||
(Gcc_backend::complex_constant_expression): New function.
|
||||
|
||||
2013-09-30 Chris Manghane <cmang@google.com>
|
||||
|
||||
* go-gcc.cc (Backend::error_expression): New function.
|
||||
(Backend::var_expression): New function.
|
||||
(Backend::indirect_expression): New function.
|
||||
* go-gcc.cc (Gcc_backend::error_expression): New function.
|
||||
(Gcc_backend::var_expression): New function.
|
||||
(Gcc_backend::indirect_expression): New function.
|
||||
|
||||
2013-09-25 Tom Tromey <tromey@redhat.com>
|
||||
|
||||
|
@ -515,7 +520,7 @@
|
|||
|
||||
2011-04-14 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
* go-gcc.cc (Backend::error_statement): New function.
|
||||
* go-gcc.cc (Gcc_backend::error_statement): New function.
|
||||
|
||||
2011-04-13 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
|
|
|
@ -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* type, Bexpression* expr, Location)
|
|||
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*
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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* gogo, Named_object* no, Location loc)
|
|||
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* gogo, Named_object* no, Location loc)
|
|||
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 : public Expression
|
|||
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_context* context)
|
|||
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
|
||||
|
|
|
@ -1514,8 +1514,8 @@ class Func_expression : public Expression
|
|||
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:
|
||||
|
|
|
@ -1089,7 +1089,7 @@ Named_object::get_tree(Gogo* gogo, Named_object* function)
|
|||
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, Named_object* function, tree var_decl)
|
|||
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(Gogo* gogo, Named_object* no)
|
|||
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(Gogo* gogo, Named_object* no)
|
|||
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(const Interface_type* interface,
|
|||
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);
|
||||
|
|
|
@ -3819,6 +3819,80 @@ Function::import_func(Import* imp, std::string* pname,
|
|||
*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)
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue