Commit 94039447 by Ian Lance Taylor Committed by Ian Lance Taylor

Use backend interface for return statements.

	* go-gcc.cc: #include "tree-iterator.h", "gimple.h", and "gogo.h".
	(class Bfunction): Define.
	(Gcc_backend::assignment_statement): Rename from assignment.
	Check for errors.
	(Gcc_backend::return_statement): New function.
	(tree_to_function): New function.
	* Make-lang.in (go/go-gcc.o): Depend on tree-iterator.h,
	$(GIMPLE_H), and $(GO_GOGO_H).

From-SVN: r171959
parent 69387b92
2011-04-04 Ian Lance Taylor <iant@google.com>
* go-gcc.cc: #include "tree-iterator.h", "gimple.h", and "gogo.h".
(class Bfunction): Define.
(Gcc_backend::assignment_statement): Rename from assignment.
Check for errors.
(Gcc_backend::return_statement): New function.
(tree_to_function): New function.
* Make-lang.in (go/go-gcc.o): Depend on tree-iterator.h,
$(GIMPLE_H), and $(GO_GOGO_H).
2011-04-03 Ian Lance Taylor <iant@google.com> 2011-04-03 Ian Lance Taylor <iant@google.com>
* go-gcc.cc: New file. * go-gcc.cc: New file.
......
...@@ -236,7 +236,8 @@ go/go-lang.o: go/go-lang.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(OPTS_H) \ ...@@ -236,7 +236,8 @@ go/go-lang.o: go/go-lang.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(OPTS_H) \
GOINCLUDES = -I $(srcdir)/go -I $(srcdir)/go/gofrontend GOINCLUDES = -I $(srcdir)/go -I $(srcdir)/go/gofrontend
go/go-gcc.o: go/go-gcc.cc $(GO_SYSTEM_H) $(TREE_H) go/gofrontend/backend.h go/go-gcc.o: go/go-gcc.cc $(GO_SYSTEM_H) $(TREE_H) tree-iterator.h \
$(GIMPLE_H) $(GO_GOGO_H) go/gofrontend/backend.h
$(CXX) -c $(GOINCLUDES) $(ALL_CPPFLAGS) $(ALL_CXXFLAGS) $< $(OUTPUT_OPTION) $(CXX) -c $(GOINCLUDES) $(ALL_CPPFLAGS) $(ALL_CXXFLAGS) $< $(OUTPUT_OPTION)
go/%.o: go/gofrontend/%.cc go/%.o: go/gofrontend/%.cc
......
...@@ -30,11 +30,14 @@ extern "C" ...@@ -30,11 +30,14 @@ extern "C"
#endif #endif
#include "tree.h" #include "tree.h"
#include "tree-iterator.h"
#include "gimple.h"
#ifndef ENABLE_BUILD_WITH_CXX #ifndef ENABLE_BUILD_WITH_CXX
} }
#endif #endif
#include "gogo.h"
#include "backend.h" #include "backend.h"
// A class wrapping a tree. // A class wrapping a tree.
...@@ -79,6 +82,14 @@ class Bstatement : public Gcc_tree ...@@ -79,6 +82,14 @@ class Bstatement : public Gcc_tree
{ } { }
}; };
class Bfunction : public Gcc_tree
{
public:
Bfunction(tree t)
: Gcc_tree(t)
{ }
};
// This file implements the interface between the Go frontend proper // This file implements the interface between the Go frontend proper
// and the gcc IR. This implements specific instantiations of // and the gcc IR. This implements specific instantiations of
// abstract classes defined by the Go frontend proper. The Go // abstract classes defined by the Go frontend proper. The Go
...@@ -149,8 +160,12 @@ class Gcc_backend : public Backend ...@@ -149,8 +160,12 @@ class Gcc_backend : public Backend
// Create an assignment statement. // Create an assignment statement.
Bstatement* Bstatement*
assignment(Bexpression* lhs, Bexpression* rhs, assignment_statement(Bexpression* lhs, Bexpression* rhs, source_location);
source_location location);
// Create a return statement.
Bstatement*
return_statement(Bfunction*, const std::vector<Bexpression*>&,
source_location);
private: private:
// Make a Bstatement from a tree. // Make a Bstatement from a tree.
...@@ -162,13 +177,76 @@ class Gcc_backend : public Backend ...@@ -162,13 +177,76 @@ class Gcc_backend : public Backend
// Assignment. // Assignment.
Bstatement* Bstatement*
Gcc_backend::assignment(Bexpression* lhs, Bexpression* rhs, Gcc_backend::assignment_statement(Bexpression* lhs, Bexpression* rhs,
source_location location) source_location location)
{ {
tree lhs_tree = lhs->get_tree();
tree rhs_tree = rhs->get_tree();
if (lhs_tree == error_mark_node || rhs_tree == error_mark_node)
return this->make_statement(error_mark_node);
return this->make_statement(fold_build2_loc(location, MODIFY_EXPR, return this->make_statement(fold_build2_loc(location, MODIFY_EXPR,
void_type_node, void_type_node,
lhs->get_tree(), lhs_tree, rhs_tree));
rhs->get_tree())); }
// Return.
Bstatement*
Gcc_backend::return_statement(Bfunction* bfunction,
const std::vector<Bexpression*>& vals,
source_location location)
{
tree fntree = bfunction->get_tree();
if (fntree == error_mark_node)
return this->make_statement(error_mark_node);
tree result = DECL_RESULT(fntree);
if (result == error_mark_node)
return this->make_statement(error_mark_node);
tree ret;
if (vals.empty())
ret = fold_build1_loc(location, RETURN_EXPR, void_type_node, NULL_TREE);
else if (vals.size() == 1)
{
tree val = vals.front()->get_tree();
if (val == error_mark_node)
return this->make_statement(error_mark_node);
tree set = fold_build2_loc(location, MODIFY_EXPR, void_type_node,
result, vals.front()->get_tree());
ret = fold_build1_loc(location, RETURN_EXPR, void_type_node, set);
}
else
{
// To return multiple values, copy the values into a temporary
// variable of the right structure type, and then assign the
// temporary variable to the DECL_RESULT in the return
// statement.
tree stmt_list = NULL_TREE;
tree rettype = TREE_TYPE(result);
tree rettmp = create_tmp_var(rettype, "RESULT");
tree field = TYPE_FIELDS(rettype);
for (std::vector<Bexpression*>::const_iterator p = vals.begin();
p != vals.end();
p++, field = DECL_CHAIN(field))
{
gcc_assert(field != NULL_TREE);
tree ref = fold_build3_loc(location, COMPONENT_REF, TREE_TYPE(field),
rettmp, field, NULL_TREE);
tree val = (*p)->get_tree();
if (val == error_mark_node)
return this->make_statement(error_mark_node);
tree set = fold_build2_loc(location, MODIFY_EXPR, void_type_node,
ref, (*p)->get_tree());
append_to_statement_list(set, &stmt_list);
}
gcc_assert(field == NULL_TREE);
tree set = fold_build2_loc(location, MODIFY_EXPR, void_type_node,
result, rettmp);
tree ret_expr = fold_build1_loc(location, RETURN_EXPR, void_type_node,
set);
append_to_statement_list(ret_expr, &stmt_list);
ret = stmt_list;
}
return this->make_statement(ret);
} }
// The single backend. // The single backend.
...@@ -192,6 +270,12 @@ tree_to_expr(tree t) ...@@ -192,6 +270,12 @@ tree_to_expr(tree t)
return new Bexpression(t); return new Bexpression(t);
} }
Bfunction*
tree_to_function(tree t)
{
return new Bfunction(t);
}
tree tree
statement_to_tree(Bstatement* bs) statement_to_tree(Bstatement* bs)
{ {
......
...@@ -24,6 +24,9 @@ class Bexpression; ...@@ -24,6 +24,9 @@ class Bexpression;
// The backend representation of a statement. // The backend representation of a statement.
class Bstatement; class Bstatement;
// The backend representation of a function definition.
class Bfunction;
// A list of backend types. // A list of backend types.
typedef std::vector<Btype*> Btypes; typedef std::vector<Btype*> Btypes;
...@@ -103,7 +106,14 @@ class Backend ...@@ -103,7 +106,14 @@ class Backend
// Create an assignment statement. // Create an assignment statement.
virtual Bstatement* virtual Bstatement*
assignment(Bexpression* lhs, Bexpression* rhs, source_location location) = 0; assignment_statement(Bexpression* lhs, Bexpression* rhs,
source_location) = 0;
// Create a return statement, passing the representation of the
// function and the list of values to return.
virtual Bstatement*
return_statement(Bfunction*, const std::vector<Bexpression*>&,
source_location) = 0;
}; };
// The backend interface has to define this function. // The backend interface has to define this function.
...@@ -114,6 +124,7 @@ extern Backend* go_get_backend(); ...@@ -114,6 +124,7 @@ extern Backend* go_get_backend();
// interface. // interface.
extern Bexpression* tree_to_expr(tree); extern Bexpression* tree_to_expr(tree);
extern Bfunction* tree_to_function(tree);
extern tree statement_to_tree(Bstatement*); extern tree statement_to_tree(Bstatement*);
#endif // !defined(GO_BACKEND_H) #endif // !defined(GO_BACKEND_H)
...@@ -10415,8 +10415,7 @@ Selector_expression::lower_method_expression(Gogo* gogo) ...@@ -10415,8 +10415,7 @@ Selector_expression::lower_method_expression(Gogo* gogo)
for (size_t i = 0; i < count; ++i) for (size_t i = 0; i < count; ++i)
retvals->push_back(Expression::make_call_result(call, i)); retvals->push_back(Expression::make_call_result(call, i));
} }
s = Statement::make_return_statement(no->func_value()->type()->results(), s = Statement::make_return_statement(retvals, location);
retvals, location);
} }
gogo->add_statement(s); gogo->add_statement(s);
......
...@@ -1761,27 +1761,16 @@ Function::return_value(Gogo* gogo, Named_object* named_function, ...@@ -1761,27 +1761,16 @@ Function::return_value(Gogo* gogo, Named_object* named_function,
if (results == NULL || results->empty()) if (results == NULL || results->empty())
return NULL_TREE; return NULL_TREE;
// In the case of an exception handler created for functions with gcc_assert(this->results_ != NULL);
// defer statements, the result variables may be unnamed. if (this->results_->size() != results->size())
bool is_named = !results->front().name().empty();
if (is_named)
{ {
gcc_assert(this->named_results_ != NULL); gcc_assert(saw_errors());
if (this->named_results_->size() != results->size()) return error_mark_node;
{
gcc_assert(saw_errors());
return error_mark_node;
}
} }
tree retval; tree retval;
if (results->size() == 1) if (results->size() == 1)
{ return this->results_->front()->get_tree(gogo, named_function);
if (is_named)
return this->named_results_->front()->get_tree(gogo, named_function);
else
return results->front().type()->get_init_tree(gogo, false);
}
else else
{ {
tree rettype = TREE_TYPE(DECL_RESULT(this->fndecl_)); tree rettype = TREE_TYPE(DECL_RESULT(this->fndecl_));
...@@ -1794,11 +1783,7 @@ Function::return_value(Gogo* gogo, Named_object* named_function, ...@@ -1794,11 +1783,7 @@ Function::return_value(Gogo* gogo, Named_object* named_function,
{ {
gcc_assert(field != NULL); gcc_assert(field != NULL);
tree val; tree val;
if (is_named) val = (*this->results_)[index]->get_tree(gogo, named_function);
val = (*this->named_results_)[index]->get_tree(gogo,
named_function);
else
val = pr->type()->get_init_tree(gogo, false);
tree set = fold_build2_loc(location, MODIFY_EXPR, void_type_node, tree set = fold_build2_loc(location, MODIFY_EXPR, void_type_node,
build3(COMPONENT_REF, TREE_TYPE(field), build3(COMPONENT_REF, TREE_TYPE(field),
retval, field, NULL_TREE), retval, field, NULL_TREE),
......
...@@ -642,7 +642,7 @@ Gogo::start_function(const std::string& name, Function_type* type, ...@@ -642,7 +642,7 @@ Gogo::start_function(const std::string& name, Function_type* type,
} }
} }
function->create_named_result_variables(this); function->create_result_variables(this);
const std::string* pname; const std::string* pname;
std::string nested_name; std::string nested_name;
...@@ -2195,8 +2195,7 @@ Build_recover_thunks::function(Named_object* orig_no) ...@@ -2195,8 +2195,7 @@ Build_recover_thunks::function(Named_object* orig_no)
for (size_t i = 0; i < rc; ++i) for (size_t i = 0; i < rc; ++i)
vals->push_back(Expression::make_call_result(call, i)); vals->push_back(Expression::make_call_result(call, i));
} }
s = Statement::make_return_statement(new_func->type()->results(), s = Statement::make_return_statement(vals, location);
vals, location);
} }
s->determine_types(); s->determine_types();
gogo->add_statement(s); gogo->add_statement(s);
...@@ -2252,8 +2251,8 @@ Build_recover_thunks::function(Named_object* orig_no) ...@@ -2252,8 +2251,8 @@ Build_recover_thunks::function(Named_object* orig_no)
new_func->traverse(&convert_recover); new_func->traverse(&convert_recover);
// Update the function pointers in any named results. // Update the function pointers in any named results.
new_func->update_named_result_variables(); new_func->update_result_variables();
orig_func->update_named_result_variables(); orig_func->update_result_variables();
return TRAVERSE_CONTINUE; return TRAVERSE_CONTINUE;
} }
...@@ -2619,26 +2618,27 @@ Gogo::convert_named_types_in_bindings(Bindings* bindings) ...@@ -2619,26 +2618,27 @@ Gogo::convert_named_types_in_bindings(Bindings* bindings)
Function::Function(Function_type* type, Function* enclosing, Block* block, Function::Function(Function_type* type, Function* enclosing, Block* block,
source_location location) source_location location)
: type_(type), enclosing_(enclosing), named_results_(NULL), : type_(type), enclosing_(enclosing), results_(NULL),
closure_var_(NULL), block_(block), location_(location), fndecl_(NULL), closure_var_(NULL), block_(block), location_(location), fndecl_(NULL),
defer_stack_(NULL), calls_recover_(false), is_recover_thunk_(false), defer_stack_(NULL), results_are_named_(false), calls_recover_(false),
has_recover_thunk_(false) is_recover_thunk_(false), has_recover_thunk_(false)
{ {
} }
// Create the named result variables. // Create the named result variables.
void void
Function::create_named_result_variables(Gogo* gogo) Function::create_result_variables(Gogo* gogo)
{ {
const Typed_identifier_list* results = this->type_->results(); const Typed_identifier_list* results = this->type_->results();
if (results == NULL if (results == NULL || results->empty())
|| results->empty()
|| results->front().name().empty())
return; return;
this->named_results_ = new Named_results(); if (!results->front().name().empty())
this->named_results_->reserve(results->size()); this->results_are_named_ = true;
this->results_ = new Results();
this->results_->reserve(results->size());
Block* block = this->block_; Block* block = this->block_;
int index = 0; int index = 0;
...@@ -2647,18 +2647,29 @@ Function::create_named_result_variables(Gogo* gogo) ...@@ -2647,18 +2647,29 @@ Function::create_named_result_variables(Gogo* gogo)
++p, ++index) ++p, ++index)
{ {
std::string name = p->name(); std::string name = p->name();
if (Gogo::is_sink_name(name)) if (name.empty() || Gogo::is_sink_name(name))
{ {
static int unnamed_result_counter; static int result_counter;
char buf[100]; char buf[100];
snprintf(buf, sizeof buf, "_$%d", unnamed_result_counter); snprintf(buf, sizeof buf, "$ret%d", result_counter);
++unnamed_result_counter; ++result_counter;
name = gogo->pack_hidden_name(buf, false); name = gogo->pack_hidden_name(buf, false);
} }
Result_variable* result = new Result_variable(p->type(), this, index); Result_variable* result = new Result_variable(p->type(), this, index);
Named_object* no = block->bindings()->add_result_variable(name, result); Named_object* no = block->bindings()->add_result_variable(name, result);
if (no->is_result_variable()) if (no->is_result_variable())
this->named_results_->push_back(no); this->results_->push_back(no);
else
{
static int dummy_result_count;
char buf[100];
snprintf(buf, sizeof buf, "$dret%d", dummy_result_count);
++dummy_result_count;
name = gogo->pack_hidden_name(buf, false);
no = block->bindings()->add_result_variable(name, result);
gcc_assert(no->is_result_variable());
this->results_->push_back(no);
}
} }
} }
...@@ -2666,13 +2677,13 @@ Function::create_named_result_variables(Gogo* gogo) ...@@ -2666,13 +2677,13 @@ Function::create_named_result_variables(Gogo* gogo)
// calls recover. // calls recover.
void void
Function::update_named_result_variables() Function::update_result_variables()
{ {
if (this->named_results_ == NULL) if (this->results_ == NULL)
return; return;
for (Named_results::iterator p = this->named_results_->begin(); for (Results::iterator p = this->results_->begin();
p != this->named_results_->end(); p != this->results_->end();
++p) ++p)
(*p)->result_var_value()->set_function(this); (*p)->result_var_value()->set_function(this);
} }
...@@ -2819,7 +2830,7 @@ void ...@@ -2819,7 +2830,7 @@ void
Function::swap_for_recover(Function *x) Function::swap_for_recover(Function *x)
{ {
gcc_assert(this->enclosing_ == x->enclosing_); gcc_assert(this->enclosing_ == x->enclosing_);
std::swap(this->named_results_, x->named_results_); std::swap(this->results_, x->results_);
std::swap(this->closure_var_, x->closure_var_); std::swap(this->closure_var_, x->closure_var_);
std::swap(this->block_, x->block_); std::swap(this->block_, x->block_);
gcc_assert(this->location_ == x->location_); gcc_assert(this->location_ == x->location_);
......
...@@ -822,14 +822,27 @@ class Function ...@@ -822,14 +822,27 @@ class Function
this->enclosing_ = enclosing; this->enclosing_ = enclosing;
} }
// Create the named result variables in the outer block. // The result variables.
typedef std::vector<Named_object*> Results;
// Create the result variables in the outer block.
void void
create_named_result_variables(Gogo*); create_result_variables(Gogo*);
// Update the named result variables when cloning a function which // Update the named result variables when cloning a function which
// calls recover. // calls recover.
void void
update_named_result_variables(); update_result_variables();
// Return the result variables.
Results*
result_variables()
{ return this->results_; }
// Whether the result variables have names.
bool
results_are_named() const
{ return this->results_are_named_; }
// Add a new field to the closure variable. // Add a new field to the closure variable.
void void
...@@ -992,8 +1005,6 @@ class Function ...@@ -992,8 +1005,6 @@ class Function
void void
build_defer_wrapper(Gogo*, Named_object*, tree*, tree*); build_defer_wrapper(Gogo*, Named_object*, tree*, tree*);
typedef std::vector<Named_object*> Named_results;
typedef std::vector<std::pair<Named_object*, typedef std::vector<std::pair<Named_object*,
source_location> > Closure_fields; source_location> > Closure_fields;
...@@ -1002,8 +1013,8 @@ class Function ...@@ -1002,8 +1013,8 @@ class Function
// The enclosing function. This is NULL when there isn't one, which // The enclosing function. This is NULL when there isn't one, which
// is the normal case. // is the normal case.
Function* enclosing_; Function* enclosing_;
// The named result variables, if any. // The result variables, if any.
Named_results* named_results_; Results* results_;
// If there is a closure, this is the list of variables which appear // If there is a closure, this is the list of variables which appear
// in the closure. This is created by the parser, and then resolved // in the closure. This is created by the parser, and then resolved
// to a real type when we lower parse trees. // to a real type when we lower parse trees.
...@@ -1022,6 +1033,8 @@ class Function ...@@ -1022,6 +1033,8 @@ class Function
// A variable holding the defer stack variable. This is NULL unless // A variable holding the defer stack variable. This is NULL unless
// we actually need a defer stack. // we actually need a defer stack.
tree defer_stack_; tree defer_stack_;
// True if the result variables are named.
bool results_are_named_;
// True if this function calls the predeclared recover function. // True if this function calls the predeclared recover function.
bool calls_recover_; bool calls_recover_;
// True if this a thunk built for a function which calls recover. // True if this a thunk built for a function which calls recover.
......
...@@ -3732,10 +3732,7 @@ Parse::return_stat() ...@@ -3732,10 +3732,7 @@ Parse::return_stat()
Expression_list* vals = NULL; Expression_list* vals = NULL;
if (this->expression_may_start_here()) if (this->expression_may_start_here())
vals = this->expression_list(NULL, false); vals = this->expression_list(NULL, false);
const Function* function = this->gogo_->current_function()->func_value(); this->gogo_->add_statement(Statement::make_return_statement(vals, location));
const Typed_identifier_list* results = function->type()->results();
this->gogo_->add_statement(Statement::make_return_statement(results, vals,
location));
} }
// IfStmt = "if" [ SimpleStmt ";" ] Expression Block [ "else" Statement ] . // IfStmt = "if" [ SimpleStmt ";" ] Expression Block [ "else" Statement ] .
......
...@@ -200,8 +200,7 @@ class Statement ...@@ -200,8 +200,7 @@ class Statement
// Make a return statement. // Make a return statement.
static Statement* static Statement*
make_return_statement(const Typed_identifier_list*, Expression_list*, make_return_statement(Expression_list*, source_location);
source_location);
// Make a break statement. // Make a break statement.
static Statement* static Statement*
...@@ -556,10 +555,9 @@ class Variable_declaration_statement : public Statement ...@@ -556,10 +555,9 @@ class Variable_declaration_statement : public Statement
class Return_statement : public Statement class Return_statement : public Statement
{ {
public: public:
Return_statement(const Typed_identifier_list* results, Expression_list* vals, Return_statement(Expression_list* vals, source_location location)
source_location location)
: Statement(STATEMENT_RETURN, location), : Statement(STATEMENT_RETURN, location),
results_(results), vals_(vals) vals_(vals), is_lowered_(false)
{ } { }
// The list of values being returned. This may be NULL. // The list of values being returned. This may be NULL.
...@@ -578,12 +576,6 @@ class Return_statement : public Statement ...@@ -578,12 +576,6 @@ class Return_statement : public Statement
Statement* Statement*
do_lower(Gogo*, Named_object*, Block*); do_lower(Gogo*, Named_object*, Block*);
void
do_determine_types();
void
do_check_types(Gogo*);
bool bool
do_may_fall_through() const do_may_fall_through() const
{ return false; } { return false; }
...@@ -592,12 +584,10 @@ class Return_statement : public Statement ...@@ -592,12 +584,10 @@ class Return_statement : public Statement
do_get_tree(Translate_context*); do_get_tree(Translate_context*);
private: private:
// The result types of the function we are returning from. This is
// here because in some of the traversals it is inconvenient to get
// it.
const Typed_identifier_list* results_;
// Return values. This may be NULL. // Return values. This may be NULL.
Expression_list* vals_; Expression_list* vals_;
// True if this statement has been lowered.
bool is_lowered_;
}; };
// A send statement. // A send statement.
......
...@@ -7924,10 +7924,7 @@ Type::build_one_stub_method(Gogo* gogo, Method* method, ...@@ -7924,10 +7924,7 @@ Type::build_one_stub_method(Gogo* gogo, Method* method,
for (size_t i = 0; i < count; ++i) for (size_t i = 0; i < count; ++i)
retvals->push_back(Expression::make_call_result(call, i)); retvals->push_back(Expression::make_call_result(call, i));
} }
const Function* function = gogo->current_function()->func_value(); Statement* retstat = Statement::make_return_statement(retvals, location);
const Typed_identifier_list* results = function->type()->results();
Statement* retstat = Statement::make_return_statement(results, retvals,
location);
gogo->add_statement(retstat); gogo->add_statement(retstat);
} }
} }
......
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