Use backend interface for temporary variables.
authorIan Lance Taylor <iant@google.com>
Tue, 19 Apr 2011 21:52:41 +0000 (21:52 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Tue, 19 Apr 2011 21:52:41 +0000 (21:52 +0000)
* go-gcc.cc (Gcc_backend::temporary_variable): New function.

From-SVN: r172737

gcc/go/ChangeLog
gcc/go/go-gcc.cc
gcc/go/gofrontend/backend.h
gcc/go/gofrontend/expressions.cc
gcc/go/gofrontend/statements.cc
gcc/go/gofrontend/statements.h

index 4fe9b4618cf5f17602c7edfd77eb272732130070..37d6b6c0d16c2f8c42fde9a26772cae40ebd4475 100644 (file)
@@ -1,3 +1,7 @@
+2011-04-19  Ian Lance Taylor  <iant@google.com>
+
+       * go-gcc.cc (Gcc_backend::temporary_variable): New function.
+
 2011-04-19  Ian Lance Taylor  <iant@google.com>
 
        * go-gcc.cc (class Bblock): Define.
index 46c149cd3cbc2b3c733a879d5fa37b2ad48300e1..7b7923d06f95fc5f7656363d6a91050809d0e91b 100644 (file)
@@ -255,6 +255,10 @@ class Gcc_backend : public Backend
   parameter_variable(Bfunction*, const std::string& name, Btype* type,
                     source_location);
 
+  Bvariable*
+  temporary_variable(Bfunction*, Bblock*, Btype*, Bexpression*, bool,
+                    source_location, Bstatement**);
+
   // Labels.
 
   Blabel*
@@ -702,6 +706,68 @@ Gcc_backend::parameter_variable(Bfunction* function, const std::string& name,
   return new Bvariable(decl);
 }
 
+// Make a temporary variable.
+
+Bvariable*
+Gcc_backend::temporary_variable(Bfunction* function, Bblock* bblock,
+                               Btype* btype, Bexpression* binit,
+                               bool is_address_taken,
+                               source_location location,
+                               Bstatement** pstatement)
+{
+  tree type_tree = btype->get_tree();
+  tree init_tree = binit == NULL ? NULL_TREE : binit->get_tree();
+  if (type_tree == error_mark_node || init_tree == error_mark_node)
+    {
+      *pstatement = this->error_statement();
+      return this->error_variable();
+    }
+
+  tree var;
+  // We can only use create_tmp_var if the type is not addressable.
+  if (!TREE_ADDRESSABLE(type_tree))
+    var = create_tmp_var(type_tree, "GOTMP");
+  else
+    {
+      gcc_assert(bblock != NULL);
+      var = build_decl(location, VAR_DECL,
+                      create_tmp_var_name("GOTMP"),
+                      type_tree);
+      DECL_ARTIFICIAL(var) = 1;
+      DECL_IGNORED_P(var) = 1;
+      TREE_USED(var) = 1;
+      // FIXME: Permitting function to be NULL here is a temporary
+      // measure until we have a proper representation of the init
+      // function.
+      if (function != NULL)
+       DECL_CONTEXT(var) = function->get_tree();
+      else
+       {
+         gcc_assert(current_function_decl != NULL_TREE);
+         DECL_CONTEXT(var) = current_function_decl;
+       }
+
+      // We have to add this variable to the BLOCK and the BIND_EXPR.
+      tree bind_tree = bblock->get_tree();
+      gcc_assert(TREE_CODE(bind_tree) == BIND_EXPR);
+      tree block_tree = BIND_EXPR_BLOCK(bind_tree);
+      gcc_assert(TREE_CODE(block_tree) == BLOCK);
+      DECL_CHAIN(var) = BLOCK_VARS(block_tree);
+      BLOCK_VARS(block_tree) = var;
+      BIND_EXPR_VARS(bind_tree) = BLOCK_VARS(block_tree);
+    }
+
+  if (init_tree != NULL_TREE)
+    DECL_INITIAL(var) = fold_convert_loc(location, type_tree, init_tree);
+
+  if (is_address_taken)
+    TREE_ADDRESSABLE(var) = 1;
+
+  *pstatement = this->make_statement(build1_loc(location, DECL_EXPR,
+                                               void_type_node, var));
+  return new Bvariable(var);
+}
+
 // Make a label.
 
 Blabel*
index 6690a5238dcc6ed7e6b6cc1912e86e667c276ab7..4377332ed09807fa25e9dbcabdafcb1f9b6a458e 100644 (file)
@@ -246,6 +246,22 @@ class Backend
   parameter_variable(Bfunction* function, const std::string& name,
                     Btype* type, source_location location) = 0;
 
+  // Create a temporary variable.  A temporary variable has no name,
+  // just a type.  We pass in FUNCTION and BLOCK in case they are
+  // needed.  If INIT is not NULL, the variable should be initialized
+  // to that value.  Otherwise the initial value is irrelevant--the
+  // backend does not have to explicitly initialize it to zero.
+  // ADDRESS_IS_TAKEN is true if the programs needs to take the
+  // address of this temporary variable.  LOCATION is the location of
+  // the statement or expression which requires creating the temporary
+  // variable, and may not be very useful.  This function should
+  // return a variable which can be referenced later and should set
+  // *PSTATEMENT to a statement which initializes the variable.
+  virtual Bvariable*
+  temporary_variable(Bfunction*, Bblock*, Btype*, Bexpression* init,
+                    bool address_is_taken, source_location location,
+                    Bstatement** pstatement) = 0;
+
   // Labels.
   
   // Create a new label.  NAME will be empty if this is a label
index 9adcbc33b6559f3cbc8ea034f4957d8c1c25bfcd..5f885ab5b3c01845ab6ded9dc264762213f60e01 100644 (file)
@@ -1029,9 +1029,22 @@ Temporary_reference_expression::do_address_taken(bool)
 // Get a tree referring to the variable.
 
 tree
-Temporary_reference_expression::do_get_tree(Translate_context*)
+Temporary_reference_expression::do_get_tree(Translate_context* context)
 {
-  return this->statement_->get_decl();
+  Bvariable* bvar = this->statement_->get_backend_variable(context);
+
+  // The gcc backend can't represent the same set of recursive types
+  // that the Go frontend can.  In some cases this means that a
+  // temporary variable won't have the right backend type.  Correct
+  // that here by adding a type cast.  We need to use base() to push
+  // the circularity down one level.
+  tree ret = var_to_tree(bvar);
+  if (POINTER_TYPE_P(TREE_TYPE(ret)) && VOID_TYPE_P(TREE_TYPE(TREE_TYPE(ret))))
+    {
+      tree type_tree = this->type()->base()->get_tree(context->gogo());
+      ret = fold_convert_loc(this->location(), type_tree, ret);
+    }
+  return ret;
 }
 
 // Make a reference to a temporary variable.
@@ -8952,7 +8965,7 @@ Call_expression::do_get_tree(Translate_context* context)
 
   // This is to support builtin math functions when using 80387 math.
   tree excess_type = NULL_TREE;
-  if (DECL_P(fndecl)
+  if (TREE_CODE(fndecl) == FUNCTION_DECL
       && DECL_IS_BUILTIN(fndecl)
       && DECL_BUILT_IN_CLASS(fndecl) == BUILT_IN_NORMAL
       && nargs > 0
index 7c6ccb989f59e3ab2c8e59656eaeebb5962e3cf5..eef93981aaae9c7fc1b5554cb79270402cc20c56 100644 (file)
@@ -311,19 +311,6 @@ Temporary_statement::type() const
   return this->type_ != NULL ? this->type_ : this->init_->type();
 }
 
-// Return the tree for the temporary variable.
-
-tree
-Temporary_statement::get_decl() const
-{
-  if (this->decl_ == NULL)
-    {
-      gcc_assert(saw_errors());
-      return error_mark_node;
-    }
-  return this->decl_;
-}
-
 // Traversal.
 
 int
@@ -400,53 +387,52 @@ Temporary_statement::do_check_types(Gogo*)
 tree
 Temporary_statement::do_get_tree(Translate_context* context)
 {
-  gcc_assert(this->decl_ == NULL_TREE);
-  tree type_tree = this->type()->get_tree(context->gogo());
-  tree init_tree = (this->init_ == NULL
-                   ? NULL_TREE
-                   : this->init_->get_tree(context));
-  if (type_tree == error_mark_node || init_tree == error_mark_node)
-    {
-      this->decl_ = error_mark_node;
-      return error_mark_node;
-    }
-  // We can only use create_tmp_var if the type is not addressable.
-  if (!TREE_ADDRESSABLE(type_tree))
+  gcc_assert(this->bvariable_ == NULL);
+
+  // FIXME: Permitting FUNCTION to be NULL here is a temporary measure
+  // until we have a better representation of the init function.
+  Named_object* function = context->function();
+  Bfunction* bfunction;
+  if (function == NULL)
+    bfunction = NULL;
+  else
+    bfunction = tree_to_function(function->func_value()->get_decl());
+
+  Btype* btype = tree_to_type(this->type()->get_tree(context->gogo()));
+
+  Bexpression* binit;
+  if (this->init_ == NULL)
+    binit = NULL;
+  else if (this->type_ == NULL)
+    binit = tree_to_expr(this->init_->get_tree(context));
+  else
     {
-      this->decl_ = create_tmp_var(type_tree, "GOTMP");
-      DECL_SOURCE_LOCATION(this->decl_) = this->location();
+      Expression* init = Expression::make_cast(this->type_, this->init_,
+                                              this->location());
+      context->gogo()->lower_expression(context->function(), &init);
+      binit = tree_to_expr(init->get_tree(context));
     }
-  else
+
+  Bstatement* statement;
+  this->bvariable_ =
+    context->backend()->temporary_variable(bfunction, context->bblock(),
+                                          btype, binit,
+                                          this->is_address_taken_,
+                                          this->location(), &statement);
+  return stat_to_tree(statement);
+}
+
+// Return the backend variable.
+
+Bvariable*
+Temporary_statement::get_backend_variable(Translate_context* context) const
+{
+  if (this->bvariable_ == NULL)
     {
-      gcc_assert(context->function() != NULL && context->block() != NULL);
-      tree decl = build_decl(this->location(), VAR_DECL,
-                            create_tmp_var_name("GOTMP"),
-                            type_tree);
-      DECL_ARTIFICIAL(decl) = 1;
-      DECL_IGNORED_P(decl) = 1;
-      TREE_USED(decl) = 1;
-      gcc_assert(current_function_decl != NULL_TREE);
-      DECL_CONTEXT(decl) = current_function_decl;
-
-      // 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;
+      gcc_assert(saw_errors());
+      return context->backend()->error_variable();
     }
-  if (init_tree != NULL_TREE)
-    DECL_INITIAL(this->decl_) =
-      Expression::convert_for_assignment(context, this->type(),
-                                        this->init_->type(), init_tree,
-                                        this->location());
-  if (this->is_address_taken_)
-    TREE_ADDRESSABLE(this->decl_) = 1;
-  return this->build_stmt_1(DECL_EXPR, this->decl_);
+  return this->bvariable_;
 }
 
 // Make and initialize a temporary variable in BLOCK.
index 1958bf9b947b89c1f6a13640b3cfcc9f64c05ce5..2310ef1d705eece950a7a6dc16229d98f07cad3a 100644 (file)
@@ -41,6 +41,7 @@ class Select_clauses;
 class Typed_identifier_list;
 class Bexpression;
 class Bstatement;
+class Bvariable;
 
 // This class is used to traverse assignments made by a statement
 // which makes assignments.
@@ -475,28 +476,23 @@ class Temporary_statement : public Statement
  public:
   Temporary_statement(Type* type, Expression* init, source_location location)
     : Statement(STATEMENT_TEMPORARY, location),
-      type_(type), init_(init), decl_(NULL), is_address_taken_(false)
+      type_(type), init_(init), bvariable_(NULL), is_address_taken_(false)
   { }
 
   // Return the type of the temporary variable.
   Type*
   type() const;
 
-  // Return the initialization expression.
-  Expression*
-  init() const
-  { return this->init_; }
-
   // Record that something takes the address of this temporary
   // variable.
   void
   set_is_address_taken()
   { this->is_address_taken_ = true; }
 
-  // Return the tree for the temporary variable itself.  This should
-  // not be called until after the statement itself has been expanded.
-  tree
-  get_decl() const;
+  // Return the temporary variable.  This should not be called until
+  // after the statement itself has been converted.
+  Bvariable*
+  get_backend_variable(Translate_context*) const;
 
  protected:
   int
@@ -519,8 +515,8 @@ class Temporary_statement : public Statement
   Type* type_;
   // The initial value of the temporary variable.  This may be NULL.
   Expression* init_;
-  // The DECL for the temporary variable.
-  tree decl_;
+  // The backend representation of the temporary variable.
+  Bvariable* bvariable_;
   // True if something takes the address of this temporary variable.
   bool is_address_taken_;
 };