Use backend interface for blocks.
authorian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 19 Apr 2011 18:20:05 +0000 (18:20 +0000)
committerian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 19 Apr 2011 18:20:05 +0000 (18:20 +0000)
* go-gcc.cc (class Bblock): Define.
(Gcc_backend::if_statement): Change then_block and else_block to
Bblock*.
(Gcc_backend::block): New function.
(Gcc_backend::block_add_statements): New function.
(Gcc_backend::block_statement): New function.
(tree_to_block, block_to_tree): New functions.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@172731 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/go/ChangeLog
gcc/go/go-gcc.cc
gcc/go/gofrontend/backend.h
gcc/go/gofrontend/gogo-tree.cc
gcc/go/gofrontend/gogo.cc
gcc/go/gofrontend/gogo.h
gcc/go/gofrontend/statements.cc
gcc/go/gofrontend/types.cc

index 141728b..4fe9b46 100644 (file)
@@ -1,3 +1,13 @@
+2011-04-19  Ian Lance Taylor  <iant@google.com>
+
+       * go-gcc.cc (class Bblock): Define.
+       (Gcc_backend::if_statement): Change then_block and else_block to
+       Bblock*.
+       (Gcc_backend::block): New function.
+       (Gcc_backend::block_add_statements): New function.
+       (Gcc_backend::block_statement): New function.
+       (tree_to_block, block_to_tree): New functions.
+
 2011-04-18  Ian Lance Taylor  <iant@google.com>
 
        * go-gcc.cc: Include "go-c.h".
index e4f4cfc..46c149c 100644 (file)
@@ -92,6 +92,14 @@ class Bfunction : public Gcc_tree
   { }
 };
 
+class Bblock : public Gcc_tree
+{
+ public:
+  Bblock(tree t)
+    : Gcc_tree(t)
+  { }
+};
+
 class Bvariable : public Gcc_tree
 {
  public:
@@ -194,8 +202,8 @@ class Gcc_backend : public Backend
                   source_location);
 
   Bstatement*
-  if_statement(Bexpression* condition, Bstatement* then_block,
-              Bstatement* else_block, source_location);
+  if_statement(Bexpression* condition, Bblock* then_block, Bblock* else_block,
+              source_location);
 
   Bstatement*
   switch_statement(Bexpression* value,
@@ -209,6 +217,18 @@ class Gcc_backend : public Backend
   Bstatement*
   statement_list(const std::vector<Bstatement*>&);
 
+  // Blocks.
+
+  Bblock*
+  block(Bfunction*, Bblock*, const std::vector<Bvariable*>&,
+       source_location, source_location);
+
+  void
+  block_add_statements(Bblock*, const std::vector<Bstatement*>&);
+
+  Bstatement*
+  block_statement(Bblock*);
+
   // Variables.
 
   Bvariable*
@@ -370,8 +390,8 @@ Gcc_backend::return_statement(Bfunction* bfunction,
 // If.
 
 Bstatement*
-Gcc_backend::if_statement(Bexpression* condition, Bstatement* then_block,
-                         Bstatement* else_block, source_location location)
+Gcc_backend::if_statement(Bexpression* condition, Bblock* then_block,
+                         Bblock* else_block, source_location location)
 {
   tree cond_tree = condition->get_tree();
   tree then_tree = then_block->get_tree();
@@ -481,6 +501,114 @@ Gcc_backend::statement_list(const std::vector<Bstatement*>& statements)
   return this->make_statement(stmt_list);
 }
 
+// Make a block.  For some reason gcc uses a dual structure for
+// blocks: BLOCK tree nodes and BIND_EXPR tree nodes.  Since the
+// BIND_EXPR node points to the BLOCK node, we store the BIND_EXPR in
+// the Bblock.
+
+Bblock*
+Gcc_backend::block(Bfunction* function, Bblock* enclosing,
+                  const std::vector<Bvariable*>& vars,
+                  source_location start_location,
+                  source_location)
+{
+  tree block_tree = make_node(BLOCK);
+  if (enclosing == NULL)
+    {
+      // FIXME: Permitting FUNCTION to be NULL is a temporary measure
+      // until we have a proper representation of the init function.
+      tree fndecl;
+      if (function == NULL)
+       fndecl = current_function_decl;
+      else
+       fndecl = function->get_tree();
+      gcc_assert(fndecl != NULL_TREE);
+
+      // We may have already created a block for local variables when
+      // we take the address of a parameter.
+      if (DECL_INITIAL(fndecl) == NULL_TREE)
+       {
+         BLOCK_SUPERCONTEXT(block_tree) = fndecl;
+         DECL_INITIAL(fndecl) = block_tree;
+       }
+      else
+       {
+         tree superblock_tree = DECL_INITIAL(fndecl);
+         BLOCK_SUPERCONTEXT(block_tree) = superblock_tree;
+         tree* pp;
+         for (pp = &BLOCK_SUBBLOCKS(superblock_tree);
+              *pp != NULL_TREE;
+              pp = &BLOCK_CHAIN(*pp))
+           ;
+         *pp = block_tree;
+       }
+    }
+  else
+    {
+      tree superbind_tree = enclosing->get_tree();
+      tree superblock_tree = BIND_EXPR_BLOCK(superbind_tree);
+      gcc_assert(TREE_CODE(superblock_tree) == BLOCK);
+
+      BLOCK_SUPERCONTEXT(block_tree) = superblock_tree;
+      tree* pp;
+      for (pp = &BLOCK_SUBBLOCKS(superblock_tree);
+          *pp != NULL_TREE;
+          pp = &BLOCK_CHAIN(*pp))
+       ;
+      *pp = block_tree;
+    }
+
+  tree* pp = &BLOCK_VARS(block_tree);
+  for (std::vector<Bvariable*>::const_iterator pv = vars.begin();
+       pv != vars.end();
+       ++pv)
+    {
+      *pp = (*pv)->get_tree();
+      if (*pp != error_mark_node)
+       pp = &DECL_CHAIN(*pp);
+    }
+  *pp = NULL_TREE;
+
+  TREE_USED(block_tree) = 1;
+
+  tree bind_tree = build3_loc(start_location, BIND_EXPR, void_type_node,
+                             BLOCK_VARS(block_tree), NULL_TREE, block_tree);
+  TREE_SIDE_EFFECTS(bind_tree) = 1;
+
+  return new Bblock(bind_tree);
+}
+
+// Add statements to a block.
+
+void
+Gcc_backend::block_add_statements(Bblock* bblock,
+                                 const std::vector<Bstatement*>& statements)
+{
+  tree stmt_list = NULL_TREE;
+  for (std::vector<Bstatement*>::const_iterator p = statements.begin();
+       p != statements.end();
+       ++p)
+    {
+      tree s = (*p)->get_tree();
+      if (s != error_mark_node)
+       append_to_statement_list(s, &stmt_list);
+    }
+
+  tree bind_tree = bblock->get_tree();
+  gcc_assert(TREE_CODE(bind_tree) == BIND_EXPR);
+  BIND_EXPR_BODY(bind_tree) = stmt_list;
+}
+
+// Return a block as a statement.
+
+Bstatement*
+Gcc_backend::block_statement(Bblock* bblock)
+{
+  tree bind_tree = bblock->get_tree();
+  gcc_assert(TREE_CODE(bind_tree) == BIND_EXPR);
+  return this->make_statement(bind_tree);
+}
+
 // Make a global variable.
 
 Bvariable*
@@ -665,6 +793,13 @@ tree_to_function(tree t)
   return new Bfunction(t);
 }
 
+Bblock*
+tree_to_block(tree t)
+{
+  gcc_assert(TREE_CODE(t) == BIND_EXPR);
+  return new Bblock(t);
+}
+
 tree
 expr_to_tree(Bexpression* be)
 {
@@ -678,6 +813,12 @@ stat_to_tree(Bstatement* bs)
 }
 
 tree
+block_to_tree(Bblock* bb)
+{
+  return bb->get_tree();
+}
+
+tree
 var_to_tree(Bvariable* bv)
 {
   return bv->get_tree();
index 3e4c629..6690a52 100644 (file)
@@ -27,6 +27,9 @@ class Bstatement;
 // The backend representation of a function definition.
 class Bfunction;
 
+// The backend representation of a block.
+class Bblock;
+
 // The backend representation of a variable.
 class Bvariable;
 
@@ -139,8 +142,8 @@ class Backend
 
   // Create an if statement.  ELSE_BLOCK may be NULL.
   virtual Bstatement*
-  if_statement(Bexpression* condition, Bstatement* then_block,
-              Bstatement* else_block, source_location) = 0;
+  if_statement(Bexpression* condition, Bblock* then_block, Bblock* else_block,
+              source_location) = 0;
 
   // Create a switch statement where the case values are constants.
   // CASES and STATEMENTS must have the same number of entries.  If
@@ -163,6 +166,35 @@ class Backend
   virtual Bstatement*
   statement_list(const std::vector<Bstatement*>&) = 0;
 
+  // Blocks.
+
+  // Create a block.  The frontend will call this function when it
+  // starts converting a block within a function.  FUNCTION is the
+  // current function.  ENCLOSING is the enclosing block; it will be
+  // NULL for the top-level block in a function.  VARS is the list of
+  // local variables defined within this block; each entry will be
+  // created by the local_variable function.  START_LOCATION is the
+  // location of the start of the block, more or less the location of
+  // the initial curly brace.  END_LOCATION is the location of the end
+  // of the block, more or less the location of the final curly brace.
+  // The statements will be added after the block is created.
+  virtual Bblock*
+  block(Bfunction* function, Bblock* enclosing,
+       const std::vector<Bvariable*>& vars,
+       source_location start_location, source_location end_location) = 0;
+
+  // Add the statements to a block.  The block is created first.  Then
+  // the statements are created.  Then the statements are added to the
+  // block.  This will called exactly once per block.  The vector may
+  // be empty if there are no statements.
+  virtual void
+  block_add_statements(Bblock*, const std::vector<Bstatement*>&) = 0;
+
+  // Return the block as a statement.  This is used to include a block
+  // in a list of statements.
+  virtual Bstatement*
+  block_statement(Bblock*) = 0;
+
   // Variables.
 
   // Create an error variable.  This is used for cases which should
@@ -250,8 +282,10 @@ extern Btype* tree_to_type(tree);
 extern Bexpression* tree_to_expr(tree);
 extern Bstatement* tree_to_stat(tree);
 extern Bfunction* tree_to_function(tree);
+extern Bblock* tree_to_block(tree);
 extern tree expr_to_tree(Bexpression*);
 extern tree stat_to_tree(Bstatement*);
+extern tree block_to_tree(Bblock*);
 extern tree var_to_tree(Bvariable*);
 
 #endif // !defined(GO_BACKEND_H)
index a59076e..ec06c65 100644 (file)
@@ -900,7 +900,7 @@ Named_object::get_tree(Gogo* gogo, Named_object* function)
     case NAMED_OBJECT_CONST:
       {
        Named_constant* named_constant = this->u_.const_value;
-       Translate_context subcontext(gogo, function, NULL, NULL_TREE);
+       Translate_context subcontext(gogo, function, NULL, NULL);
        tree expr_tree = named_constant->expr()->get_tree(&subcontext);
        if (expr_tree == error_mark_node)
          decl = error_mark_node;
@@ -1038,7 +1038,7 @@ Variable::get_init_tree(Gogo* gogo, Named_object* function)
     }
   else
     {
-      Translate_context context(gogo, function, NULL, NULL_TREE);
+      Translate_context context(gogo, function, NULL, NULL);
       tree rhs_tree = this->init_->get_tree(&context);
       return Expression::convert_for_assignment(&context, this->type(),
                                                this->init_->type(),
@@ -1059,8 +1059,9 @@ Variable::get_init_block(Gogo* gogo, Named_object* function, tree var_decl)
   // TRY_CATCH_EXPR; if it does, we want to add to the end of the
   // regular statements.
 
-  Translate_context context(gogo, function, NULL, NULL_TREE);
-  tree block_tree = this->preinit_->get_tree(&context);
+  Translate_context context(gogo, function, NULL, NULL);
+  Bblock* bblock = this->preinit_->get_backend(&context);
+  tree block_tree = block_to_tree(bblock);
   if (block_tree == error_mark_node)
     return error_mark_node;
   gcc_assert(TREE_CODE(block_tree) == BIND_EXPR);
@@ -1472,21 +1473,22 @@ Function::build_tree(Gogo* gogo, Named_object* named_function)
          BLOCK_VARS(block) = declare_vars;
          TREE_USED(block) = 1;
 
+         bind = build3(BIND_EXPR, void_type_node, BLOCK_VARS(block),
+                       NULL_TREE, block);
+         TREE_SIDE_EFFECTS(bind) = 1;
+
          if (this->defer_stack_ != NULL)
            {
              Translate_context dcontext(gogo, named_function, this->block_,
-                                        block);
+                                        tree_to_block(bind));
              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;
        }
 
       // Build the trees for all the statements in the function.
-      Translate_context context(gogo, named_function, NULL, NULL_TREE);
-      tree code = this->block_->get_tree(&context);
+      Translate_context context(gogo, named_function, NULL, NULL);
+      Bblock* bblock = this->block_->get_backend(&context);
+      tree code = block_to_tree(bblock);
 
       tree init = NULL_TREE;
       tree except = NULL_TREE;
@@ -1681,95 +1683,6 @@ Function::return_value(Gogo* gogo, Named_object* named_function,
     }
 }
 
-// Get a tree for the statements in a block.
-
-tree
-Block::get_tree(Translate_context* context)
-{
-  Gogo* gogo = context->gogo();
-
-  tree block = make_node(BLOCK);
-
-  // Put the new block into the block tree.
-
-  if (context->block() == NULL)
-    {
-      tree fndecl;
-      if (context->function() != NULL)
-       fndecl = context->function()->func_value()->get_decl();
-      else
-       fndecl = current_function_decl;
-      gcc_assert(fndecl != NULL_TREE);
-
-      // We may have already created a block for the receiver.
-      if (DECL_INITIAL(fndecl) == NULL_TREE)
-       {
-         BLOCK_SUPERCONTEXT(block) = fndecl;
-         DECL_INITIAL(fndecl) = block;
-       }
-      else
-       {
-         tree superblock_tree = DECL_INITIAL(fndecl);
-         BLOCK_SUPERCONTEXT(block) = superblock_tree;
-         gcc_assert(BLOCK_CHAIN(block) == NULL_TREE);
-         BLOCK_CHAIN(block) = block;
-       }
-    }
-  else
-    {
-      tree superblock_tree = context->block_tree();
-      BLOCK_SUPERCONTEXT(block) = superblock_tree;
-      tree* pp;
-      for (pp = &BLOCK_SUBBLOCKS(superblock_tree);
-          *pp != NULL_TREE;
-          pp = &BLOCK_CHAIN(*pp))
-       ;
-      *pp = block;
-    }
-
-  // Expand local variables in the block.
-
-  tree* pp = &BLOCK_VARS(block);
-  for (Bindings::const_definitions_iterator pv =
-        this->bindings_->begin_definitions();
-       pv != this->bindings_->end_definitions();
-       ++pv)
-    {
-      if ((*pv)->is_variable() && !(*pv)->var_value()->is_parameter())
-       {
-         Bvariable* var = (*pv)->get_backend_variable(gogo,
-                                                      context->function());
-         *pp = var_to_tree(var);
-         if (*pp != error_mark_node)
-           pp = &DECL_CHAIN(*pp);
-       }
-    }
-  *pp = NULL_TREE;
-
-  Translate_context subcontext(gogo, context->function(), this, block);
-
-  tree statements = NULL_TREE;
-
-  // Expand the statements.
-
-  for (std::vector<Statement*>::const_iterator p = this->statements_.begin();
-       p != this->statements_.end();
-       ++p)
-    {
-      tree statement = (*p)->get_tree(&subcontext);
-      if (statement != error_mark_node)
-       append_to_statement_list(statement, &statements);
-    }
-
-  TREE_USED(block) = 1;
-
-  tree bind = build3(BIND_EXPR, void_type_node, BLOCK_VARS(block), statements,
-                    block);
-  TREE_SIDE_EFFECTS(bind) = 1;
-
-  return bind;
-}
-
 // Return the integer type to use for a size.
 
 GO_EXTERN_C
index 8f0d328..be945c5 100644 (file)
@@ -3285,6 +3285,48 @@ Block::may_fall_through() const
   return this->statements_.back()->may_fall_through();
 }
 
+// Convert a block to the backend representation.
+
+Bblock*
+Block::get_backend(Translate_context* context)
+{
+  Gogo* gogo = context->gogo();
+  Named_object* function = context->function();
+  std::vector<Bvariable*> vars;
+  vars.reserve(this->bindings_->size_definitions());
+  for (Bindings::const_definitions_iterator pv =
+        this->bindings_->begin_definitions();
+       pv != this->bindings_->end_definitions();
+       ++pv)
+    {
+      if ((*pv)->is_variable() && !(*pv)->var_value()->is_parameter())
+       vars.push_back((*pv)->get_backend_variable(gogo, function));
+    }
+
+  // FIXME: Permitting FUNCTION to be NULL here is a temporary measure
+  // until we have a proper representation of the init function.
+  Bfunction* bfunction;
+  if (function == NULL)
+    bfunction = NULL;
+  else
+    bfunction = tree_to_function(function->func_value()->get_decl());
+  Bblock* ret = context->backend()->block(bfunction, context->bblock(),
+                                         vars, this->start_location_,
+                                         this->end_location_);
+
+  Translate_context subcontext(gogo, function, this, ret);
+  std::vector<Bstatement*> bstatements;
+  bstatements.reserve(this->statements_.size());
+  for (std::vector<Statement*>::const_iterator p = this->statements_.begin();
+       p != this->statements_.end();
+       ++p)
+    bstatements.push_back(tree_to_stat((*p)->get_tree(&subcontext)));
+
+  context->backend()->block_add_statements(ret, bstatements);
+
+  return ret;
+}
+
 // Class Variable.
 
 Variable::Variable(Type* type, Expression* init, bool is_global,
index cb6501e..f9eba50 100644 (file)
@@ -43,6 +43,7 @@ class Export;
 class Import;
 class Bexpression;
 class Bstatement;
+class Bblock;
 class Bvariable;
 class Blabel;
 
@@ -767,9 +768,9 @@ class Block
   bool
   may_fall_through() const;
 
-  // Return a tree of the code in this block.
-  tree
-  get_tree(Translate_context*);
+  // Convert the block to the backend representation.
+  Bblock*
+  get_backend(Translate_context*);
 
   // Iterate over statements.
 
@@ -2507,9 +2508,9 @@ class Translate_context
 {
  public:
   Translate_context(Gogo* gogo, Named_object* function, Block* block,
-                   tree block_tree)
+                   Bblock* bblock)
     : gogo_(gogo), backend_(gogo->backend()), function_(function),
-      block_(block), block_tree_(block_tree), is_const_(false)
+      block_(block), bblock_(bblock), is_const_(false)
   { }
 
   // Accessors.
@@ -2530,9 +2531,9 @@ class Translate_context
   block()
   { return this->block_; }
 
-  tree
-  block_tree()
-  { return this->block_tree_; }
+  Bblock*
+  bblock()
+  { return this->bblock_; }
 
   bool
   is_const()
@@ -2548,12 +2549,15 @@ class Translate_context
   Gogo* gogo_;
   // The generator for the backend data structures.
   Backend* backend_;
-  // The function we are currently translating.
+  // The function we are currently translating.  NULL if not in a
+  // function, e.g., the initializer of a global variable.
   Named_object* function_;
-  // The block we are currently translating.
+  // The block we are currently translating.  NULL if not in a
+  // function.
   Block *block_;
-  // The BLOCK node for the current block.
-  tree block_tree_;
+  // The backend representation of the current block.  NULL if block_
+  // is NULL.
+  Bblock* bblock_;
   // Whether this is being evaluated in a constant context.  This is
   // used for type descriptor initializers.
   bool is_const_;
index fde3f62..7c6ccb9 100644 (file)
@@ -428,12 +428,14 @@ Temporary_statement::do_get_tree(Translate_context* context)
       gcc_assert(current_function_decl != NULL_TREE);
       DECL_CONTEXT(decl) = current_function_decl;
 
-      // We have to add this variable to the block so that it winds up
-      // in a BIND_EXPR.
-      tree block_tree = context->block_tree();
-      gcc_assert(block_tree != NULL_TREE);
+      // We have to add this variable to the BLOCK and the BIND_EXPR.
+      tree bind_tree = block_to_tree(context->bblock());
+      gcc_assert(bind_tree != NULL_TREE && TREE_CODE(bind_tree) == BIND_EXPR);
+      tree block_tree = BIND_EXPR_BLOCK(bind_tree);
+      gcc_assert(TREE_CODE(block_tree) == BLOCK);
       DECL_CHAIN(decl) = BLOCK_VARS(block_tree);
       BLOCK_VARS(block_tree) = decl;
+      BIND_EXPR_VARS(bind_tree) = BLOCK_VARS(block_tree);
 
       this->decl_ = decl;
     }
@@ -1518,13 +1520,22 @@ class Block_statement : public Statement
   { return this->block_->may_fall_through(); }
 
   tree
-  do_get_tree(Translate_context* context)
-  { return this->block_->get_tree(context); }
+  do_get_tree(Translate_context* context);
 
  private:
   Block* block_;
 };
 
+// Convert a block to the backend representation of a statement.
+
+tree
+Block_statement::do_get_tree(Translate_context* context)
+{
+  Bblock* bblock = this->block_->get_backend(context);
+  Bstatement* ret = context->backend()->block_statement(bblock);
+  return stat_to_tree(ret);
+}
+
 // Make a block statement.
 
 Statement*
@@ -2767,19 +2778,14 @@ If_statement::do_get_tree(Translate_context* context)
   gcc_assert(this->cond_->type()->is_boolean_type()
             || this->cond_->type()->is_error());
   tree cond_tree = this->cond_->get_tree(context);
-  tree then_tree = this->then_block_->get_tree(context);
-  tree else_tree = (this->else_block_ == NULL
-                   ? NULL_TREE
-                   : this->else_block_->get_tree(context));
-
+  Bblock* then_block = this->then_block_->get_backend(context);
+  Bblock* else_block = (this->else_block_ == NULL
+                       ? NULL
+                       : this->else_block_->get_backend(context));
   Bexpression* cond_expr = tree_to_expr(cond_tree);
-  Bstatement* then_stat = tree_to_stat(then_tree);
-  Bstatement* else_stat = (else_tree == NULL_TREE
-                          ? NULL
-                          : tree_to_stat(else_tree));
   
-  Bstatement* ret = context->backend()->if_statement(cond_expr, then_stat,
-                                                    else_stat,
+  Bstatement* ret = context->backend()->if_statement(cond_expr, then_block,
+                                                    else_block,
                                                     this->location());
   return stat_to_tree(ret);
 }
@@ -3056,7 +3062,10 @@ Case_clauses::Case_clause::get_backend(Translate_context* context,
   if (this->statements_ == NULL)
     statements = NULL;
   else
-    statements = tree_to_stat(this->statements_->get_tree(context));
+    {
+      Bblock* bblock = this->statements_->get_backend(context);
+      statements = context->backend()->block_statement(bblock);
+    }
 
   Bstatement* break_stat;
   if (this->is_fallthrough_)
@@ -4070,7 +4079,8 @@ Select_clauses::Select_clause::get_statements_backend(
 {
   if (this->statements_ == NULL)
     return NULL;
-  return tree_to_stat(this->statements_->get_tree(context));
+  Bblock* bblock = this->statements_->get_backend(context);
+  return context->backend()->block_statement(bblock);
 }
 
 // Class Select_clauses.
index 1143376..da22947 100644 (file)
@@ -4470,7 +4470,7 @@ Array_type::get_length_tree(Gogo* gogo)
 
          // Make up a translation context for the array length
          // expression.  FIXME: This won't work in general.
-         Translate_context context(gogo, NULL, NULL, NULL_TREE);
+         Translate_context context(gogo, NULL, NULL, NULL);
          tree len = this->length_->get_tree(&context);
          if (len != error_mark_node)
            {