summaryrefslogtreecommitdiff
path: root/gcc/go
diff options
context:
space:
mode:
authorMartin Jambor <mjambor@suse.cz>2017-07-31 14:43:24 +0200
committerMartin Jambor <mjambor@suse.cz>2017-07-31 14:43:24 +0200
commitb32f12dece884f1fa0f04c643a77105aff6ce8bc (patch)
treecdab5f10806561fc198f907299b0e55eb5701ef0 /gcc/go
parent166bec868d991fdf71f9a66f994e5977fcab4aa2 (diff)
parenta168a775e93ec31ae743ad282d8e60fa1c116891 (diff)
downloadgcc-gcn.tar.gz
Merge branch 'master' into gcngcn
Diffstat (limited to 'gcc/go')
-rw-r--r--gcc/go/ChangeLog5
-rw-r--r--gcc/go/go-backend.c8
-rw-r--r--gcc/go/gofrontend/MERGE2
-rw-r--r--gcc/go/gofrontend/expressions.cc194
-rw-r--r--gcc/go/gofrontend/expressions.h18
-rw-r--r--gcc/go/gofrontend/gogo.cc2
-rw-r--r--gcc/go/gofrontend/types.cc51
-rw-r--r--gcc/go/gofrontend/types.h12
8 files changed, 148 insertions, 144 deletions
diff --git a/gcc/go/ChangeLog b/gcc/go/ChangeLog
index ac0dbe3f99d..1925111f169 100644
--- a/gcc/go/ChangeLog
+++ b/gcc/go/ChangeLog
@@ -1,3 +1,8 @@
+2017-07-27 Tony Reix <tony.reix@atos.net>
+
+ * go-backend.c (go_write_export_data): Use EXCLUDE section for
+ AIX.
+
2017-06-09 Ian Lance Taylor <iant@golang.org>
* go-lang.c (go_langhook_post_options): If -fsplit-stack is turned
diff --git a/gcc/go/go-backend.c b/gcc/go/go-backend.c
index 2f8d2f405da..21277ea2eb9 100644
--- a/gcc/go/go-backend.c
+++ b/gcc/go/go-backend.c
@@ -45,6 +45,10 @@ along with GCC; see the file COPYING3. If not see
#define GO_EXPORT_SECTION_NAME ".go_export"
#endif
+#ifndef TARGET_AIX
+#define TARGET_AIX 0
+#endif
+
/* This file holds all the cases where the Go frontend needs
information from gcc's backend. */
@@ -101,7 +105,9 @@ go_write_export_data (const char *bytes, unsigned int size)
if (sec == NULL)
{
gcc_assert (targetm_common.have_named_sections);
- sec = get_section (GO_EXPORT_SECTION_NAME, SECTION_DEBUG, NULL);
+ sec = get_section (GO_EXPORT_SECTION_NAME,
+ TARGET_AIX ? SECTION_EXCLUDE : SECTION_DEBUG,
+ NULL);
}
switch_to_section (sec);
diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE
index 416a5876da8..685cff9935b 100644
--- a/gcc/go/gofrontend/MERGE
+++ b/gcc/go/gofrontend/MERGE
@@ -1,4 +1,4 @@
-0a20181d00d43a423c55f4e772b759fba0619478
+f7c36b27a49131f60eedde260896d310d735d408
The first line of this file holds the git revision number of the last
merge done from the gofrontend repository.
diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc
index 12505b23939..eb23ec26ecf 100644
--- a/gcc/go/gofrontend/expressions.cc
+++ b/gcc/go/gofrontend/expressions.cc
@@ -1204,7 +1204,14 @@ Func_expression::do_get_backend(Translate_context* context)
// expression. It is a pointer to a struct whose first field points
// to the function code and whose remaining fields are the addresses
// of the closed-over variables.
- return this->closure_->get_backend(context);
+ Bexpression *bexpr = this->closure_->get_backend(context);
+
+ // Introduce a backend type conversion, to account for any differences
+ // between the argument type (function descriptor, struct with a
+ // single field) and the closure (struct with multiple fields).
+ Gogo* gogo = context->gogo();
+ Btype *btype = this->type()->get_backend(gogo);
+ return gogo->backend()->convert_expression(btype, bexpr, this->location());
}
// Ast dump for function.
@@ -9456,24 +9463,28 @@ Call_expression::do_lower(Gogo* gogo, Named_object* function,
this->is_varargs_, loc);
// If this call returns multiple results, create a temporary
- // variable for each result.
- size_t rc = this->result_count();
- if (rc > 1 && this->results_ == NULL)
+ // variable to hold them.
+ if (this->result_count() > 1 && this->call_temp_ == NULL)
{
- std::vector<Temporary_statement*>* temps =
- new std::vector<Temporary_statement*>;
- temps->reserve(rc);
+ Struct_field_list* sfl = new Struct_field_list();
+ Function_type* fntype = this->get_function_type();
const Typed_identifier_list* results = fntype->results();
+ Location loc = this->location();
+
+ int i = 0;
+ char buf[20];
for (Typed_identifier_list::const_iterator p = results->begin();
- p != results->end();
- ++p)
- {
- Temporary_statement* temp = Statement::make_temporary(p->type(),
- NULL, loc);
- inserter->insert(temp);
- temps->push_back(temp);
- }
- this->results_ = temps;
+ p != results->end();
+ ++p, ++i)
+ {
+ snprintf(buf, sizeof buf, "res%d", i);
+ sfl->push_back(Struct_field(Typed_identifier(buf, p->type(), loc)));
+ }
+
+ Struct_type* st = Type::make_struct_type(sfl, loc);
+ st->set_is_struct_incomparable();
+ this->call_temp_ = Statement::make_temporary(st, NULL, loc);
+ inserter->insert(this->call_temp_);
}
// Handle a call to a varargs function by packaging up the extra
@@ -9772,30 +9783,6 @@ Call_expression::do_flatten(Gogo* gogo, Named_object*,
this->args_ = args;
}
- size_t rc = this->result_count();
- if (rc > 1 && this->call_temp_ == NULL)
- {
- Struct_field_list* sfl = new Struct_field_list();
- Function_type* fntype = this->get_function_type();
- const Typed_identifier_list* results = fntype->results();
- Location loc = this->location();
-
- int i = 0;
- char buf[20];
- for (Typed_identifier_list::const_iterator p = results->begin();
- p != results->end();
- ++p, ++i)
- {
- snprintf(buf, sizeof buf, "res%d", i);
- sfl->push_back(Struct_field(Typed_identifier(buf, p->type(), loc)));
- }
-
- Struct_type* st = Type::make_struct_type(sfl, loc);
- st->set_is_struct_incomparable();
- this->call_temp_ = Statement::make_temporary(st, NULL, loc);
- inserter->insert(this->call_temp_);
- }
-
return this;
}
@@ -9820,17 +9807,18 @@ Call_expression::result_count() const
return fntype->results()->size();
}
-// Return the temporary which holds a result.
+// Return the temporary that holds the result for a call with multiple
+// results.
Temporary_statement*
-Call_expression::result(size_t i) const
+Call_expression::results() const
{
- if (this->results_ == NULL || this->results_->size() <= i)
+ if (this->call_temp_ == NULL)
{
go_assert(saw_errors());
return NULL;
}
- return (*this->results_)[i];
+ return this->call_temp_;
}
// Set the number of results expected from a call expression.
@@ -10184,8 +10172,21 @@ Call_expression::interface_method_function(
Bexpression*
Call_expression::do_get_backend(Translate_context* context)
{
+ Location location = this->location();
+
if (this->call_ != NULL)
- return this->call_;
+ {
+ // If the call returns multiple results, make a new reference to
+ // the temporary.
+ if (this->call_temp_ != NULL)
+ {
+ Expression* ref =
+ Expression::make_temporary_reference(this->call_temp_, location);
+ return ref->get_backend(context);
+ }
+
+ return this->call_;
+ }
Function_type* fntype = this->get_function_type();
if (fntype == NULL)
@@ -10195,7 +10196,6 @@ Call_expression::do_get_backend(Translate_context* context)
return context->backend()->error_expression();
Gogo* gogo = context->gogo();
- Location location = this->location();
Func_expression* func = this->fn_->func_expression();
Interface_field_reference_expression* interface_method =
@@ -10316,91 +10316,28 @@ Call_expression::do_get_backend(Translate_context* context)
fn_args, bclosure,
location);
- if (this->results_ != NULL)
+ if (this->call_temp_ != NULL)
{
- Bexpression* bcall_ref = this->call_result_ref(context);
- Bstatement* assn_stmt =
- gogo->backend()->assignment_statement(bfunction,
- bcall_ref, call, location);
+ // This case occurs when the call returns multiple results.
- this->call_ = this->set_results(context);
+ Expression* ref = Expression::make_temporary_reference(this->call_temp_,
+ location);
+ Bexpression* bref = ref->get_backend(context);
+ Bstatement* bassn = gogo->backend()->assignment_statement(bfunction,
+ bref, call,
+ location);
- Bexpression* set_and_call =
- gogo->backend()->compound_expression(assn_stmt, this->call_,
- location);
- return set_and_call;
+ ref = Expression::make_temporary_reference(this->call_temp_, location);
+ this->call_ = ref->get_backend(context);
+
+ return gogo->backend()->compound_expression(bassn, this->call_,
+ location);
}
this->call_ = call;
return this->call_;
}
-// Return the backend representation of a reference to the struct used
-// to capture the result of a multiple-output call.
-
-Bexpression*
-Call_expression::call_result_ref(Translate_context* context)
-{
- go_assert(this->call_temp_ != NULL);
- Location location = this->location();
- Expression* call_ref =
- Expression::make_temporary_reference(this->call_temp_, location);
- Bexpression* bcall_ref = call_ref->get_backend(context);
- return bcall_ref;
-}
-
-// Set the result variables if this call returns multiple results.
-
-Bexpression*
-Call_expression::set_results(Translate_context* context)
-{
- Gogo* gogo = context->gogo();
-
- Bexpression* results = NULL;
- Location loc = this->location();
-
- go_assert(this->call_temp_ != NULL);
-
- size_t rc = this->result_count();
- for (size_t i = 0; i < rc; ++i)
- {
- Temporary_statement* temp = this->result(i);
- if (temp == NULL)
- {
- go_assert(saw_errors());
- return gogo->backend()->error_expression();
- }
- Temporary_reference_expression* ref =
- Expression::make_temporary_reference(temp, loc);
- ref->set_is_lvalue();
-
- Bfunction* bfunction = context->function()->func_value()->get_decl();
- Bexpression* result_ref = ref->get_backend(context);
- Bexpression* bcall_ref = this->call_result_ref(context);
- Bexpression* call_result =
- gogo->backend()->struct_field_expression(bcall_ref, i, loc);
- Bstatement* assn_stmt =
- gogo->backend()->assignment_statement(bfunction,
- result_ref, call_result, loc);
-
- bcall_ref = this->call_result_ref(context);
- call_result = gogo->backend()->struct_field_expression(bcall_ref, i, loc);
- Bexpression* result =
- gogo->backend()->compound_expression(assn_stmt, call_result, loc);
-
- if (results == NULL)
- results = result;
- else
- {
- Bstatement* expr_stmt =
- gogo->backend()->expression_statement(bfunction, result);
- results =
- gogo->backend()->compound_expression(expr_stmt, results, loc);
- }
- }
- return results;
-}
-
// Dump ast representation for a call expressin.
void
@@ -10521,13 +10458,14 @@ Call_result_expression::do_get_backend(Translate_context* context)
go_assert(this->call_->is_error_expression());
return context->backend()->error_expression();
}
- Temporary_statement* ts = ce->result(this->index_);
+ Temporary_statement* ts = ce->results();
if (ts == NULL)
{
go_assert(saw_errors());
return context->backend()->error_expression();
}
Expression* ref = Expression::make_temporary_reference(ts, this->location());
+ ref = Expression::make_field_reference(ref, this->index_, this->location());
return ref->get_backend(context);
}
@@ -12119,12 +12057,15 @@ Interface_field_reference_expression::do_get_backend(Translate_context* context)
Bexpression* bclosure =
Expression::make_heap_expression(expr, loc)->get_backend(context);
+ Gogo* gogo = context->gogo();
+ Btype* btype = this->type()->get_backend(gogo);
+ bclosure = gogo->backend()->convert_expression(btype, bclosure, loc);
+
Expression* nil_check =
Expression::make_binary(OPERATOR_EQEQ, this->expr_,
Expression::make_nil(loc), loc);
Bexpression* bnil_check = nil_check->get_backend(context);
- Gogo* gogo = context->gogo();
Bexpression* bcrash = gogo->runtime_error(RUNTIME_ERROR_NIL_DEREFERENCE,
loc)->get_backend(context);
@@ -14300,7 +14241,10 @@ Type_guard_expression::do_get_backend(Translate_context* context)
Expression::convert_for_assignment(context->gogo(), this->type_,
this->expr_, this->location());
- return conversion->get_backend(context);
+ Gogo* gogo = context->gogo();
+ Btype* bt = this->type_->get_backend(gogo);
+ Bexpression* bexpr = conversion->get_backend(context);
+ return gogo->backend()->convert_expression(bt, bexpr, this->location());
}
// Dump ast representation for a type guard expression.
diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h
index a144ff4168b..0c742fd92df 100644
--- a/gcc/go/gofrontend/expressions.h
+++ b/gcc/go/gofrontend/expressions.h
@@ -2115,8 +2115,8 @@ class Call_expression : public Expression
Call_expression(Expression* fn, Expression_list* args, bool is_varargs,
Location location)
: Expression(EXPRESSION_CALL, location),
- fn_(fn), args_(args), type_(NULL), results_(NULL), call_(NULL),
- call_temp_(NULL), expected_result_count_(0), is_varargs_(is_varargs),
+ fn_(fn), args_(args), type_(NULL), call_(NULL), call_temp_(NULL)
+ , expected_result_count_(0), is_varargs_(is_varargs),
varargs_are_lowered_(false), types_are_determined_(false),
is_deferred_(false), is_concurrent_(false), issued_error_(false),
is_multi_value_arg_(false), is_flattened_(false)
@@ -2144,11 +2144,11 @@ class Call_expression : public Expression
size_t
result_count() const;
- // Return the temporary variable which holds result I. This is only
- // valid after the expression has been lowered, and is only valid
- // for calls which return multiple results.
+ // Return the temporary variable that holds the results. This is
+ // only valid after the expression has been lowered, and is only
+ // valid for calls which return multiple results.
Temporary_statement*
- result(size_t i) const;
+ results() const;
// Set the number of results expected from this call. This is used
// when the call appears in a context that expects multiple results,
@@ -2292,9 +2292,6 @@ class Call_expression : public Expression
Bexpression*
set_results(Translate_context*);
- Bexpression*
- call_result_ref(Translate_context* context);
-
// The function to call.
Expression* fn_;
// The arguments to pass. This may be NULL if there are no
@@ -2302,9 +2299,6 @@ class Call_expression : public Expression
Expression_list* args_;
// The type of the expression, to avoid recomputing it.
Type* type_;
- // The list of temporaries which will hold the results if the
- // function returns a tuple.
- std::vector<Temporary_statement*>* results_;
// The backend expression for the call, used for a call which returns a tuple.
Bexpression* call_;
// A temporary variable to store this call if the function returns a tuple.
diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc
index a9d72ff4aa0..ca4b454a238 100644
--- a/gcc/go/gofrontend/gogo.cc
+++ b/gcc/go/gofrontend/gogo.cc
@@ -4824,6 +4824,8 @@ Gogo::convert_named_types()
Runtime::convert_types(this);
this->named_types_are_converted_ = true;
+
+ Type::finish_pointer_types(this);
}
// Convert all names types in a set of bindings.
diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc
index b2756fde048..4d923733667 100644
--- a/gcc/go/gofrontend/types.cc
+++ b/gcc/go/gofrontend/types.cc
@@ -1057,6 +1057,8 @@ Type::get_backend_placeholder(Gogo* gogo)
{
Location loc = Linemap::unknown_location();
bt = gogo->backend()->placeholder_pointer_type("", loc, false);
+ Pointer_type* pt = this->convert<Pointer_type, TYPE_POINTER>();
+ Type::placeholder_pointers.push_back(pt);
}
break;
@@ -5516,14 +5518,22 @@ Pointer_type::do_import(Import* imp)
return Type::make_pointer_type(to);
}
+// Cache of pointer types. Key is "to" type, value is pointer type
+// that points to key.
+
+Type::Pointer_type_table Type::pointer_types;
+
+// A list of placeholder pointer types. We keep this so we can ensure
+// they are finalized.
+
+std::vector<Pointer_type*> Type::placeholder_pointers;
+
// Make a pointer type.
Pointer_type*
Type::make_pointer_type(Type* to_type)
{
- typedef Unordered_map(Type*, Pointer_type*) Hashtable;
- static Hashtable pointer_types;
- Hashtable::const_iterator p = pointer_types.find(to_type);
+ Pointer_type_table::const_iterator p = pointer_types.find(to_type);
if (p != pointer_types.end())
return p->second;
Pointer_type* ret = new Pointer_type(to_type);
@@ -5531,6 +5541,37 @@ Type::make_pointer_type(Type* to_type)
return ret;
}
+// This helper is invoked immediately after named types have been
+// converted, to clean up any unresolved pointer types remaining in
+// the pointer type cache.
+//
+// The motivation for this routine: occasionally the compiler creates
+// some specific pointer type as part of a lowering operation (ex:
+// pointer-to-void), then Type::backend_type_size() is invoked on the
+// type (which creates a Btype placeholder for it), that placeholder
+// passed somewhere along the line to the back end, but since there is
+// no reference to the type in user code, there is never a call to
+// Type::finish_backend for the type (hence the Btype remains as an
+// unresolved placeholder). Calling this routine will clean up such
+// instances.
+
+void
+Type::finish_pointer_types(Gogo* gogo)
+{
+ // We don't use begin() and end() because it is possible to add new
+ // placeholder pointer types as we finalized existing ones.
+ for (size_t i = 0; i < Type::placeholder_pointers.size(); i++)
+ {
+ Pointer_type* pt = Type::placeholder_pointers[i];
+ Type_btypes::iterator tbti = Type::type_btypes.find(pt);
+ if (tbti != Type::type_btypes.end() && tbti->second.is_placeholder)
+ {
+ pt->finish_backend(gogo, tbti->second.btype);
+ tbti->second.is_placeholder = false;
+ }
+ }
+}
+
// The nil type. We use a special type for nil because it is not the
// same as any other type. In C term nil has type void*, but there is
// no such type in Go.
@@ -10994,13 +11035,13 @@ Named_type::do_get_backend(Gogo* gogo)
if (this->seen_in_get_backend_)
{
this->is_circular_ = true;
- return gogo->backend()->circular_pointer_type(bt, false);
+ return gogo->backend()->circular_pointer_type(bt, true);
}
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, false);
+ bt1 = gogo->backend()->circular_pointer_type(bt, true);
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 aeb04d6c50f..f15f08ae4f0 100644
--- a/gcc/go/gofrontend/types.h
+++ b/gcc/go/gofrontend/types.h
@@ -504,6 +504,9 @@ class Type
static Pointer_type*
make_pointer_type(Type*);
+ static void
+ finish_pointer_types(Gogo* gogo);
+
static Type*
make_nil_type();
@@ -1341,6 +1344,15 @@ class Type
static Type_functions type_functions_table;
+ // Cache for reusing existing pointer types; maps from pointed-to-type
+ // to pointer type.
+ typedef Unordered_map(Type*, Pointer_type*) Pointer_type_table;
+
+ static Pointer_type_table pointer_types;
+
+ // List of placeholder pointer types.
+ static std::vector<Pointer_type*> placeholder_pointers;
+
// The type classification.
Type_classification classification_;
// The backend representation of the type, once it has been