aboutsummaryrefslogtreecommitdiff
path: root/gcc/go
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@google.com>2013-11-23 19:01:57 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2013-11-23 19:01:57 +0000
commit18768faed3875e1d33b122fbf867788add95f056 (patch)
tree4b25b8df89857ef87087b3f0a341c0a0d717af7a /gcc/go
parent7c42f52b7419ea5db30917cf39c15783e5aa2bf5 (diff)
downloadgcc-18768faed3875e1d33b122fbf867788add95f056.zip
gcc-18768faed3875e1d33b122fbf867788add95f056.tar.gz
gcc-18768faed3875e1d33b122fbf867788add95f056.tar.bz2
compiler: Fix backend representation of calls to interface methods.
Also unify all identical result parameter sets into a single struct type, and fix the use of backend function pointers. * go-gcc.cc (Gcc_backend::function_type): Add result_struct parameter. From-SVN: r205316
Diffstat (limited to 'gcc/go')
-rw-r--r--gcc/go/ChangeLog5
-rw-r--r--gcc/go/go-gcc.cc29
-rw-r--r--gcc/go/gofrontend/backend.h15
-rw-r--r--gcc/go/gofrontend/expressions.cc7
-rw-r--r--gcc/go/gofrontend/types.cc164
-rw-r--r--gcc/go/gofrontend/types.h39
6 files changed, 202 insertions, 57 deletions
diff --git a/gcc/go/ChangeLog b/gcc/go/ChangeLog
index d2e3573..a7dafac 100644
--- a/gcc/go/ChangeLog
+++ b/gcc/go/ChangeLog
@@ -1,3 +1,8 @@
+2013-11-23 Ian Lance Taylor <iant@google.com>
+
+ * go-gcc.cc (Gcc_backend::function_type): Add result_struct
+ parameter.
+
2013-11-22 Andrew MacLeod <amacleod@redhat.com>
* go-gcc.cc: Add required include files from gimple.h.
diff --git a/gcc/go/go-gcc.cc b/gcc/go/go-gcc.cc
index 50e31ff..939be20 100644
--- a/gcc/go/go-gcc.cc
+++ b/gcc/go/go-gcc.cc
@@ -158,6 +158,7 @@ class Gcc_backend : public Backend
function_type(const Btyped_identifier&,
const std::vector<Btyped_identifier>&,
const std::vector<Btyped_identifier>&,
+ Btype*,
const Location);
Btype*
@@ -493,7 +494,8 @@ Btype*
Gcc_backend::function_type(const Btyped_identifier& receiver,
const std::vector<Btyped_identifier>& parameters,
const std::vector<Btyped_identifier>& results,
- Location location)
+ Btype* result_struct,
+ Location)
{
tree args = NULL_TREE;
tree* pp = &args;
@@ -528,29 +530,8 @@ Gcc_backend::function_type(const Btyped_identifier& receiver,
result = results.front().btype->get_tree();
else
{
- result = make_node(RECORD_TYPE);
- tree field_trees = NULL_TREE;
- pp = &field_trees;
- for (std::vector<Btyped_identifier>::const_iterator p = results.begin();
- p != results.end();
- ++p)
- {
- const std::string name = (p->name.empty()
- ? "UNNAMED"
- : p->name);
- tree name_tree = get_identifier_from_string(name);
- tree field_type_tree = p->btype->get_tree();
- if (field_type_tree == error_mark_node)
- return this->error_type();
- gcc_assert(TYPE_SIZE(field_type_tree) != NULL_TREE);
- tree field = build_decl(location.gcc_location(), FIELD_DECL,
- name_tree, field_type_tree);
- DECL_CONTEXT(field) = result;
- *pp = field;
- pp = &DECL_CHAIN(field);
- }
- TYPE_FIELDS(result) = field_trees;
- layout_type(result);
+ gcc_assert(result_struct != NULL);
+ result = result_struct->get_tree();
}
if (result == error_mark_node)
return this->error_type();
diff --git a/gcc/go/gofrontend/backend.h b/gcc/go/gofrontend/backend.h
index 6f2c321..8344da4 100644
--- a/gcc/go/gofrontend/backend.h
+++ b/gcc/go/gofrontend/backend.h
@@ -101,11 +101,15 @@ class Backend
// is provided so that the names are available. This should return
// not the type of a Go function (which is a pointer to a struct)
// but the type of a C function pointer (which will be used as the
- // type of the first field of the struct).
+ // type of the first field of the struct). If there is more than
+ // one result, RESULT_STRUCT is a struct type to hold the results,
+ // and RESULTS may be ignored; if there are zero or one results,
+ // RESULT_STRUCT is NULL.
virtual Btype*
function_type(const Btyped_identifier& receiver,
const std::vector<Btyped_identifier>& parameters,
const std::vector<Btyped_identifier>& results,
+ Btype* result_struct,
Location location) = 0;
// Get a struct type.
@@ -121,10 +125,11 @@ class Backend
// NAME is the name of the type, and the location is where the named
// type is defined. This function is also used for unnamed function
// types with multiple results, in which case the type has no name
- // and NAME will be empty. FOR_FUNCTION is true if this is for a Go
- // function type, which corresponds to a C/C++ pointer to function
- // type. The return value will later be passed as the first
- // parameter to set_placeholder_pointer_type or
+ // and NAME will be empty. FOR_FUNCTION is true if this is for a C
+ // pointer to function type. A Go func type is represented as a
+ // pointer to a struct, and the first field of the struct is a C
+ // pointer to function. The return value will later be passed as
+ // the first parameter to set_placeholder_pointer_type or
// set_placeholder_function_type.
virtual Btype*
placeholder_pointer_type(const std::string& name, Location,
diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc
index dd2bee4..4f9368e 100644
--- a/gcc/go/gofrontend/expressions.cc
+++ b/gcc/go/gofrontend/expressions.cc
@@ -9863,8 +9863,11 @@ Call_expression::do_get_tree(Translate_context* context)
fndecl = TREE_OPERAND(fndecl, 0);
// Add a type cast in case the type of the function is a recursive
- // type which refers to itself.
- if (!DECL_P(fndecl) || !DECL_IS_BUILTIN(fndecl))
+ // type which refers to itself. We don't do this for an interface
+ // method because 1) an interface method never refers to itself, so
+ // we always have a function type here; 2) we pass an extra first
+ // argument to an interface method, so fnfield_type is not correct.
+ if ((!DECL_P(fndecl) || !DECL_IS_BUILTIN(fndecl)) && !is_interface_method)
fn = fold_convert_loc(location.gcc_location(), fnfield_type, fn);
// This is to support builtin math functions when using 80387 math.
diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc
index 4f2bd0b..28a5b32 100644
--- a/gcc/go/gofrontend/types.cc
+++ b/gcc/go/gofrontend/types.cc
@@ -1059,8 +1059,9 @@ Type::get_backend_placeholder(Gogo* gogo)
{
case TYPE_FUNCTION:
{
+ // A Go function type is a pointer to a struct type.
Location loc = this->function_type()->location();
- bt = gogo->backend()->placeholder_pointer_type("", loc, true);
+ bt = gogo->backend()->placeholder_pointer_type("", loc, false);
}
break;
@@ -1153,7 +1154,7 @@ Type::finish_backend(Gogo* gogo, Btype *placeholder)
case TYPE_FUNCTION:
{
Btype* bt = this->do_get_backend(gogo);
- if (!gogo->backend()->set_placeholder_function_type(placeholder, bt))
+ if (!gogo->backend()->set_placeholder_pointer_type(placeholder, bt))
go_assert(saw_errors());
}
break;
@@ -3378,6 +3379,48 @@ Function_type::do_hash_for_method(Gogo* gogo) const
return ret;
}
+// Hash result parameters.
+
+unsigned int
+Function_type::Results_hash::operator()(const Typed_identifier_list* t) const
+{
+ unsigned int hash = 0;
+ for (Typed_identifier_list::const_iterator p = t->begin();
+ p != t->end();
+ ++p)
+ {
+ hash <<= 2;
+ hash = Type::hash_string(p->name(), hash);
+ hash += p->type()->hash_for_method(NULL);
+ }
+ return hash;
+}
+
+// Compare result parameters so that can map identical result
+// parameters to a single struct type.
+
+bool
+Function_type::Results_equal::operator()(const Typed_identifier_list* a,
+ const Typed_identifier_list* b) const
+{
+ if (a->size() != b->size())
+ return false;
+ Typed_identifier_list::const_iterator pa = a->begin();
+ for (Typed_identifier_list::const_iterator pb = b->begin();
+ pb != b->end();
+ ++pa, ++pb)
+ {
+ if (pa->name() != pb->name()
+ || !Type::are_identical(pa->type(), pb->type(), true, NULL))
+ return false;
+ }
+ return true;
+}
+
+// Hash from results to a backend struct type.
+
+Function_type::Results_structs Function_type::results_structs;
+
// Get the backend representation for a function type.
Btype*
@@ -3416,12 +3459,14 @@ Function_type::get_backend_fntype(Gogo* gogo)
}
std::vector<Backend::Btyped_identifier> bresults;
+ Btype* bresult_struct = NULL;
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();
+ this->results_->begin();
+ p != this->results_->end();
++p, ++i)
{
bresults[i].name = Gogo::unpack_hidden_name(p->name());
@@ -3429,10 +3474,42 @@ Function_type::get_backend_fntype(Gogo* gogo)
bresults[i].location = p->location();
}
go_assert(i == bresults.size());
+
+ if (this->results_->size() > 1)
+ {
+ // Use the same results struct for all functions that
+ // return the same set of results. This is useful to
+ // unify calls to interface methods with other calls.
+ std::pair<Typed_identifier_list*, Btype*> val;
+ val.first = this->results_;
+ val.second = NULL;
+ std::pair<Results_structs::iterator, bool> ins =
+ Function_type::results_structs.insert(val);
+ if (ins.second)
+ {
+ // Build a new struct type.
+ Struct_field_list* sfl = new Struct_field_list;
+ for (Typed_identifier_list::const_iterator p =
+ this->results_->begin();
+ p != this->results_->end();
+ ++p)
+ {
+ Typed_identifier tid = *p;
+ if (tid.name().empty())
+ tid = Typed_identifier("UNNAMED", tid.type(),
+ tid.location());
+ sfl->push_back(Struct_field(tid));
+ }
+ Struct_type* st = Type::make_struct_type(sfl,
+ this->location());
+ ins.first->second = st->get_backend(gogo);
+ }
+ bresult_struct = ins.first->second;
+ }
}
this->fnbtype_ = gogo->backend()->function_type(breceiver, bparameters,
- bresults,
+ bresults, bresult_struct,
this->location());
}
@@ -7134,18 +7211,18 @@ Interface_type::get_backend_empty_interface_type(Gogo* gogo)
return empty_interface_type;
}
-// Return the fields of a non-empty interface type. This is not
-// declared in types.h so that types.h doesn't have to #include
-// backend.h.
+// Return a pointer to the backend representation of the method table.
-static void
-get_backend_interface_fields(Gogo* gogo, Interface_type* type,
- bool use_placeholder,
- std::vector<Backend::Btyped_identifier>* bfields)
+Btype*
+Interface_type::get_backend_methods(Gogo* gogo)
{
- Location loc = type->location();
+ if (this->bmethods_ != NULL && !this->bmethods_is_placeholder_)
+ return this->bmethods_;
- std::vector<Backend::Btyped_identifier> mfields(type->methods()->size() + 1);
+ Location loc = this->location();
+
+ std::vector<Backend::Btyped_identifier>
+ mfields(this->all_methods_->size() + 1);
Type* pdt = Type::make_type_descriptor_ptr_type();
mfields[0].name = "__type_descriptor";
@@ -7154,8 +7231,8 @@ get_backend_interface_fields(Gogo* gogo, Interface_type* type,
std::string last_name = "";
size_t i = 1;
- for (Typed_identifier_list::const_iterator p = type->methods()->begin();
- p != type->methods()->end();
+ for (Typed_identifier_list::const_iterator p = this->all_methods_->begin();
+ p != this->all_methods_->end();
++p, ++i)
{
// The type of the method in Go only includes the parameters.
@@ -7186,21 +7263,56 @@ get_backend_interface_fields(Gogo* gogo, Interface_type* type,
ft->location());
mfields[i].name = Gogo::unpack_hidden_name(p->name());
- mfields[i].btype = (use_placeholder
- ? mft->get_backend_placeholder(gogo)
- : mft->get_backend(gogo));
+ mfields[i].btype = mft->get_backend_fntype(gogo);
mfields[i].location = loc;
+
// Sanity check: the names should be sorted.
go_assert(p->name() > last_name);
last_name = p->name();
}
- Btype* methods = gogo->backend()->struct_type(mfields);
+ Btype* st = gogo->backend()->struct_type(mfields);
+ Btype* ret = gogo->backend()->pointer_type(st);
+
+ if (this->bmethods_ != NULL && this->bmethods_is_placeholder_)
+ gogo->backend()->set_placeholder_pointer_type(this->bmethods_, ret);
+ this->bmethods_ = ret;
+ this->bmethods_is_placeholder_ = false;
+ return ret;
+}
+
+// Return a placeholder for the pointer to the backend methods table.
+
+Btype*
+Interface_type::get_backend_methods_placeholder(Gogo* gogo)
+{
+ if (this->bmethods_ == NULL)
+ {
+ Location loc = this->location();
+ this->bmethods_ = gogo->backend()->placeholder_pointer_type("", loc,
+ false);
+ this->bmethods_is_placeholder_ = true;
+ }
+ return this->bmethods_;
+}
+
+// Return the fields of a non-empty interface type. This is not
+// declared in types.h so that types.h doesn't have to #include
+// backend.h.
+
+static void
+get_backend_interface_fields(Gogo* gogo, Interface_type* type,
+ bool use_placeholder,
+ std::vector<Backend::Btyped_identifier>* bfields)
+{
+ Location loc = type->location();
bfields->resize(2);
(*bfields)[0].name = "__methods";
- (*bfields)[0].btype = gogo->backend()->pointer_type(methods);
+ (*bfields)[0].btype = (use_placeholder
+ ? type->get_backend_methods_placeholder(gogo)
+ : type->get_backend_methods(gogo));
(*bfields)[0].location = loc;
Type* vt = Type::make_pointer_type(Type::make_void_type());
@@ -7241,7 +7353,7 @@ Interface_type::do_get_backend(Gogo* gogo)
void
Interface_type::finish_backend_methods(Gogo* gogo)
{
- if (!this->interface_type()->is_empty())
+ if (!this->is_empty())
{
const Typed_identifier_list* methods = this->methods();
if (methods != NULL)
@@ -7251,6 +7363,10 @@ Interface_type::finish_backend_methods(Gogo* gogo)
++p)
p->type()->get_backend(gogo);
}
+
+ // Getting the backend methods now will set the placeholder
+ // pointer.
+ this->get_backend_methods(gogo);
}
}
@@ -8542,14 +8658,14 @@ Named_type::do_get_backend(Gogo* gogo)
if (this->seen_in_get_backend_)
{
this->is_circular_ = true;
- return gogo->backend()->circular_pointer_type(bt, true);
+ return gogo->backend()->circular_pointer_type(bt, false);
}
this->seen_in_get_backend_ = true;
bt1 = Type::get_named_base_btype(gogo, base);
this->seen_in_get_backend_ = false;
if (this->is_circular_)
- bt1 = gogo->backend()->circular_pointer_type(bt, true);
- if (!gogo->backend()->set_placeholder_function_type(bt, bt1))
+ bt1 = gogo->backend()->circular_pointer_type(bt, false);
+ if (!gogo->backend()->set_placeholder_pointer_type(bt, bt1))
bt = gogo->backend()->error_type();
return bt;
diff --git a/gcc/go/gofrontend/types.h b/gcc/go/gofrontend/types.h
index 12a7c85..d1a739a 100644
--- a/gcc/go/gofrontend/types.h
+++ b/gcc/go/gofrontend/types.h
@@ -1840,6 +1840,27 @@ class Function_type : public Type
type_descriptor_params(Type*, const Typed_identifier*,
const Typed_identifier_list*);
+ // A mapping from a list of result types to a backend struct type.
+ class Results_hash
+ {
+ public:
+ unsigned int
+ operator()(const Typed_identifier_list*) const;
+ };
+
+ class Results_equal
+ {
+ public:
+ bool
+ operator()(const Typed_identifier_list*,
+ const Typed_identifier_list*) const;
+ };
+
+ typedef Unordered_map_hash(Typed_identifier_list*, Btype*,
+ Results_hash, Results_equal) Results_structs;
+
+ static Results_structs results_structs;
+
// The receiver name and type. This will be NULL for a normal
// function, non-NULL for a method.
Typed_identifier* receiver_;
@@ -2552,8 +2573,9 @@ class Interface_type : public Type
Interface_type(Typed_identifier_list* methods, Location location)
: Type(TYPE_INTERFACE),
parse_methods_(methods), all_methods_(NULL), location_(location),
- interface_btype_(NULL), assume_identical_(NULL),
- methods_are_finalized_(false), seen_(false)
+ interface_btype_(NULL), bmethods_(NULL), assume_identical_(NULL),
+ methods_are_finalized_(false), bmethods_is_placeholder_(false),
+ seen_(false)
{ go_assert(methods == NULL || !methods->empty()); }
// The location where the interface type was defined.
@@ -2620,6 +2642,15 @@ class Interface_type : public Type
static Btype*
get_backend_empty_interface_type(Gogo*);
+ // Get a pointer to the backend representation of the method table.
+ Btype*
+ get_backend_methods(Gogo*);
+
+ // Return a placeholder for the backend representation of the
+ // pointer to the method table.
+ Btype*
+ get_backend_methods_placeholder(Gogo*);
+
// Finish the backend representation of the method types.
void
finish_backend_methods(Gogo*);
@@ -2686,11 +2717,15 @@ class Interface_type : public Type
Location location_;
// The backend representation of this type during backend conversion.
Btype* interface_btype_;
+ // The backend representation of the pointer to the method table.
+ Btype* bmethods_;
// A list of interface types assumed to be identical during
// interface comparison.
mutable Assume_identical* assume_identical_;
// Whether the methods have been finalized.
bool methods_are_finalized_;
+ // Whether the bmethods_ field is a placeholder.
+ bool bmethods_is_placeholder_;
// Used to avoid endless recursion in do_mangled_name.
mutable bool seen_;
};