]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
compiler: Use backend interface for slice construction.
authorChris Manghane <cmang@google.com>
Tue, 6 May 2014 00:11:29 +0000 (00:11 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Tue, 6 May 2014 00:11:29 +0000 (00:11 +0000)
* go-gcc.cc (Gcc_backend::implicit_variable): Rename from
gc_root_variable.  Add name and is_constant parameters.

From-SVN: r210088

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

index 4e4afdb64baf3aa7ab0736f8094df7786918aaab..8fe468f9b3dd364b811ce30dca5213e763e2839a 100644 (file)
@@ -1,3 +1,8 @@
+2014-05-05  Chris Manghane  <cmang@google.com>
+
+       * go-gcc.cc (Gcc_backend::implicit_variable): Rename from
+       gc_root_variable.  Add name and is_constant parameters.
+
 2014-05-05  Chris Manghane  <cmang@google.com>
 
        * go-gcc.cc (Gcc_backend::indirect_expression): Add btype
index 343661ec9d28874d304d7dd0abbd580e6df2357f..3d9fc8e369a5ba34e7552d376ba57d5ed0fee82e 100644 (file)
@@ -381,7 +381,7 @@ class Gcc_backend : public Backend
                     Location, Bstatement**);
 
   Bvariable*
-  gc_root_variable(Btype*, Bexpression*);
+  implicit_variable(const std::string&, Btype*, Bexpression*, bool);
 
   Bvariable*
   immutable_struct(const std::string&, bool, bool, Btype*, Location);
@@ -2476,10 +2476,12 @@ Gcc_backend::temporary_variable(Bfunction* function, Bblock* bblock,
   return new Bvariable(var);
 }
 
-// Make a GC root variable.
+// Create an implicit variable that is compiler-defined.  This is used when
+// generating GC root variables and storing the values of a slice initializer.
 
 Bvariable*
-Gcc_backend::gc_root_variable(Btype* type, Bexpression* init)
+Gcc_backend::implicit_variable(const std::string& name, Btype* type,
+                              Bexpression* init, bool is_constant)
 {
   tree type_tree = type->get_tree();
   tree init_tree = init->get_tree();
@@ -2487,11 +2489,16 @@ Gcc_backend::gc_root_variable(Btype* type, Bexpression* init)
     return this->error_variable();
 
   tree decl = build_decl(BUILTINS_LOCATION, VAR_DECL,
-                         create_tmp_var_name("gc"), type_tree);
+                         get_identifier_from_string(name), type_tree);
   DECL_EXTERNAL(decl) = 0;
   TREE_PUBLIC(decl) = 0;
   TREE_STATIC(decl) = 1;
   DECL_ARTIFICIAL(decl) = 1;
+  if (is_constant)
+    {
+      TREE_READONLY(decl) = 1;
+      TREE_CONSTANT(decl) = 1;
+    }
   DECL_INITIAL(decl) = init_tree;
   rest_of_decl_compilation(decl, 1, 0);
 
index e49cedf54cc16b0bfbff1812ed777fcf5e7f5886..95f494accfc3d2271b185132dc5c5f0505f9021a 100644 (file)
@@ -536,11 +536,16 @@ class Backend
                     bool address_is_taken, Location location,
                     Bstatement** pstatement) = 0;
 
-  // Create a GC root variable. TYPE is the __go_gc_root_list struct described
-  // in Gogo::register_gc_vars.  INIT is the composite literal consisting of a
-  // pointer to the next GC root and the global variables registered.
+  // Create an implicit variable that is compiler-defined.  This is used when
+  // generating GC root variables and storing the values of a slice constructor.
+  // NAME is the name of the variable, either gc# for GC roots or C# for slice
+  // initializers.  TYPE is the type of the implicit variable with an initial
+  // value INIT.  IS_CONSTANT is true if the implicit variable should be treated
+  // like it is immutable.  For slice initializers, if the values must be copied
+  // to the heap, the variable IS_CONSTANT.
   virtual Bvariable*
-  gc_root_variable(Btype* type, Bexpression* init) = 0;
+  implicit_variable(const std::string& name, Btype* type, Bexpression* init,
+                   bool is_constant) = 0;
 
   // Create a named immutable initialized data structure.  This is
   // used for type descriptors, map descriptors, and function
index b1d9bcc9839c97a1647cda1fc3db9897eb335b15..9381764e1439609a2d16e2ab798b6752089f726e 100644 (file)
@@ -4113,20 +4113,47 @@ Unary_expression::do_get_tree(Translate_context* context)
            }
        }
 
-      if (this->is_gc_root_)
+      static unsigned int counter;
+      char buf[100];
+      if (this->is_gc_root_ || this->is_slice_init_)
        {
-         // Build a decl for a GC root variable.  GC roots are mutable, so they
-         // cannot be represented as an immutable_struct in the backend.
-         Bvariable* gc_root = gogo->backend()->gc_root_variable(btype, bexpr);
-         bexpr = gogo->backend()->var_expression(gc_root, loc);
+         bool copy_to_heap = false;
+         if (this->is_gc_root_)
+           {
+             // Build a decl for a GC root variable.  GC roots are mutable, so
+             // they cannot be represented as an immutable_struct in the
+             // backend.
+             static unsigned int root_counter;
+             snprintf(buf, sizeof buf, "gc%u", root_counter);
+             ++root_counter;
+           }
+         else
+           {
+             // Build a decl for a slice value initializer.  An immutable slice
+             // value initializer may have to be copied to the heap if it
+             // contains pointers in a non-constant context.
+             snprintf(buf, sizeof buf, "C%u", counter);
+             ++counter;
+
+             Array_type* at = this->expr_->type()->array_type();
+             go_assert(at != NULL);
+
+             // If we are not copying the value to the heap, we will only
+             // initialize the value once, so we can use this directly
+             // rather than copying it.  In that case we can't make it
+             // read-only, because the program is permitted to change it.
+             copy_to_heap = (at->element_type()->has_pointer()
+                             && !context->is_const());
+           }
+         Bvariable* implicit =
+           gogo->backend()->implicit_variable(buf, btype, bexpr, copy_to_heap);
+         bexpr = gogo->backend()->var_expression(implicit, loc);
        }
       else if ((this->expr_->is_composite_literal()
            || this->expr_->string_expression() != NULL)
           && this->expr_->is_immutable())
         {
          // Build a decl for a constant constructor.
-          static unsigned int counter;
-          char buf[100];
           snprintf(buf, sizeof buf, "C%u", counter);
           ++counter;
 
@@ -12450,6 +12477,7 @@ Slice_construction_expression::do_get_tree(Translate_context* context)
       return error_mark_node;
     }
 
+  Location loc = this->location();
   Type* element_type = array_type->element_type();
   if (this->valtype_ == NULL)
     {
@@ -12464,35 +12492,24 @@ Slice_construction_expression::do_get_tree(Translate_context* context)
           else
             mpz_init_set_ui(lenval, this->indexes()->back() + 1);
         }
-      Location loc = this->location();
       Type* int_type = Type::lookup_integer_type("int");
       length = Expression::make_integer(&lenval, int_type, loc);
       mpz_clear(lenval);
       this->valtype_ = Type::make_array_type(element_type, length);
     }
 
-  tree values;
-  Gogo* gogo = context->gogo();
-  Btype* val_btype = this->valtype_->get_backend(gogo);
+  Expression_list* vals = this->vals();
   if (this->vals() == NULL || this->vals()->empty())
     {
-      // We need to create a unique value.
-      Btype* int_btype = Type::lookup_integer_type("int")->get_backend(gogo);
-      Bexpression* zero = gogo->backend()->zero_expression(int_btype);
-      std::vector<unsigned long> index(1, 0);
-      std::vector<Bexpression*> val(1, zero);
-      Bexpression* ctor =
-       gogo->backend()->array_constructor_expression(val_btype, index, val,
-                                                     this->location());
-      values = expr_to_tree(ctor);
+      // We need to create a unique value for the empty array literal.
+      vals = new Expression_list;
+      vals->push_back(NULL);
     }
-  else
-    values = expr_to_tree(this->get_constructor(context, val_btype));
-
-  if (values == error_mark_node)
-    return error_mark_node;
+  Expression* array_val =
+    new Fixed_array_construction_expression(this->valtype_, this->indexes(),
+                                           vals, loc);
 
-  bool is_constant_initializer = TREE_CONSTANT(values);
+  bool is_constant_initializer = array_val->is_immutable();
 
   // We have to copy the initial values into heap memory if we are in
   // a function or if the values are not constants.  We also have to
@@ -12503,89 +12520,22 @@ Slice_construction_expression::do_get_tree(Translate_context* context)
                       || (element_type->has_pointer()
                           && !context->is_const()));
 
-  if (is_constant_initializer)
-    {
-      tree tmp = build_decl(this->location().gcc_location(), VAR_DECL,
-                           create_tmp_var_name("C"), TREE_TYPE(values));
-      DECL_EXTERNAL(tmp) = 0;
-      TREE_PUBLIC(tmp) = 0;
-      TREE_STATIC(tmp) = 1;
-      DECL_ARTIFICIAL(tmp) = 1;
-      if (copy_to_heap)
-       {
-         // If we are not copying the value to the heap, we will only
-         // initialize the value once, so we can use this directly
-         // rather than copying it.  In that case we can't make it
-         // read-only, because the program is permitted to change it.
-         TREE_READONLY(tmp) = 1;
-         TREE_CONSTANT(tmp) = 1;
-       }
-      DECL_INITIAL(tmp) = values;
-      rest_of_decl_compilation(tmp, 1, 0);
-      values = tmp;
-    }
-
-  tree space;
-  tree set;
+  Expression* space;
   if (!copy_to_heap)
     {
-      // the initializer will only run once.
-      space = build_fold_addr_expr(values);
-      set = NULL_TREE;
+      // The initializer will only run once.
+      space = Expression::make_unary(OPERATOR_AND, array_val, loc);
+      space->unary_expression()->set_is_slice_init();
     }
   else
-    {
-      Expression* alloc =
-          context->gogo()->allocate_memory(this->valtype_, this->location());
-      space = save_expr(alloc->get_tree(context));
-
-      tree s = fold_convert(build_pointer_type(TREE_TYPE(values)), space);
-      tree ref = build_fold_indirect_ref_loc(this->location().gcc_location(),
-                                             s);
-      TREE_THIS_NOTRAP(ref) = 1;
-      set = build2(MODIFY_EXPR, void_type_node, ref, values);
-    }
+    space = Expression::make_heap_expression(array_val, loc);
 
   // Build a constructor for the slice.
 
-  tree type_tree = type_to_tree(this->type()->get_backend(context->gogo()));
-  if (type_tree == error_mark_node)
-    return error_mark_node;
-  go_assert(TREE_CODE(type_tree) == RECORD_TYPE);
-
-  vec<constructor_elt, va_gc> *init;
-  vec_alloc(init, 3);
-
-  constructor_elt empty = {NULL, NULL};
-  constructor_elt* elt = init->quick_push(empty);
-  tree field = TYPE_FIELDS(type_tree);
-  go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__values") == 0);
-  elt->index = field;
-  elt->value = fold_convert(TREE_TYPE(field), space);
-
-  tree length_tree = this->valtype_->array_type()->length()->get_tree(context);
-  elt = init->quick_push(empty);
-  field = DECL_CHAIN(field);
-  go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__count") == 0);
-  elt->index = field;
-  elt->value = fold_convert(TREE_TYPE(field), length_tree);
-
-  elt = init->quick_push(empty);
-  field = DECL_CHAIN(field);
-  go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)),"__capacity") == 0);
-  elt->index = field;
-  elt->value = fold_convert(TREE_TYPE(field), length_tree);
-
-  tree constructor = build_constructor(type_tree, init);
-  if (constructor == error_mark_node)
-    return error_mark_node;
-  if (!copy_to_heap)
-    TREE_CONSTANT(constructor) = 1;
-
-  if (set == NULL_TREE)
-    return constructor;
-  else
-    return build2(COMPOUND_EXPR, type_tree, set, constructor);
+  Expression* len = this->valtype_->array_type()->length();
+  Expression* slice_val =
+    Expression::make_slice_value(this->type(), space, len, len, loc);
+  return slice_val->get_tree(context);
 }
 
 // Make a slice composite literal.  This is used by the type
@@ -14802,6 +14752,10 @@ class Struct_field_offset_expression : public Expression
   { }
 
  protected:
+  bool
+  do_is_immutable() const
+  { return true; }
+
   Type*
   do_type()
   { return Type::lookup_integer_type("uintptr"); }
index 0936e00bae0eae4ea75fd9fbd87c622104f30980..6f03e02a8c6d984bf688db5880f6e1c3fdddce78 100644 (file)
@@ -1305,7 +1305,7 @@ class Unary_expression : public Expression
   Unary_expression(Operator op, Expression* expr, Location location)
     : Expression(EXPRESSION_UNARY, location),
       op_(op), escapes_(true), create_temp_(false), is_gc_root_(false),
-      expr_(expr), issue_nil_check_(false)
+      is_slice_init_(false), expr_(expr), issue_nil_check_(false)
   { }
 
   // Return the operator.
@@ -1344,6 +1344,15 @@ class Unary_expression : public Expression
     this->is_gc_root_ = true;
   }
 
+  // Record that this is an address expression of a slice value initializer,
+  // which is mutable if the values are not copied to the heap.
+  void
+  set_is_slice_init()
+  {
+    go_assert(this->op_ == OPERATOR_AND);
+    this->is_slice_init_ = true;
+  }
+
   // Apply unary opcode OP to UNC, setting NC.  Return true if this
   // could be done, false if not.  Issue errors for overflow.
   static bool
@@ -1427,6 +1436,11 @@ class Unary_expression : public Expression
   // special struct composite literal that is mutable when addressed, meaning
   // it cannot be represented as an immutable_struct in the backend.
   bool is_gc_root_;
+  // True if this is an address expression for a slice value with an immutable
+  // initializer.  The initializer for a slice's value pointer has an array
+  // type, meaning it cannot be represented as an immutable_struct in the
+  // backend.
+  bool is_slice_init_;
   // The operand.
   Expression* expr_;
   // Whether or not to issue a nil check for this expression if its address