OSDN Git Service

Use backend interface for variables.
authorian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 19 Apr 2011 04:23:00 +0000 (04:23 +0000)
committerian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 19 Apr 2011 04:23:00 +0000 (04:23 +0000)
* go-gcc.cc: Include "go-c.h".
(class Bvariable): Define.
(Gcc_backend::init_statement): New function.
(Gcc_backend::global_variable): New function.
(Gcc_backend::global_variable_set_init): New function.
(Gcc_backend::local_variable): New function.
(Gcc_backend::parameter_variable): New function.
(tree_to_type, var_to_tree): New functions.
* Make-lang.in (go/go-gcc.o): Depend on $(GO_C_H).
* (go/gogo-tree.o): Depend on go/gofrontend/backend.h.

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

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

index b6f91c4..141728b 100644 (file)
@@ -1,3 +1,16 @@
+2011-04-18  Ian Lance Taylor  <iant@google.com>
+
+       * go-gcc.cc: Include "go-c.h".
+       (class Bvariable): Define.
+       (Gcc_backend::init_statement): New function.
+       (Gcc_backend::global_variable): New function.
+       (Gcc_backend::global_variable_set_init): New function.
+       (Gcc_backend::local_variable): New function.
+       (Gcc_backend::parameter_variable): New function.
+       (tree_to_type, var_to_tree): New functions.
+       * Make-lang.in (go/go-gcc.o): Depend on $(GO_C_H).
+       * (go/gogo-tree.o): Depend on go/gofrontend/backend.h.
+
 2011-04-15  Ian Lance Taylor  <iant@google.com>
 
        * go-gcc.cc (Gcc_backend::compound_statement): New function.
index c20cebd..c0b279d 100644 (file)
@@ -239,7 +239,7 @@ go/go-lang.o: go/go-lang.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(OPTS_H) \
 GOINCLUDES = -I $(srcdir)/go -I $(srcdir)/go/gofrontend
 
 go/go-gcc.o: go/go-gcc.cc $(GO_SYSTEM_H) $(TREE_H) tree-iterator.h \
-               $(GIMPLE_H) $(GO_GOGO_H) go/gofrontend/backend.h
+               $(GIMPLE_H) $(GO_C_H) $(GO_GOGO_H) go/gofrontend/backend.h
        $(CXX) -c $(GOINCLUDES) $(ALL_CPPFLAGS) $(ALL_CXXFLAGS) $< $(OUTPUT_OPTION)
 
 go/%.o: go/gofrontend/%.cc
@@ -262,7 +262,8 @@ 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_RUNTIME_H) $(GO_GOGO_H)
+       $(GO_EXPRESSIONS_H) $(GO_STATEMENTS_H) $(GO_RUNTIME_H) \
+       go/gofrontend/backend.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 6cd402e..e4f4cfc 100644 (file)
@@ -37,6 +37,8 @@ extern "C"
 }
 #endif
 
+#include "go-c.h"
+
 #include "gogo.h"
 #include "backend.h"
 
@@ -90,6 +92,14 @@ class Bfunction : public Gcc_tree
   { }
 };
 
+class Bvariable : public Gcc_tree
+{
+ public:
+  Bvariable(tree t)
+    : Gcc_tree(t)
+  { }
+};
+
 class Blabel : public Gcc_tree
 {
  public:
@@ -174,6 +184,9 @@ class Gcc_backend : public Backend
   expression_statement(Bexpression*);
 
   Bstatement*
+  init_statement(Bvariable* var, Bexpression* init);
+
+  Bstatement*
   assignment_statement(Bexpression* lhs, Bexpression* rhs, source_location);
 
   Bstatement*
@@ -196,6 +209,32 @@ class Gcc_backend : public Backend
   Bstatement*
   statement_list(const std::vector<Bstatement*>&);
 
+  // Variables.
+
+  Bvariable*
+  error_variable()
+  { return new Bvariable(error_mark_node); }
+
+  Bvariable*
+  global_variable(const std::string& package_name,
+                 const std::string& unique_prefix,
+                 const std::string& name,
+                 Btype* btype,
+                 bool is_external,
+                 bool is_hidden,
+                 source_location location);
+
+  void
+  global_variable_set_init(Bvariable*, Bexpression*);
+
+  Bvariable*
+  local_variable(Bfunction*, const std::string& name, Btype* type,
+                source_location);
+
+  Bvariable*
+  parameter_variable(Bfunction*, const std::string& name, Btype* type,
+                    source_location);
+
   // Labels.
 
   Blabel*
@@ -238,6 +277,21 @@ Gcc_backend::expression_statement(Bexpression* expr)
   return this->make_statement(expr->get_tree());
 }
 
+// Variable initialization.
+
+Bstatement*
+Gcc_backend::init_statement(Bvariable* var, Bexpression* init)
+{
+  tree var_tree = var->get_tree();
+  tree init_tree = init->get_tree();
+  if (var_tree == error_mark_node || init_tree == error_mark_node)
+    return this->error_statement();
+  gcc_assert(TREE_CODE(var_tree) == VAR_DECL);
+  DECL_INITIAL(var_tree) = init_tree;
+  return this->make_statement(build1_loc(DECL_SOURCE_LOCATION(var_tree),
+                                        DECL_EXPR, void_type_node, var_tree));
+}
+
 // Assignment.
 
 Bstatement*
@@ -427,6 +481,99 @@ Gcc_backend::statement_list(const std::vector<Bstatement*>& statements)
   return this->make_statement(stmt_list);
 }
 
+// Make a global variable.
+
+Bvariable*
+Gcc_backend::global_variable(const std::string& package_name,
+                            const std::string& unique_prefix,
+                            const std::string& name,
+                            Btype* btype,
+                            bool is_external,
+                            bool is_hidden,
+                            source_location location)
+{
+  tree type_tree = btype->get_tree();
+  if (type_tree == error_mark_node)
+    return this->error_variable();
+
+  std::string var_name(package_name);
+  var_name.push_back('.');
+  var_name.append(name);
+  tree decl = build_decl(location, VAR_DECL,
+                        get_identifier_from_string(var_name),
+                        type_tree);
+  if (is_external)
+    DECL_EXTERNAL(decl) = 1;
+  else
+    TREE_STATIC(decl) = 1;
+  if (!is_hidden)
+    {
+      TREE_PUBLIC(decl) = 1;
+
+      std::string asm_name(unique_prefix);
+      asm_name.push_back('.');
+      asm_name.append(var_name);
+      SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(asm_name));
+    }
+  TREE_USED(decl) = 1;
+
+  go_preserve_from_gc(decl);
+
+  return new Bvariable(decl);
+}
+
+// Set the initial value of a global variable.
+
+void
+Gcc_backend::global_variable_set_init(Bvariable* var, Bexpression* expr)
+{
+  tree expr_tree = expr->get_tree();
+  if (expr_tree == error_mark_node)
+    return;
+  gcc_assert(TREE_CONSTANT(expr_tree));
+  tree var_decl = var->get_tree();
+  if (var_decl == error_mark_node)
+    return;
+  DECL_INITIAL(var_decl) = expr_tree;
+}
+
+// Make a local variable.
+
+Bvariable*
+Gcc_backend::local_variable(Bfunction* function, const std::string& name,
+                           Btype* btype, source_location location)
+{
+  tree type_tree = btype->get_tree();
+  if (type_tree == error_mark_node)
+    return this->error_variable();
+  tree decl = build_decl(location, VAR_DECL,
+                        get_identifier_from_string(name),
+                        type_tree);
+  DECL_CONTEXT(decl) = function->get_tree();
+  TREE_USED(decl) = 1;
+  go_preserve_from_gc(decl);
+  return new Bvariable(decl);
+}
+
+// Make a function parameter variable.
+
+Bvariable*
+Gcc_backend::parameter_variable(Bfunction* function, const std::string& name,
+                               Btype* btype, source_location location)
+{
+  tree type_tree = btype->get_tree();
+  if (type_tree == error_mark_node)
+    return this->error_variable();
+  tree decl = build_decl(location, PARM_DECL,
+                        get_identifier_from_string(name),
+                        type_tree);
+  DECL_CONTEXT(decl) = function->get_tree();
+  DECL_ARG_TYPE(decl) = type_tree;
+  TREE_USED(decl) = 1;
+  go_preserve_from_gc(decl);
+  return new Bvariable(decl);
+}
+
 // Make a label.
 
 Blabel*
@@ -494,6 +641,12 @@ go_get_backend()
 // FIXME: Temporary functions while converting to the new backend
 // interface.
 
+Btype*
+tree_to_type(tree t)
+{
+  return new Btype(t);
+}
+
 Bexpression*
 tree_to_expr(tree t)
 {
@@ -523,3 +676,9 @@ stat_to_tree(Bstatement* bs)
 {
   return bs->get_tree();
 }
+
+tree
+var_to_tree(Bvariable* bv)
+{
+  return bv->get_tree();
+}
index bd761bd..3e4c629 100644 (file)
@@ -27,6 +27,9 @@ class Bstatement;
 // The backend representation of a function definition.
 class Bfunction;
 
+// The backend representation of a variable.
+class Bvariable;
+
 // The backend representation of a label.
 class Blabel;
 
@@ -117,6 +120,12 @@ class Backend
   virtual Bstatement*
   expression_statement(Bexpression*) = 0;
 
+  // Create a variable initialization statement.  This initializes a
+  // local variable at the point in the program flow where it is
+  // declared.
+  virtual Bstatement*
+  init_statement(Bvariable* var, Bexpression* init) = 0;
+
   // Create an assignment statement.
   virtual Bstatement*
   assignment_statement(Bexpression* lhs, Bexpression* rhs,
@@ -154,6 +163,57 @@ class Backend
   virtual Bstatement*
   statement_list(const std::vector<Bstatement*>&) = 0;
 
+  // Variables.
+
+  // Create an error variable.  This is used for cases which should
+  // not occur in a correct program, in order to keep the compilation
+  // going without crashing.
+  virtual Bvariable*
+  error_variable() = 0;
+
+  // Create a global variable.  PACKAGE_NAME is the name of the
+  // package where the variable is defined.  UNIQUE_PREFIX is the
+  // prefix for that package, from the -fgo-prefix option.  NAME is
+  // the name of the variable.  BTYPE is the type of the variable.
+  // IS_EXTERNAL is true if the variable is defined in some other
+  // package.  IS_HIDDEN is true if the variable is not exported (name
+  // begins with a lower case letter).  LOCATION is where the variable
+  // was defined.
+  virtual Bvariable*
+  global_variable(const std::string& package_name,
+                 const std::string& unique_prefix,
+                 const std::string& name,
+                 Btype* btype,
+                 bool is_external,
+                 bool is_hidden,
+                 source_location location) = 0;
+
+  // A global variable will 1) be initialized to zero, or 2) be
+  // initialized to a constant value, or 3) be initialized in the init
+  // function.  In case 2, the frontend will call
+  // global_variable_set_init to set the initial value.  If this is
+  // not called, the backend should initialize a global variable to 0.
+  // The init function may then assign a value to it.
+  virtual void
+  global_variable_set_init(Bvariable*, Bexpression*) = 0;
+
+  // Create a local variable.  The frontend will create the local
+  // variables first, and then create the block which contains them.
+  // FUNCTION is the function in which the variable is defined.  NAME
+  // is the name of the variable.  TYPE is the type.  LOCATION is
+  // where the variable is defined.  For each local variable the
+  // frontend will call init_statement to set the initial value.
+  virtual Bvariable*
+  local_variable(Bfunction* function, const std::string& name, Btype* type,
+                source_location location) = 0;
+
+  // Create a function parameter.  This is an incoming parameter, not
+  // a result parameter (result parameters are treated as local
+  // variables).  The arguments are as for local_variable.
+  virtual Bvariable*
+  parameter_variable(Bfunction* function, const std::string& name,
+                    Btype* type, source_location location) = 0;
+
   // Labels.
   
   // Create a new label.  NAME will be empty if this is a label
@@ -186,10 +246,12 @@ extern Backend* go_get_backend();
 // FIXME: Temporary helper functions while converting to new backend
 // interface.
 
+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 tree expr_to_tree(Bexpression*);
 extern tree stat_to_tree(Bstatement*);
+extern tree var_to_tree(Bvariable*);
 
 #endif // !defined(GO_BACKEND_H)
index 5b72c6a..9adcbc3 100644 (file)
@@ -972,7 +972,24 @@ Var_expression::do_address_taken(bool escapes)
 tree
 Var_expression::do_get_tree(Translate_context* context)
 {
-  return this->variable_->get_tree(context->gogo(), context->function());
+  Bvariable* bvar = this->variable_->get_backend_variable(context->gogo(),
+                                                         context->function());
+  tree ret = var_to_tree(bvar);
+  if (ret == error_mark_node)
+    return error_mark_node;
+  bool is_in_heap;
+  if (this->variable_->is_variable())
+    is_in_heap = this->variable_->var_value()->is_in_heap();
+  else if (this->variable_->is_result_variable())
+    is_in_heap = this->variable_->result_var_value()->is_in_heap();
+  else
+    gcc_unreachable();
+  if (is_in_heap)
+    {
+      ret = build_fold_indirect_ref_loc(this->location(), ret);
+      TREE_THIS_NOTRAP(ret) = 1;
+    }
+  return ret;
 }
 
 // Make a reference to a variable in an expression.
index ea46639..a59076e 100644 (file)
@@ -32,6 +32,7 @@ extern "C"
 #include "expressions.h"
 #include "statements.h"
 #include "runtime.h"
+#include "backend.h"
 #include "gogo.h"
 
 // Whether we have seen any errors.
@@ -277,7 +278,8 @@ Gogo::register_gc_vars(const std::vector<Named_object*>& var_gc,
       constructor_elt* elt = VEC_quick_push(constructor_elt, init, NULL);
       tree field = TYPE_FIELDS(root_type);
       elt->index = field;
-      tree decl = (*p)->get_tree(this, NULL);
+      Bvariable* bvar = (*p)->get_backend_variable(this, NULL);
+      tree decl = var_to_tree(bvar);
       gcc_assert(TREE_CODE(decl) == VAR_DECL);
       elt->value = build_fold_addr_expr(decl);
 
@@ -704,24 +706,31 @@ Gogo::write_globals()
            }
        }
 
-      vec[i] = no->get_tree(this, NULL);
-
-      if (vec[i] == error_mark_node)
+      if (!no->is_variable())
        {
-         gcc_assert(saw_errors());
-         --i;
-         --count;
-         continue;
+         vec[i] = no->get_tree(this, NULL);
+         if (vec[i] == error_mark_node)
+           {
+             gcc_assert(saw_errors());
+             --i;
+             --count;
+             continue;
+           }
        }
-
-      // If a variable is initialized to a non-constant value, do the
-      // initialization in an initialization function.
-      if (TREE_CODE(vec[i]) == VAR_DECL)
+      else
        {
-         gcc_assert(no->is_variable());
+         Bvariable* var = no->get_backend_variable(this, NULL);
+         vec[i] = var_to_tree(var);
+         if (vec[i] == error_mark_node)
+           {
+             gcc_assert(saw_errors());
+             --i;
+             --count;
+             continue;
+           }
 
-         // Check for a sink variable, which may be used to run
-         // an initializer purely for its side effects.
+         // Check for a sink variable, which may be used to run an
+         // initializer purely for its side effects.
          bool is_sink = no->name()[0] == '_' && no->name()[1] == '.';
 
          tree var_init_tree = NULL_TREE;
@@ -733,7 +742,8 @@ Gogo::write_globals()
              else if (init == NULL_TREE)
                ;
              else if (TREE_CONSTANT(init))
-               DECL_INITIAL(vec[i]) = init;
+               this->backend()->global_variable_set_init(var,
+                                                         tree_to_expr(init));
              else if (is_sink)
                var_init_tree = init;
              else
@@ -828,16 +838,15 @@ Gogo::write_globals()
 tree
 Named_object::get_id(Gogo* gogo)
 {
+  gcc_assert(!this->is_variable() && !this->is_result_variable());
   std::string decl_name;
   if (this->is_function_declaration()
       && !this->func_declaration_value()->asm_name().empty())
     decl_name = this->func_declaration_value()->asm_name();
-  else if ((this->is_variable() && !this->var_value()->is_global())
-          || (this->is_type()
-              && this->type_value()->location() == BUILTINS_LOCATION))
+  else if (this->is_type()
+          && this->type_value()->location() == BUILTINS_LOCATION)
     {
-      // We don't need the package name for local variables or builtin
-      // types.
+      // We don't need the package name for builtin types.
       decl_name = Gogo::unpack_hidden_name(this->name_);
     }
   else
@@ -878,22 +887,7 @@ tree
 Named_object::get_tree(Gogo* gogo, Named_object* function)
 {
   if (this->tree_ != NULL_TREE)
-    {
-      // If this is a variable whose address is taken, we must rebuild
-      // the INDIRECT_REF each time to avoid invalid sharing.
-      tree ret = this->tree_;
-      if (((this->classification_ == NAMED_OBJECT_VAR
-           && this->var_value()->is_in_heap())
-          || (this->classification_ == NAMED_OBJECT_RESULT_VAR
-              && this->result_var_value()->is_in_heap()))
-         && ret != error_mark_node)
-       {
-         gcc_assert(TREE_CODE(ret) == INDIRECT_REF);
-         ret = build_fold_indirect_ref(TREE_OPERAND(ret, 0));
-         TREE_THIS_NOTRAP(ret) = 1;
-       }
-      return ret;
-    }
+    return this->tree_;
 
   tree name;
   if (this->classification_ == NAMED_OBJECT_TYPE)
@@ -976,117 +970,7 @@ Named_object::get_tree(Gogo* gogo, Named_object* function)
       return error_mark_node;
 
     case NAMED_OBJECT_VAR:
-      {
-       Variable* var = this->u_.var_value;
-       Type* type = var->type();
-       if (type->is_error_type()
-           || (type->is_undefined()
-               && (!var->is_global() || this->package() == NULL)))
-         {
-           // Force the error for an undefined type, just in case.
-           type->base();
-           decl = error_mark_node;
-         }
-       else
-         {
-           tree var_type = type->get_tree(gogo);
-           bool is_parameter = var->is_parameter();
-           if (var->is_receiver() && type->points_to() == NULL)
-             is_parameter = false;
-           if (var->is_in_heap())
-             {
-               is_parameter = false;
-               var_type = build_pointer_type(var_type);
-             }
-           decl = build_decl(var->location(),
-                             is_parameter ? PARM_DECL : VAR_DECL,
-                             name, var_type);
-           if (!var->is_global())
-             {
-               tree fnid = function->get_id(gogo);
-               tree fndecl = function->func_value()->get_or_make_decl(gogo,
-                                                                      function,
-                                                                      fnid);
-               DECL_CONTEXT(decl) = fndecl;
-             }
-           if (is_parameter)
-             DECL_ARG_TYPE(decl) = TREE_TYPE(decl);
-
-           if (var->is_global())
-             {
-               const Package* package = this->package();
-               if (package == NULL)
-                 TREE_STATIC(decl) = 1;
-               else
-                 DECL_EXTERNAL(decl) = 1;
-               if (!Gogo::is_hidden_name(this->name_))
-                 {
-                   TREE_PUBLIC(decl) = 1;
-                   std::string asm_name = (package == NULL
-                                           ? gogo->unique_prefix()
-                                           : package->unique_prefix());
-                   asm_name.append(1, '.');
-                   asm_name.append(IDENTIFIER_POINTER(name),
-                                   IDENTIFIER_LENGTH(name));
-                   tree asm_id = get_identifier_from_string(asm_name);
-                   SET_DECL_ASSEMBLER_NAME(decl, asm_id);
-                 }
-             }
-
-           // FIXME: We should only set this for variables which are
-           // actually used somewhere.
-           TREE_USED(decl) = 1;
-         }
-      }
-      break;
-
     case NAMED_OBJECT_RESULT_VAR:
-      {
-       Result_variable* result = this->u_.result_var_value;
-       Type* type = result->type();
-       if (type->is_error())
-         decl = error_mark_node;
-       else
-         {
-           gcc_assert(result->function() == function->func_value());
-           source_location loc = function->location();
-           tree result_type = type->get_tree(gogo);
-           tree init;
-           if (!result->is_in_heap())
-             init = type->get_init_tree(gogo, false);
-           else
-             {
-               tree space = gogo->allocate_memory(type,
-                                                  TYPE_SIZE_UNIT(result_type),
-                                                  loc);
-               result_type = build_pointer_type(result_type);
-               tree subinit = type->get_init_tree(gogo, true);
-               if (subinit == NULL_TREE)
-                 init = fold_convert_loc(loc, result_type, space);
-               else
-                 {
-                   space = save_expr(space);
-                   space = fold_convert_loc(loc, result_type, space);
-                   tree spaceref = build_fold_indirect_ref_loc(loc, space);
-                   TREE_THIS_NOTRAP(spaceref) = 1;
-                   tree set = fold_build2_loc(loc, MODIFY_EXPR, void_type_node,
-                                              spaceref, subinit);
-                   init = fold_build2_loc(loc, COMPOUND_EXPR, TREE_TYPE(space),
-                                          set, space);
-                 }
-             }
-           decl = build_decl(loc, VAR_DECL, name, result_type);
-           tree fnid = function->get_id(gogo);
-           tree fndecl = function->func_value()->get_or_make_decl(gogo,
-                                                                  function,
-                                                                  fnid);
-           DECL_CONTEXT(decl) = fndecl;
-           DECL_INITIAL(decl) = init;
-           TREE_USED(decl) = 1;
-         }
-      }
-      break;
-
     case NAMED_OBJECT_SINK:
       gcc_unreachable();
 
@@ -1129,20 +1013,6 @@ Named_object::get_tree(Gogo* gogo, Named_object* function)
 
   tree ret = decl;
 
-  // If this is a local variable whose address is taken, then we
-  // actually store it in the heap.  For uses of the variable we need
-  // to return a reference to that heap location.
-  if (((this->classification_ == NAMED_OBJECT_VAR
-       && this->var_value()->is_in_heap())
-       || (this->classification_ == NAMED_OBJECT_RESULT_VAR
-          && this->result_var_value()->is_in_heap()))
-      && ret != error_mark_node)
-    {
-      gcc_assert(POINTER_TYPE_P(TREE_TYPE(ret)));
-      ret = build_fold_indirect_ref(ret);
-      TREE_THIS_NOTRAP(ret) = 1;
-    }
-
   this->tree_ = ret;
 
   if (ret != error_mark_node)
@@ -1162,7 +1032,9 @@ Variable::get_init_tree(Gogo* gogo, Named_object* function)
   if (this->init_ == NULL)
     {
       gcc_assert(!this->is_parameter_);
-      return this->type_->get_init_tree(gogo, this->is_global_);
+      return this->type_->get_init_tree(gogo,
+                                       (this->is_global_
+                                        || this->is_in_heap()));
     }
   else
     {
@@ -1301,7 +1173,9 @@ Function::get_or_make_decl(Gogo* gogo, Named_object* no, tree id)
            {
              push_struct_function(decl);
 
-             tree closure_decl = this->closure_var_->get_tree(gogo, no);
+             Bvariable* bvar = this->closure_var_->get_backend_variable(gogo,
+                                                                        no);
+             tree closure_decl = var_to_tree(bvar);
              if (closure_decl == error_mark_node)
                this->fndecl_ = error_mark_node;
              else
@@ -1384,26 +1258,15 @@ Function::make_receiver_parm_decl(Gogo* gogo, Named_object* no, tree var_decl)
 {
   if (var_decl == error_mark_node)
     return error_mark_node;
-  // If the function takes the address of a receiver which is passed
-  // by value, then we will have an INDIRECT_REF here.  We need to get
-  // the real variable.
+  gcc_assert(TREE_CODE(var_decl) == VAR_DECL);
+  tree val_type = TREE_TYPE(var_decl);
   bool is_in_heap = no->var_value()->is_in_heap();
-  tree val_type;
-  if (TREE_CODE(var_decl) != INDIRECT_REF)
-    {
-      gcc_assert(!is_in_heap);
-      val_type = TREE_TYPE(var_decl);
-    }
-  else
+  if (is_in_heap)
     {
-      gcc_assert(is_in_heap);
-      var_decl = TREE_OPERAND(var_decl, 0);
-      if (var_decl == error_mark_node)
-       return error_mark_node;
-      gcc_assert(POINTER_TYPE_P(TREE_TYPE(var_decl)));
-      val_type = TREE_TYPE(TREE_TYPE(var_decl));
+      gcc_assert(POINTER_TYPE_P(val_type));
+      val_type = TREE_TYPE(val_type);
     }
-  gcc_assert(TREE_CODE(var_decl) == VAR_DECL);
+
   source_location loc = DECL_SOURCE_LOCATION(var_decl);
   std::string name = IDENTIFIER_POINTER(DECL_NAME(var_decl));
   name += ".pointer";
@@ -1456,14 +1319,8 @@ Function::make_receiver_parm_decl(Gogo* gogo, Named_object* no, tree var_decl)
 // indirection.
 
 tree
-Function::copy_parm_to_heap(Gogo* gogo, Named_object* no, tree ref)
+Function::copy_parm_to_heap(Gogo* gogo, Named_object* no, tree var_decl)
 {
-  if (ref == error_mark_node)
-    return error_mark_node;
-
-  gcc_assert(TREE_CODE(ref) == INDIRECT_REF);
-
-  tree var_decl = TREE_OPERAND(ref, 0);
   if (var_decl == error_mark_node)
     return error_mark_node;
   gcc_assert(TREE_CODE(var_decl) == VAR_DECL);
@@ -1514,7 +1371,8 @@ Function::build_tree(Gogo* gogo, Named_object* named_function)
     {
       if ((*p)->is_variable() && (*p)->var_value()->is_parameter())
        {
-         *pp = (*p)->get_tree(gogo, named_function);
+         Bvariable* bvar = (*p)->get_backend_variable(gogo, named_function);
+         *pp = var_to_tree(bvar);
 
          // We always pass the receiver to a method as a pointer.  If
          // the receiver is declared as a non-pointer type, then we
@@ -1524,8 +1382,6 @@ Function::build_tree(Gogo* gogo, Named_object* named_function)
            {
              tree parm_decl = this->make_receiver_parm_decl(gogo, *p, *pp);
              tree var = *pp;
-             if (TREE_CODE(var) == INDIRECT_REF)
-               var = TREE_OPERAND(var, 0);
              if (var != error_mark_node)
                {
                  gcc_assert(TREE_CODE(var) == VAR_DECL);
@@ -1539,16 +1395,12 @@ Function::build_tree(Gogo* gogo, Named_object* named_function)
              // If we take the address of a parameter, then we need
              // to copy it into the heap.
              tree parm_decl = this->copy_parm_to_heap(gogo, *p, *pp);
-             if (*pp != error_mark_node)
+             tree var = *pp;
+             if (var != error_mark_node)
                {
-                 gcc_assert(TREE_CODE(*pp) == INDIRECT_REF);
-                 tree var_decl = TREE_OPERAND(*pp, 0);
-                 if (var_decl != error_mark_node)
-                   {
-                     gcc_assert(TREE_CODE(var_decl) == VAR_DECL);
-                     DECL_CHAIN(var_decl) = declare_vars;
-                     declare_vars = var_decl;
-                   }
+                 gcc_assert(TREE_CODE(var) == VAR_DECL);
+                 DECL_CHAIN(var) = declare_vars;
+                 declare_vars = var;
                }
              *pp = parm_decl;
            }
@@ -1561,16 +1413,41 @@ Function::build_tree(Gogo* gogo, Named_object* named_function)
        }
       else if ((*p)->is_result_variable())
        {
-         tree var_decl = (*p)->get_tree(gogo, named_function);
-         if (var_decl != error_mark_node
-             && (*p)->result_var_value()->is_in_heap())
+         Bvariable* bvar = (*p)->get_backend_variable(gogo, named_function);
+         tree var_decl = var_to_tree(bvar);
+
+         Type* type = (*p)->result_var_value()->type();
+         tree init;
+         if (!(*p)->result_var_value()->is_in_heap())
+           init = type->get_init_tree(gogo, false);
+         else
            {
-             gcc_assert(TREE_CODE(var_decl) == INDIRECT_REF);
-             var_decl = TREE_OPERAND(var_decl, 0);
+             source_location loc = (*p)->location();
+             tree type_tree = type->get_tree(gogo);
+             tree space = gogo->allocate_memory(type,
+                                                TYPE_SIZE_UNIT(type_tree),
+                                                loc);
+             tree ptr_type_tree = build_pointer_type(type_tree);
+             tree subinit = type->get_init_tree(gogo, true);
+             if (subinit == NULL_TREE)
+               init = fold_convert_loc(loc, ptr_type_tree, space);
+             else
+               {
+                 space = save_expr(space);
+                 space = fold_convert_loc(loc, ptr_type_tree, space);
+                 tree spaceref = build_fold_indirect_ref_loc(loc, space);
+                 TREE_THIS_NOTRAP(spaceref) = 1;
+                 tree set = fold_build2_loc(loc, MODIFY_EXPR, void_type_node,
+                                            spaceref, subinit);
+                 init = fold_build2_loc(loc, COMPOUND_EXPR, TREE_TYPE(space),
+                                        set, space);
+               }
            }
+
          if (var_decl != error_mark_node)
            {
              gcc_assert(TREE_CODE(var_decl) == VAR_DECL);
+             DECL_INITIAL(var_decl) = init;
              DECL_CHAIN(var_decl) = declare_vars;
              declare_vars = var_decl;
            }
@@ -1769,7 +1646,15 @@ Function::return_value(Gogo* gogo, Named_object* named_function,
 
   tree retval;
   if (results->size() == 1)
-    return this->results_->front()->get_tree(gogo, named_function);
+    {
+      Bvariable* bvar =
+       this->results_->front()->get_backend_variable(gogo,
+                                                     named_function);
+      tree ret = var_to_tree(bvar);
+      if (this->results_->front()->result_var_value()->is_in_heap())
+       ret = build_fold_indirect_ref_loc(location, ret);
+      return ret;
+    }
   else
     {
       tree rettype = TREE_TYPE(DECL_RESULT(this->fndecl_));
@@ -1781,8 +1666,11 @@ Function::return_value(Gogo* gogo, Named_object* named_function,
           ++pr, ++index, field = DECL_CHAIN(field))
        {
          gcc_assert(field != NULL);
-         tree val;
-         val = (*this->results_)[index]->get_tree(gogo, named_function);
+         Named_object* no = (*this->results_)[index];
+         Bvariable* bvar = no->get_backend_variable(gogo, named_function);
+         tree val = var_to_tree(bvar);
+         if (no->result_var_value()->is_in_heap())
+           val = build_fold_indirect_ref_loc(location, val);
          tree set = fold_build2_loc(location, MODIFY_EXPR, void_type_node,
                                     build3(COMPONENT_REF, TREE_TYPE(field),
                                            retval, field, NULL_TREE),
@@ -1847,28 +1735,18 @@ Block::get_tree(Translate_context* context)
        pv != this->bindings_->end_definitions();
        ++pv)
     {
-      if ((!(*pv)->is_variable() || !(*pv)->var_value()->is_parameter())
-         && !(*pv)->is_result_variable()
-         && !(*pv)->is_const())
+      if ((*pv)->is_variable() && !(*pv)->var_value()->is_parameter())
        {
-         tree var = (*pv)->get_tree(gogo, context->function());
-         if (var != error_mark_node && TREE_TYPE(var) != error_mark_node)
-           {
-             if ((*pv)->is_variable() && (*pv)->var_value()->is_in_heap())
-               {
-                 gcc_assert(TREE_CODE(var) == INDIRECT_REF);
-                 var = TREE_OPERAND(var, 0);
-                 gcc_assert(TREE_CODE(var) == VAR_DECL);
-               }
-             *pp = var;
-             pp = &DECL_CHAIN(*pp);
-           }
+         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(context->gogo(), context->function(),
-                              this, block);
+  Translate_context subcontext(gogo, context->function(), this, block);
 
   tree statements = NULL_TREE;
 
index 91a7526..8f0d328 100644 (file)
@@ -2659,7 +2659,8 @@ Function::create_result_variables(Gogo* gogo)
          ++result_counter;
          name = gogo->pack_hidden_name(buf, false);
        }
-      Result_variable* result = new Result_variable(p->type(), this, index);
+      Result_variable* result = new Result_variable(p->type(), this, index,
+                                                   p->location());
       Named_object* no = block->bindings()->add_result_variable(name, result);
       if (no->is_result_variable())
        this->results_->push_back(no);
@@ -3290,7 +3291,7 @@ Variable::Variable(Type* type, Expression* init, bool is_global,
                   bool is_parameter, bool is_receiver,
                   source_location location)
   : type_(type), init_(init), preinit_(NULL), location_(location),
-    is_global_(is_global), is_parameter_(is_parameter),
+    backend_(NULL), is_global_(is_global), is_parameter_(is_parameter),
     is_receiver_(is_receiver), is_varargs_parameter_(false),
     is_address_taken_(false), seen_(false), init_is_lowered_(false),
     type_from_init_tuple_(false), type_from_range_index_(false),
@@ -3636,6 +3637,93 @@ Variable::import_var(Import* imp, std::string* pname, Type** ptype)
   imp->require_c_string(";\n");
 }
 
+// Convert a variable to the backend representation.
+
+Bvariable*
+Variable::get_backend_variable(Gogo* gogo, Named_object* function,
+                              const Package* package, const std::string& name)
+{
+  if (this->backend_ == NULL)
+    {
+      Backend* backend = gogo->backend();
+      Type* type = this->type_;
+      if (type->is_error_type()
+         || (type->is_undefined()
+             && (!this->is_global_ || package == NULL)))
+       this->backend_ = backend->error_variable();
+      else
+       {
+         bool is_parameter = this->is_parameter_;
+         if (this->is_receiver_ && type->points_to() == NULL)
+           is_parameter = false;
+         if (this->is_in_heap())
+           {
+             is_parameter = false;
+             type = Type::make_pointer_type(type);
+           }
+
+         std::string n = Gogo::unpack_hidden_name(name);
+         Btype* btype = tree_to_type(type->get_tree(gogo));
+
+         Bvariable* bvar;
+         if (this->is_global_)
+           bvar = backend->global_variable((package == NULL
+                                            ? gogo->package_name()
+                                            : package->name()),
+                                           (package == NULL
+                                            ? gogo->unique_prefix()
+                                            : package->unique_prefix()),
+                                           n,
+                                           btype,
+                                           package != NULL,
+                                           Gogo::is_hidden_name(name),
+                                           this->location_);
+         else
+           {
+             tree fndecl = function->func_value()->get_decl();
+             Bfunction* bfunction = tree_to_function(fndecl);
+             if (is_parameter)
+               bvar = backend->parameter_variable(bfunction, n, btype,
+                                                  this->location_);
+             else
+               bvar = backend->local_variable(bfunction, n, btype,
+                                              this->location_);
+           }
+         this->backend_ = bvar;
+       }
+    }
+  return this->backend_;
+}
+
+// Class Result_variable.
+
+// Convert a result variable to the backend representation.
+
+Bvariable*
+Result_variable::get_backend_variable(Gogo* gogo, Named_object* function,
+                                     const std::string& name)
+{
+  if (this->backend_ == NULL)
+    {
+      Backend* backend = gogo->backend();
+      Type* type = this->type_;
+      if (type->is_error())
+       this->backend_ = backend->error_variable();
+      else
+       {
+         if (this->is_in_heap())
+           type = Type::make_pointer_type(type);
+         Btype* btype = tree_to_type(type->get_tree(gogo));
+         tree fndecl = function->func_value()->get_decl();
+         Bfunction* bfunction = tree_to_function(fndecl);
+         std::string n = Gogo::unpack_hidden_name(name);
+         this->backend_ = backend->local_variable(bfunction, n, btype,
+                                                  this->location_);
+       }
+    }
+  return this->backend_;
+}
+
 // Class Named_constant.
 
 // Traverse the initializer expression.
@@ -3997,7 +4085,7 @@ Named_object::location() const
       return this->var_value()->location();
 
     case NAMED_OBJECT_RESULT_VAR:
-      return this->result_var_value()->function()->location();
+      return this->result_var_value()->location();
 
     case NAMED_OBJECT_SINK:
       gcc_unreachable();
@@ -4057,6 +4145,21 @@ Named_object::export_named_object(Export* exp) const
     }
 }
 
+// Convert a variable to the backend representation.
+
+Bvariable*
+Named_object::get_backend_variable(Gogo* gogo, Named_object* function)
+{
+  if (this->classification_ == NAMED_OBJECT_VAR)
+    return this->var_value()->get_backend_variable(gogo, function,
+                                                  this->package_, this->name_);
+  else if (this->classification_ == NAMED_OBJECT_RESULT_VAR)
+    return this->result_var_value()->get_backend_variable(gogo, function,
+                                                         this->name_);
+  else
+    gcc_unreachable();
+}
+
 // Class Bindings.
 
 Bindings::Bindings(Bindings* enclosing)
index b622d04..cb6501e 100644 (file)
@@ -43,6 +43,7 @@ class Export;
 class Import;
 class Bexpression;
 class Bstatement;
+class Bvariable;
 class Blabel;
 
 // This file declares the basic classes used to hold the internal
@@ -1270,6 +1271,11 @@ class Variable
   set_address_taken()
   { this->is_address_taken_ = true; }
 
+  // Get the backend representation of the variable.
+  Bvariable*
+  get_backend_variable(Gogo*, Named_object*, const Package*,
+                      const std::string&);
+
   // Get the initial value of the variable as a tree.  This may only
   // be called if has_pre_init() returns false.
   tree
@@ -1312,6 +1318,8 @@ class Variable
   Block* preinit_;
   // Location of variable definition.
   source_location location_;
+  // Backend representation.
+  Bvariable* backend_;
   // Whether this is a global variable.
   bool is_global_ : 1;
   // Whether this is a function parameter.
@@ -1346,9 +1354,10 @@ class Variable
 class Result_variable
 {
  public:
-  Result_variable(Type* type, Function* function, int index)
-    : type_(type), function_(function), index_(index),
-      is_address_taken_(false)
+  Result_variable(Type* type, Function* function, int index,
+                 source_location location)
+    : type_(type), function_(function), index_(index), location_(location),
+      backend_(NULL), is_address_taken_(false)
   { }
 
   // Get the type of the result variable.
@@ -1366,6 +1375,11 @@ class Result_variable
   index() const
   { return this->index_; }
 
+  // The location of the variable definition.
+  source_location
+  location() const
+  { return this->location_; }
+
   // Whether this variable's address is taken.
   bool
   is_address_taken() const
@@ -1387,6 +1401,10 @@ class Result_variable
   set_function(Function* function)
   { this->function_ = function; }
 
+  // Get the backend representation of the variable.
+  Bvariable*
+  get_backend_variable(Gogo*, Named_object*, const std::string&);
+
  private:
   // Type of result variable.
   Type* type_;
@@ -1394,6 +1412,10 @@ class Result_variable
   Function* function_;
   // Index in list of results.
   int index_;
+  // Where the result variable is defined.
+  source_location location_;
+  // Backend representation.
+  Bvariable* backend_;
   // Whether something takes the address of this variable.
   bool is_address_taken_;
 };
@@ -1868,6 +1890,10 @@ class Named_object
   source_location
   location() const;
 
+  // Convert a variable to the backend representation.
+  Bvariable*
+  get_backend_variable(Gogo*, Named_object* function);
+
   // Return a tree for the external identifier for this object.
   tree
   get_id(Gogo*);
index 8e00d37..fde3f62 100644 (file)
@@ -251,37 +251,46 @@ Variable_declaration_statement::do_traverse_assignments(
 tree
 Variable_declaration_statement::do_get_tree(Translate_context* context)
 {
-  tree val = this->var_->get_tree(context->gogo(), context->function());
-  if (val == error_mark_node || TREE_TYPE(val) == error_mark_node)
-    return error_mark_node;
-  Variable* variable = this->var_->var_value();
-
-  tree init = variable->get_init_tree(context->gogo(), context->function());
-  if (init == error_mark_node)
-    return error_mark_node;
-
-  // If this variable lives on the heap, we need to allocate it now.
-  if (!variable->is_in_heap())
+  Variable* var = this->var_->var_value();
+  Bvariable* bvar = this->var_->get_backend_variable(context->gogo(),
+                                                    context->function());
+  tree init = var->get_init_tree(context->gogo(), context->function());
+  Bexpression* binit = init == NULL_TREE ? NULL : tree_to_expr(init);
+  Bstatement* ret;
+  if (!var->is_in_heap())
     {
-      DECL_INITIAL(val) = init;
-      return this->build_stmt_1(DECL_EXPR, val);
+      gcc_assert(binit != NULL);
+      ret = context->backend()->init_statement(bvar, binit);
     }
   else
     {
-      gcc_assert(TREE_CODE(val) == INDIRECT_REF);
-      tree decl = TREE_OPERAND(val, 0);
-      gcc_assert(TREE_CODE(decl) == VAR_DECL);
-      tree type = TREE_TYPE(decl);
-      gcc_assert(POINTER_TYPE_P(type));
-      tree size = TYPE_SIZE_UNIT(TREE_TYPE(type));
-      tree space = context->gogo()->allocate_memory(variable->type(), size,
-                                                   this->location());
-      space = fold_convert(TREE_TYPE(decl), space);
-      DECL_INITIAL(decl) = space;
-      return build2(COMPOUND_EXPR, void_type_node,
-                   this->build_stmt_1(DECL_EXPR, decl),
-                   build2(MODIFY_EXPR, void_type_node, val, init));
+      // Something takes the address of this variable, so the value is
+      // stored in the heap.  Initialize it to newly allocated memory
+      // space, and assign the initial value to the new space.
+      source_location loc = this->location();
+      tree decl = var_to_tree(bvar);
+      tree decl_type = TREE_TYPE(decl);
+      gcc_assert(POINTER_TYPE_P(decl_type));
+      tree size = TYPE_SIZE_UNIT(TREE_TYPE(decl_type));
+      tree space = context->gogo()->allocate_memory(var->type(), size, loc);
+      if (binit != NULL)
+       space = save_expr(space);
+      space = fold_convert_loc(loc, decl_type, space);
+      Bstatement* s1 = context->backend()->init_statement(bvar,
+                                                         tree_to_expr(space));
+      if (binit == NULL)
+       ret = s1;
+      else
+       {
+         tree indir = build_fold_indirect_ref_loc(loc, space);
+         Bexpression* bindir = tree_to_expr(indir);
+         Bstatement* s2 = context->backend()->assignment_statement(bindir,
+                                                                   binit,
+                                                                   loc);
+         ret = context->backend()->compound_statement(s1, s2);
+       }
     }
+  return stat_to_tree(ret);
 }
 
 // Make a variable declaration.
@@ -2421,6 +2430,8 @@ Return_statement::do_lower(Gogo*, Named_object* function, Block* enclosing)
 tree
 Return_statement::do_get_tree(Translate_context* context)
 {
+  source_location loc = this->location();
+
   Function* function = context->function()->func_value();
   tree fndecl = function->get_decl();
 
@@ -2433,14 +2444,14 @@ Return_statement::do_get_tree(Translate_context* context)
           p != results->end();
           p++)
        {
-         tree rv = (*p)->get_tree(context->gogo(), context->function());
-         retvals.push_back(tree_to_expr(rv));
+         Expression* vr = Expression::make_var_reference(*p, loc);
+         retvals.push_back(tree_to_expr(vr->get_tree(context)));
        }
     }
 
   Bstatement* ret;
   ret = context->backend()->return_statement(tree_to_function(fndecl),
-                                            retvals, this->location());
+                                            retvals, loc);
   return stat_to_tree(ret);
 }