Commit f7191ecd by Chris Manghane Committed by Ian Lance Taylor

compiler: Use backend interface for function declarations.

	* go-gcc.cc (Backend::error_function): New function.
	(Backend::function): New function.
	(Backend::make_function): New function.
	(function_to_tree): New function.

From-SVN: r203403
parent cf5e3504
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.
(function_to_tree): New function.
2013-10-04 Chris Manghane <cmang@google.com>
* go-gcc.cc (Backend::convert_expression): New function.
......
......@@ -334,6 +334,17 @@ class Gcc_backend : public Backend
Bexpression*
label_address(Blabel*, Location);
// Functions.
Bfunction*
error_function()
{ return this->make_function(error_mark_node); }
Bfunction*
function(Btype* fntype, const std::string& name, const std::string& asm_name,
bool is_visible, bool is_declaration, bool is_inlinable,
bool disable_split_stack, bool in_unique_section, Location);
private:
// Make a Bexpression from a tree.
Bexpression*
......@@ -350,6 +361,10 @@ class Gcc_backend : public Backend
make_type(tree t)
{ return new Btype(t); }
Bfunction*
make_function(tree t)
{ return new Bfunction(t); }
Btype*
fill_in_struct(Btype*, const std::vector<Btyped_identifier>&);
......@@ -1724,6 +1739,56 @@ Gcc_backend::label_address(Blabel* label, Location location)
return this->make_expression(ret);
}
// Declare or define a new function.
Bfunction*
Gcc_backend::function(Btype* fntype, const std::string& name,
const std::string& asm_name, bool is_visible,
bool is_declaration, bool is_inlinable,
bool disable_split_stack, bool in_unique_section,
Location location)
{
tree functype = fntype->get_tree();
if (functype != error_mark_node)
{
gcc_assert(FUNCTION_POINTER_TYPE_P(functype));
functype = TREE_TYPE(functype);
}
tree id = get_identifier_from_string(name);
if (functype == error_mark_node || id == error_mark_node)
return this->error_function();
tree decl = build_decl(location.gcc_location(), FUNCTION_DECL, id, functype);
if (!asm_name.empty())
SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(asm_name));
if (is_visible)
TREE_PUBLIC(decl) = 1;
if (is_declaration)
DECL_EXTERNAL(decl) = 1;
else
{
tree restype = TREE_TYPE(functype);
tree resdecl =
build_decl(location.gcc_location(), RESULT_DECL, NULL_TREE, restype);
DECL_ARTIFICIAL(resdecl) = 1;
DECL_IGNORED_P(resdecl) = 1;
DECL_CONTEXT(resdecl) = decl;
DECL_RESULT(decl) = resdecl;
}
if (!is_inlinable)
DECL_UNINLINABLE(decl) = 1;
if (disable_split_stack)
{
tree attr = get_identifier("__no_split_stack__");
DECL_ATTRIBUTES(decl) = tree_cons(attr, NULL_TREE, NULL_TREE);
}
if (in_unique_section)
resolve_unique_section(decl, 0, 1);
go_preserve_from_gc(decl);
return new Bfunction(decl);
}
// The single backend.
static Gcc_backend gcc_backend;
......@@ -1799,3 +1864,9 @@ var_to_tree(Bvariable* bv)
{
return bv->get_tree();
}
tree
function_to_tree(Bfunction* bf)
{
return bf->get_tree();
}
......@@ -23,7 +23,7 @@ class Bexpression;
// The backend representation of a statement.
class Bstatement;
// The backend representation of a function definition.
// The backend representation of a function definition or declaration.
class Bfunction;
// The backend representation of a block.
......@@ -498,6 +498,32 @@ class Backend
// recover.
virtual Bexpression*
label_address(Blabel*, Location) = 0;
// Functions.
// Create an error function. This is used for cases which should
// not occur in a correct program, in order to keep the compilation
// going without crashing.
virtual Bfunction*
error_function() = 0;
// Declare or define a function of FNTYPE.
// NAME is the Go name of the function. ASM_NAME, if not the empty string, is
// the name that should be used in the symbol table; this will be non-empty if
// a magic extern comment is used.
// IS_VISIBLE is true if this function should be visible outside of the
// current compilation unit. IS_DECLARATION is true if this is a function
// declaration rather than a definition; the function definition will be in
// another compilation unit.
// IS_INLINABLE is true if the function can be inlined.
// DISABLE_SPLIT_STACK is true if this function may not split the stack; this
// is used for the implementation of recover.
// IN_UNIQUE_SECTION is true if this function should be put into a unique
// location if possible; this is used for field tracking.
virtual Bfunction*
function(Btype* fntype, const std::string& name, const std::string& asm_name,
bool is_visible, bool is_declaration, bool is_inlinable,
bool disable_split_stack, bool in_unique_section, Location) = 0;
};
// The backend interface has to define this function.
......@@ -517,5 +543,6 @@ extern tree expr_to_tree(Bexpression*);
extern tree stat_to_tree(Bstatement*);
extern tree block_to_tree(Bblock*);
extern tree var_to_tree(Bvariable*);
extern tree function_to_tree(Bfunction*);
#endif // !defined(GO_BACKEND_H)
......@@ -1240,15 +1240,11 @@ Func_expression::get_code_pointer(Gogo* gogo, Named_object* no, Location loc)
return error_mark_node;
}
tree id = no->get_id(gogo);
if (id == error_mark_node)
return error_mark_node;
tree fndecl;
if (no->is_function())
fndecl = no->func_value()->get_or_make_decl(gogo, no, id);
fndecl = no->func_value()->get_or_make_decl(gogo, no);
else if (no->is_function_declaration())
fndecl = no->func_declaration_value()->get_or_make_decl(gogo, no, id);
fndecl = no->func_declaration_value()->get_or_make_decl(gogo, no);
else
go_unreachable();
......@@ -9825,14 +9821,8 @@ Call_expression::do_get_tree(Translate_context* context)
}
tree fntype_tree = type_to_tree(fntype->get_backend(gogo));
if (fntype_tree == error_mark_node)
return error_mark_node;
go_assert(POINTER_TYPE_P(fntype_tree));
if (TREE_TYPE(fntype_tree) == error_mark_node)
return error_mark_node;
go_assert(TREE_CODE(TREE_TYPE(fntype_tree)) == RECORD_TYPE);
tree fnfield_type = TREE_TYPE(TYPE_FIELDS(TREE_TYPE(fntype_tree)));
if (fnfield_type == error_mark_node)
tree fnfield_type = type_to_tree(fntype->get_backend_fntype(gogo));
if (fntype_tree == error_mark_node || fnfield_type == error_mark_node)
return error_mark_node;
go_assert(FUNCTION_POINTER_TYPE_P(fnfield_type));
tree rettype = TREE_TYPE(TREE_TYPE(fnfield_type));
......
......@@ -5110,6 +5110,75 @@ Named_object::get_backend_variable(Gogo* gogo, Named_object* function)
go_unreachable();
}
// Return the external identifier for this object.
std::string
Named_object::get_id(Gogo* gogo)
{
go_assert(!this->is_variable() && !this->is_result_variable());
std::string decl_name;
if (this->is_function_declaration()
&& !this->func_declaration_value()->asm_name().empty())
decl_name = this->func_declaration_value()->asm_name();
else if (this->is_type()
&& Linemap::is_predeclared_location(this->type_value()->location()))
{
// We don't need the package name for builtin types.
decl_name = Gogo::unpack_hidden_name(this->name_);
}
else
{
std::string package_name;
if (this->package_ == NULL)
package_name = gogo->package_name();
else
package_name = this->package_->package_name();
// Note that this will be misleading if this is an unexported
// method generated for an embedded imported type. In that case
// the unexported method should have the package name of the
// package from which it is imported, but we are going to give
// it our package name. Fixing this would require knowing the
// package name, but we only know the package path. It might be
// better to use package paths here anyhow. This doesn't affect
// the assembler code, because we always set that name in
// Function::get_or_make_decl anyhow. FIXME.
decl_name = package_name + '.' + Gogo::unpack_hidden_name(this->name_);
Function_type* fntype;
if (this->is_function())
fntype = this->func_value()->type();
else if (this->is_function_declaration())
fntype = this->func_declaration_value()->type();
else
fntype = NULL;
if (fntype != NULL && fntype->is_method())
{
decl_name.push_back('.');
decl_name.append(fntype->receiver()->type()->mangled_name(gogo));
}
}
if (this->is_type())
{
unsigned int index;
const Named_object* in_function = this->type_value()->in_function(&index);
if (in_function != NULL)
{
decl_name += '$' + Gogo::unpack_hidden_name(in_function->name());
if (index > 0)
{
char buf[30];
snprintf(buf, sizeof buf, "%u", index);
decl_name += '$';
decl_name += buf;
}
}
}
return decl_name;
}
// Class Bindings.
Bindings::Bindings(Bindings* enclosing)
......
......@@ -48,6 +48,7 @@ class Bstatement;
class Bblock;
class Bvariable;
class Blabel;
class Bfunction;
// This file declares the basic classes used to hold the internal
// representation of Go which is built by the parser.
......@@ -1091,15 +1092,11 @@ class Function
// Return the function's decl given an identifier.
tree
get_or_make_decl(Gogo*, Named_object*, tree id);
get_or_make_decl(Gogo*, Named_object*);
// Return the function's decl after it has been built.
tree
get_decl() const
{
go_assert(this->fndecl_ != NULL);
return this->fndecl_;
}
get_decl() const;
// Set the function decl to hold a tree of the function code.
void
......@@ -1170,7 +1167,7 @@ class Function
// The function descriptor, if any.
Expression* descriptor_;
// The function decl.
tree fndecl_;
Bfunction* fndecl_;
// The defer stack variable. A pointer to this variable is used to
// distinguish the defer stack for one function from another. This
// is NULL unless we actually need a defer stack.
......@@ -1267,7 +1264,7 @@ class Function_declaration
// Return a decl for the function given an identifier.
tree
get_or_make_decl(Gogo*, Named_object*, tree id);
get_or_make_decl(Gogo*, Named_object*);
// If there is a descriptor, build it into the backend
// representation.
......@@ -1290,7 +1287,7 @@ class Function_declaration
// The function descriptor, if any.
Expression* descriptor_;
// The function decl if needed.
tree fndecl_;
Bfunction* fndecl_;
};
// A variable.
......@@ -2181,8 +2178,8 @@ class Named_object
Bvariable*
get_backend_variable(Gogo*, Named_object* function);
// Return a tree for the external identifier for this object.
tree
// Return the external identifier for this object.
std::string
get_id(Gogo*);
// Return a tree representing this object.
......
......@@ -3383,6 +3383,68 @@ Function_type::do_hash_for_method(Gogo* gogo) const
// Get the backend representation for a function type.
Btype*
Function_type::get_backend_fntype(Gogo* gogo)
{
if (this->fnbtype_ == NULL)
{
Backend::Btyped_identifier breceiver;
if (this->receiver_ != NULL)
{
breceiver.name = Gogo::unpack_hidden_name(this->receiver_->name());
// We always pass the address of the receiver parameter, in
// order to make interface calls work with unknown types.
Type* rtype = this->receiver_->type();
if (rtype->points_to() == NULL)
rtype = Type::make_pointer_type(rtype);
breceiver.btype = rtype->get_backend(gogo);
breceiver.location = this->receiver_->location();
}
std::vector<Backend::Btyped_identifier> bparameters;
if (this->parameters_ != NULL)
{
bparameters.resize(this->parameters_->size());
size_t i = 0;
for (Typed_identifier_list::const_iterator p =
this->parameters_->begin(); p != this->parameters_->end();
++p, ++i)
{
bparameters[i].name = Gogo::unpack_hidden_name(p->name());
bparameters[i].btype = p->type()->get_backend(gogo);
bparameters[i].location = p->location();
}
go_assert(i == bparameters.size());
}
std::vector<Backend::Btyped_identifier> bresults;
if (this->results_ != NULL)
{
bresults.resize(this->results_->size());
size_t i = 0;
for (Typed_identifier_list::const_iterator p =
this->results_->begin(); p != this->results_->end();
++p, ++i)
{
bresults[i].name = Gogo::unpack_hidden_name(p->name());
bresults[i].btype = p->type()->get_backend(gogo);
bresults[i].location = p->location();
}
go_assert(i == bresults.size());
}
this->fnbtype_ = gogo->backend()->function_type(breceiver, bparameters,
bresults,
this->location());
}
return this->fnbtype_;
}
// Get the backend representation for a Go function type.
Btype*
Function_type::do_get_backend(Gogo* gogo)
{
// When we do anything with a function value other than call it, it
......@@ -3395,57 +3457,9 @@ Function_type::do_get_backend(Gogo* gogo)
gogo->backend()->placeholder_struct_type("__go_descriptor", loc);
Btype* ptr_struct_type = gogo->backend()->pointer_type(struct_type);
Backend::Btyped_identifier breceiver;
if (this->receiver_ != NULL)
{
breceiver.name = Gogo::unpack_hidden_name(this->receiver_->name());
// We always pass the address of the receiver parameter, in
// order to make interface calls work with unknown types.
Type* rtype = this->receiver_->type();
if (rtype->points_to() == NULL)
rtype = Type::make_pointer_type(rtype);
breceiver.btype = rtype->get_backend(gogo);
breceiver.location = this->receiver_->location();
}
std::vector<Backend::Btyped_identifier> bparameters;
if (this->parameters_ != NULL)
{
bparameters.resize(this->parameters_->size());
size_t i = 0;
for (Typed_identifier_list::const_iterator p = this->parameters_->begin();
p != this->parameters_->end();
++p, ++i)
{
bparameters[i].name = Gogo::unpack_hidden_name(p->name());
bparameters[i].btype = p->type()->get_backend(gogo);
bparameters[i].location = p->location();
}
go_assert(i == bparameters.size());
}
std::vector<Backend::Btyped_identifier> bresults;
if (this->results_ != NULL)
{
bresults.resize(this->results_->size());
size_t i = 0;
for (Typed_identifier_list::const_iterator p = this->results_->begin();
p != this->results_->end();
++p, ++i)
{
bresults[i].name = Gogo::unpack_hidden_name(p->name());
bresults[i].btype = p->type()->get_backend(gogo);
bresults[i].location = p->location();
}
go_assert(i == bresults.size());
}
Btype* fntype = gogo->backend()->function_type(breceiver, bparameters,
bresults, loc);
std::vector<Backend::Btyped_identifier> fields(1);
fields[0].name = "code";
fields[0].btype = fntype;
fields[0].btype = this->get_backend_fntype(gogo);
fields[0].location = loc;
if (!gogo->backend()->set_placeholder_struct_type(struct_type, fields))
return gogo->backend()->error_type();
......
......@@ -1717,7 +1717,8 @@ class Function_type : public Type
Typed_identifier_list* results, Location location)
: Type(TYPE_FUNCTION),
receiver_(receiver), parameters_(parameters), results_(results),
location_(location), is_varargs_(false), is_builtin_(false)
location_(location), is_varargs_(false), is_builtin_(false),
fnbtype_(NULL)
{ }
// Get the receiver.
......@@ -1798,6 +1799,11 @@ class Function_type : public Type
static Type*
make_function_type_descriptor_type();
// Return the backend representation of this function type. This is used
// as the real type of a backend function declaration or defintion.
Btype*
get_backend_fntype(Gogo*);
protected:
int
do_traverse(Traverse*);
......@@ -1851,6 +1857,9 @@ class Function_type : public Type
// Whether this is a special builtin function which can not simply
// be called. This is used for len, cap, etc.
bool is_builtin_;
// The backend representation of this type for backend function
// declarations and definitions.
Btype* fnbtype_;
};
// The type of a pointer.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment