aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@google.com>2011-04-13 23:21:21 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2011-04-13 23:21:21 +0000
commit8dc421e03520f7b1d2ccd73648985c83998604bc (patch)
tree12891b40b73b55524a731253846a51b5cd780fff /gcc
parent123c516a9ee069efe6783682ff0bfbf28ec94919 (diff)
downloadgcc-8dc421e03520f7b1d2ccd73648985c83998604bc.zip
gcc-8dc421e03520f7b1d2ccd73648985c83998604bc.tar.gz
gcc-8dc421e03520f7b1d2ccd73648985c83998604bc.tar.bz2
Use backend interface for go and defer statements.
Change defer stack from tree to Expression. From-SVN: r172402
Diffstat (limited to 'gcc')
-rw-r--r--gcc/go/ChangeLog4
-rw-r--r--gcc/go/Make-lang.in2
-rw-r--r--gcc/go/gofrontend/gogo-tree.cc85
-rw-r--r--gcc/go/gofrontend/gogo.cc23
-rw-r--r--gcc/go/gofrontend/gogo.h10
-rw-r--r--gcc/go/gofrontend/statements.cc133
-rw-r--r--gcc/go/gofrontend/statements.h6
7 files changed, 133 insertions, 130 deletions
diff --git a/gcc/go/ChangeLog b/gcc/go/ChangeLog
index 79f9a11..002c9e3 100644
--- a/gcc/go/ChangeLog
+++ b/gcc/go/ChangeLog
@@ -1,5 +1,9 @@
2011-04-13 Ian Lance Taylor <iant@google.com>
+ * Make-lang.in (go/gogo-tree.o): depend on $(GO_RUNTIME_H).
+
+2011-04-13 Ian Lance Taylor <iant@google.com>
+
* Make-lang.in (GO_OBJS): Add go/runtime.o.
(GO_RUNTIME_H): New variable.
(go/runtime.o): New target.
diff --git a/gcc/go/Make-lang.in b/gcc/go/Make-lang.in
index c5289c6..c20cebd 100644
--- a/gcc/go/Make-lang.in
+++ b/gcc/go/Make-lang.in
@@ -262,7 +262,7 @@ go/go-dump.o: go/gofrontend/go-dump.cc $(GO_SYSTEM_H) $(GO_C_H) \
go/gogo-tree.o: go/gofrontend/gogo-tree.cc $(GO_SYSTEM_H) $(TOPLEV_H) \
$(TREE_H) $(GIMPLE_H) tree-iterator.h $(CGRAPH_H) langhooks.h \
convert.h output.h $(DIAGNOSTIC_H) $(GO_TYPES_H) \
- $(GO_EXPRESSIONS_H) $(GO_STATEMENTS_H) $(GO_GOGO_H)
+ $(GO_EXPRESSIONS_H) $(GO_STATEMENTS_H) $(GO_RUNTIME_H) $(GO_GOGO_H)
go/gogo.o: go/gofrontend/gogo.cc $(GO_SYSTEM_H) $(GO_C_H) \
go/gofrontend/go-dump.h $(GO_LEX_H) $(GO_TYPES_H) $(GO_STATEMENTS_H) \
$(GO_EXPRESSIONS_H) go/gofrontend/dataflow.h $(GO_RUNTIME_H) \
diff --git a/gcc/go/gofrontend/gogo-tree.cc b/gcc/go/gofrontend/gogo-tree.cc
index a8a5b4c..1cf36dd 100644
--- a/gcc/go/gofrontend/gogo-tree.cc
+++ b/gcc/go/gofrontend/gogo-tree.cc
@@ -31,6 +31,7 @@ extern "C"
#include "types.h"
#include "expressions.h"
#include "statements.h"
+#include "runtime.h"
#include "gogo.h"
// Whether we have seen any errors.
@@ -1585,13 +1586,22 @@ Function::build_tree(Gogo* gogo, Named_object* named_function)
// Declare variables if necessary.
tree bind = NULL_TREE;
- if (declare_vars != NULL_TREE)
+ tree defer_init = NULL_TREE;
+ if (declare_vars != NULL_TREE || this->defer_stack_ != NULL)
{
tree block = make_node(BLOCK);
BLOCK_SUPERCONTEXT(block) = fndecl;
DECL_INITIAL(fndecl) = block;
BLOCK_VARS(block) = declare_vars;
TREE_USED(block) = 1;
+
+ if (this->defer_stack_ != NULL)
+ {
+ Translate_context dcontext(gogo, named_function, this->block_,
+ block);
+ defer_init = this->defer_stack_->get_tree(&dcontext);
+ }
+
bind = build3(BIND_EXPR, void_type_node, BLOCK_VARS(block),
NULL_TREE, block);
TREE_SIDE_EFFECTS(bind) = 1;
@@ -1615,10 +1625,8 @@ Function::build_tree(Gogo* gogo, Named_object* named_function)
// If we have a defer stack, initialize it at the start of a
// function.
- if (this->defer_stack_ != NULL_TREE)
+ if (defer_init != NULL_TREE && defer_init != error_mark_node)
{
- tree defer_init = build1(DECL_EXPR, void_type_node,
- this->defer_stack_);
SET_EXPR_LOCATION(defer_init, this->block_->start_location());
append_to_statement_list(defer_init, &init);
@@ -1663,17 +1671,15 @@ Function::build_defer_wrapper(Gogo* gogo, Named_object* named_function,
// purpose is to stop the stack unwinding if a deferred function
// calls recover. There are more details in
// libgo/runtime/go-unwind.c.
+
tree stmt_list = NULL_TREE;
- static tree check_fndecl;
- tree call = Gogo::call_builtin(&check_fndecl,
- end_loc,
- "__go_check_defer",
- 1,
- void_type_node,
- ptr_type_node,
- this->defer_stack(end_loc));
- if (call != error_mark_node)
- append_to_statement_list(call, &stmt_list);
+
+ Expression* call = Runtime::make_call(Runtime::CHECK_DEFER, end_loc, 1,
+ this->defer_stack(end_loc));
+ Translate_context context(gogo, named_function, NULL, NULL);
+ tree call_tree = call->get_tree(&context);
+ if (call_tree != error_mark_node)
+ append_to_statement_list(call_tree, &stmt_list);
tree retval = this->return_value(gogo, named_function, end_loc, &stmt_list);
tree set;
@@ -1704,24 +1710,17 @@ Function::build_defer_wrapper(Gogo* gogo, Named_object* named_function,
label);
append_to_statement_list(define_label, &stmt_list);
- static tree undefer_fndecl;
- tree undefer = Gogo::call_builtin(&undefer_fndecl,
- end_loc,
- "__go_undefer",
- 1,
- void_type_node,
- ptr_type_node,
- this->defer_stack(end_loc));
- if (undefer_fndecl != NULL_TREE)
- TREE_NOTHROW(undefer_fndecl) = 0;
-
- tree defer = Gogo::call_builtin(&check_fndecl,
- end_loc,
- "__go_check_defer",
- 1,
- void_type_node,
- ptr_type_node,
- this->defer_stack(end_loc));
+ call = Runtime::make_call(Runtime::UNDEFER, end_loc, 1,
+ this->defer_stack(end_loc));
+ tree undefer = call->get_tree(&context);
+
+ call = Runtime::make_call(Runtime::CHECK_DEFER, end_loc, 1,
+ this->defer_stack(end_loc));
+ tree defer = call->get_tree(&context);
+
+ if (undefer == error_mark_node || defer == error_mark_node)
+ return;
+
tree jump = fold_build1_loc(end_loc, GOTO_EXPR, void_type_node, label);
tree catch_body = build2(COMPOUND_EXPR, void_type_node, defer, jump);
catch_body = build2(CATCH_EXPR, void_type_node, NULL, catch_body);
@@ -1794,28 +1793,6 @@ Function::return_value(Gogo* gogo, Named_object* named_function,
}
}
-// Get the tree for the variable holding the defer stack for this
-// function. At least at present, the value of this variable is not
-// used. However, a pointer to this variable is used as a marker for
-// the functions on the defer stack associated with this function.
-// Doing things this way permits inlining a function which uses defer.
-
-tree
-Function::defer_stack(source_location location)
-{
- if (this->defer_stack_ == NULL_TREE)
- {
- tree var = create_tmp_var(ptr_type_node, "DEFER");
- DECL_INITIAL(var) = null_pointer_node;
- DECL_SOURCE_LOCATION(var) = location;
- TREE_ADDRESSABLE(var) = 1;
- this->defer_stack_ = var;
- }
- return fold_convert_loc(location, ptr_type_node,
- build_fold_addr_expr_loc(location,
- this->defer_stack_));
-}
-
// Get a tree for the statements in a block.
tree
diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc
index e22de4b..91a7526 100644
--- a/gcc/go/gofrontend/gogo.cc
+++ b/gcc/go/gofrontend/gogo.cc
@@ -2884,6 +2884,29 @@ Function::determine_types()
this->block_->determine_types();
}
+// Get a pointer to the variable holding the defer stack for this
+// function, making it if necessary. At least at present, the value
+// of this variable is not used. However, a pointer to this variable
+// is used as a marker for the functions on the defer stack associated
+// with this function. Doing things this way permits inlining a
+// function which uses defer.
+
+Expression*
+Function::defer_stack(source_location location)
+{
+ Type* t = Type::make_pointer_type(Type::make_void_type());
+ if (this->defer_stack_ == NULL)
+ {
+ Expression* n = Expression::make_nil(location);
+ this->defer_stack_ = Statement::make_temporary(t, n, location);
+ this->defer_stack_->set_is_address_taken();
+ }
+ Expression* ref = Expression::make_temporary_reference(this->defer_stack_,
+ location);
+ Expression* addr = Expression::make_unary(OPERATOR_AND, ref, location);
+ return Expression::make_unsafe_cast(t, addr, location);
+}
+
// Export the function.
void
diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h
index cf126cd..f958b9c 100644
--- a/gcc/go/gofrontend/gogo.h
+++ b/gcc/go/gofrontend/gogo.h
@@ -17,6 +17,7 @@ class Typed_identifier_list;
class Function_type;
class Expression;
class Statement;
+class Temporary_statement;
class Block;
class Function;
class Bindings;
@@ -977,7 +978,7 @@ class Function
return_value(Gogo*, Named_object*, source_location, tree* stmt_list) const;
// Get a tree for the variable holding the defer stack.
- tree
+ Expression*
defer_stack(source_location);
// Export the function.
@@ -1033,9 +1034,10 @@ class Function
Labels labels_;
// The function decl.
tree fndecl_;
- // A variable holding the defer stack variable. This is NULL unless
- // we actually need a defer stack.
- tree defer_stack_;
+ // 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.
+ Temporary_statement* defer_stack_;
// True if the result variables are named.
bool results_are_named_;
// True if this function calls the predeclared recover function.
diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc
index 0b22e30..6ca8bf5 100644
--- a/gcc/go/gofrontend/statements.cc
+++ b/gcc/go/gofrontend/statements.cc
@@ -1718,17 +1718,39 @@ class Simplify_thunk_traverse : public Traverse
{
public:
Simplify_thunk_traverse(Gogo* gogo)
- : Traverse(traverse_blocks),
- gogo_(gogo)
+ : Traverse(traverse_functions | traverse_blocks),
+ gogo_(gogo), function_(NULL)
{ }
int
+ function(Named_object*);
+
+ int
block(Block*);
private:
+ // General IR.
Gogo* gogo_;
+ // The function we are traversing.
+ Named_object* function_;
};
+// Keep track of the current function while looking for thunks.
+
+int
+Simplify_thunk_traverse::function(Named_object* no)
+{
+ gcc_assert(this->function_ == NULL);
+ this->function_ = no;
+ int t = no->func_value()->traverse(this);
+ this->function_ = NULL;
+ if (t == TRAVERSE_EXIT)
+ return t;
+ return TRAVERSE_SKIP_COMPONENTS;
+}
+
+// Look for thunks in a block.
+
int
Simplify_thunk_traverse::block(Block* b)
{
@@ -1739,7 +1761,7 @@ Simplify_thunk_traverse::block(Block* b)
Thunk_statement* stat = b->statements()->back()->thunk_statement();
if (stat == NULL)
return TRAVERSE_CONTINUE;
- if (stat->simplify_statement(this->gogo_, b))
+ if (stat->simplify_statement(this->gogo_, this->function_, b))
return TRAVERSE_SKIP_COMPONENTS;
return TRAVERSE_CONTINUE;
}
@@ -1761,13 +1783,23 @@ Gogo::simplify_thunk_statements()
// struct to a thunk. The thunk does the real call.
bool
-Thunk_statement::simplify_statement(Gogo* gogo, Block* block)
+Thunk_statement::simplify_statement(Gogo* gogo, Named_object* function,
+ Block* block)
{
if (this->classification() == STATEMENT_ERROR)
return false;
if (this->call_->is_error_expression())
return false;
+ if (this->classification() == STATEMENT_DEFER)
+ {
+ // Make sure that the defer stack exists for the function. We
+ // will use when converting this statement to the backend
+ // representation, but we want it to exist when we start
+ // converting the function.
+ function->func_value()->defer_stack(this->location());
+ }
+
Call_expression* ce = this->call_->call_expression();
Function_type* fntype = ce->get_function_type();
if (fntype == NULL)
@@ -2160,30 +2192,26 @@ Thunk_statement::build_thunk(Gogo* gogo, const std::string& thunk_name,
// Get the function and argument trees.
-void
-Thunk_statement::get_fn_and_arg(Translate_context* context, tree* pfn,
- tree* parg)
+bool
+Thunk_statement::get_fn_and_arg(Expression** pfn, Expression** parg)
{
if (this->call_->is_error_expression())
- {
- *pfn = error_mark_node;
- *parg = error_mark_node;
- return;
- }
+ return false;
Call_expression* ce = this->call_->call_expression();
- Expression* fn = ce->fn();
- *pfn = fn->get_tree(context);
+ *pfn = ce->fn();
const Expression_list* args = ce->args();
if (args == NULL || args->empty())
- *parg = null_pointer_node;
+ *parg = Expression::make_nil(this->location());
else
{
gcc_assert(args->size() == 1);
- *parg = args->front()->get_tree(context);
+ *parg = args->front();
}
+
+ return true;
}
// Class Go_statement.
@@ -2191,30 +2219,17 @@ Thunk_statement::get_fn_and_arg(Translate_context* context, tree* pfn,
tree
Go_statement::do_get_tree(Translate_context* context)
{
- tree fn_tree;
- tree arg_tree;
- this->get_fn_and_arg(context, &fn_tree, &arg_tree);
-
- static tree go_fndecl;
-
- tree fn_arg_type = NULL_TREE;
- if (go_fndecl == NULL_TREE)
- {
- // Only build FN_ARG_TYPE if we need it.
- tree subargtypes = tree_cons(NULL_TREE, ptr_type_node, void_list_node);
- tree subfntype = build_function_type(ptr_type_node, subargtypes);
- fn_arg_type = build_pointer_type(subfntype);
- }
+ Expression* fn;
+ Expression* arg;
+ if (!this->get_fn_and_arg(&fn, &arg))
+ return error_mark_node;
- return Gogo::call_builtin(&go_fndecl,
- this->location(),
- "__go_go",
- 2,
- void_type_node,
- fn_arg_type,
- fn_tree,
- ptr_type_node,
- arg_tree);
+ Expression* call = Runtime::make_call(Runtime::GO, this->location(), 2,
+ fn, arg);
+ tree call_tree = call->get_tree(context);
+ Bexpression* call_bexpr = tree_to_expr(call_tree);
+ Bstatement* ret = context->backend()->expression_statement(call_bexpr);
+ return stat_to_tree(ret);
}
// Make a go statement.
@@ -2230,38 +2245,20 @@ Statement::make_go_statement(Call_expression* call, source_location location)
tree
Defer_statement::do_get_tree(Translate_context* context)
{
- source_location loc = this->location();
-
- tree fn_tree;
- tree arg_tree;
- this->get_fn_and_arg(context, &fn_tree, &arg_tree);
- if (fn_tree == error_mark_node || arg_tree == error_mark_node)
+ Expression* fn;
+ Expression* arg;
+ if (!this->get_fn_and_arg(&fn, &arg))
return error_mark_node;
- static tree defer_fndecl;
-
- tree fn_arg_type = NULL_TREE;
- if (defer_fndecl == NULL_TREE)
- {
- // Only build FN_ARG_TYPE if we need it.
- tree subargtypes = tree_cons(NULL_TREE, ptr_type_node, void_list_node);
- tree subfntype = build_function_type(ptr_type_node, subargtypes);
- fn_arg_type = build_pointer_type(subfntype);
- }
+ source_location loc = this->location();
+ Expression* ds = context->function()->func_value()->defer_stack(loc);
- tree defer_stack = context->function()->func_value()->defer_stack(loc);
-
- return Gogo::call_builtin(&defer_fndecl,
- loc,
- "__go_defer",
- 3,
- void_type_node,
- ptr_type_node,
- defer_stack,
- fn_arg_type,
- fn_tree,
- ptr_type_node,
- arg_tree);
+ Expression* call = Runtime::make_call(Runtime::DEFER, loc, 3,
+ ds, fn, arg);
+ tree call_tree = call->get_tree(context);
+ Bexpression* call_bexpr = tree_to_expr(call_tree);
+ Bstatement* ret = context->backend()->expression_statement(call_bexpr);
+ return stat_to_tree(ret);
}
// Make a defer statement.
diff --git a/gcc/go/gofrontend/statements.h b/gcc/go/gofrontend/statements.h
index 826cd0c..2436bb5 100644
--- a/gcc/go/gofrontend/statements.h
+++ b/gcc/go/gofrontend/statements.h
@@ -852,7 +852,7 @@ class Thunk_statement : public Statement
// Simplify a go or defer statement so that it only uses a single
// parameter.
bool
- simplify_statement(Gogo*, Block*);
+ simplify_statement(Gogo*, Named_object*, Block*);
protected:
int
@@ -868,8 +868,8 @@ class Thunk_statement : public Statement
do_check_types(Gogo*);
// Return the function and argument trees for the call.
- void
- get_fn_and_arg(Translate_context*, tree* pfn, tree* parg);
+ bool
+ get_fn_and_arg(Expression** pfn, Expression** parg);
private:
// Return whether this is a simple go statement.