Use backend interface for go and defer statements.
authorIan Lance Taylor <iant@google.com>
Wed, 13 Apr 2011 23:21:21 +0000 (23:21 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Wed, 13 Apr 2011 23:21:21 +0000 (23:21 +0000)
Change defer stack from tree to Expression.

From-SVN: r172402

gcc/go/ChangeLog
gcc/go/Make-lang.in
gcc/go/gofrontend/gogo-tree.cc
gcc/go/gofrontend/gogo.cc
gcc/go/gofrontend/gogo.h
gcc/go/gofrontend/statements.cc
gcc/go/gofrontend/statements.h

index 79f9a111aabf09f945bc087a7dd0f3e9ef305e8c..002c9e36c0e15d9085e2ec1229d3646b5542702c 100644 (file)
@@ -1,3 +1,7 @@
+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.
index c5289c67884b759f5a58ee5113c52c82adba9a2f..c20cebdec4ebd9f19beed01a233010d55ee942b8 100644 (file)
@@ -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) \
index a8a5b4c978fbd1f31e31d8334e9360b8cea35075..1cf36dd731eebd25d3735ac0df15dd59165ce06e 100644 (file)
@@ -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
index e22de4be4461dfc81b4b622c4fd95f1318b97236..91a7526aecef8741a08bdf4d243232482792655b 100644 (file)
@@ -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
index cf126cdc282b43027f4bb677f362aaf3f9de01e5..f958b9c58ccc493703d491e0c2b5bd4a638b9aa1 100644 (file)
@@ -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.
index 0b22e307306c3966383ca0f59e1523361fd87aff..6ca8bf54a369a24429ee1d0f9fa71c11747b4cbb 100644 (file)
@@ -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.
index 826cd0cc05f14e50080316a64b69d2dc3820ed1e..2436bb54aa81c553d1d3abbdd4b88f161d6fb0fb 100644 (file)
@@ -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.