diff options
author | Ian Lance Taylor <iant@google.com> | 2011-04-13 23:21:21 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2011-04-13 23:21:21 +0000 |
commit | 8dc421e03520f7b1d2ccd73648985c83998604bc (patch) | |
tree | 12891b40b73b55524a731253846a51b5cd780fff /gcc | |
parent | 123c516a9ee069efe6783682ff0bfbf28ec94919 (diff) | |
download | gcc-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/ChangeLog | 4 | ||||
-rw-r--r-- | gcc/go/Make-lang.in | 2 | ||||
-rw-r--r-- | gcc/go/gofrontend/gogo-tree.cc | 85 | ||||
-rw-r--r-- | gcc/go/gofrontend/gogo.cc | 23 | ||||
-rw-r--r-- | gcc/go/gofrontend/gogo.h | 10 | ||||
-rw-r--r-- | gcc/go/gofrontend/statements.cc | 133 | ||||
-rw-r--r-- | gcc/go/gofrontend/statements.h | 6 |
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. |