This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Go patch committed: Use backend interface for slice construction


This patch by Chris Manghane changes the Go frontend to use the backend
interface for slice construction.  Bootstrapped and ran Go testsuite on
x86_64-unknown-linux-gnu.  Committed to mainline.

Ian


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.


Index: gcc/go/gofrontend/expressions.h
===================================================================
--- gcc/go/gofrontend/expressions.h	(revision 209819)
+++ gcc/go/gofrontend/expressions.h	(working copy)
@@ -1305,7 +1305,7 @@ class Unary_expression : public Expressi
   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 Expressi
     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 Expressi
   // 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
Index: gcc/go/gofrontend/backend.h
===================================================================
--- gcc/go/gofrontend/backend.h	(revision 210087)
+++ gcc/go/gofrontend/backend.h	(working copy)
@@ -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: gcc/go/gofrontend/expressions.cc
===================================================================
--- gcc/go/gofrontend/expressions.cc	(revision 210087)
+++ gcc/go/gofrontend/expressions.cc	(working copy)
@@ -4113,20 +4113,47 @@ Unary_expression::do_get_tree(Translate_
 	    }
 	}
 
-      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.
-	  Bvariable* gc_root = gogo->backend()->gc_root_variable(btype, bexpr);
-	  bexpr = gogo->backend()->var_expression(gc_root, loc);
+      static unsigned int counter;
+      char buf[100];
+      if (this->is_gc_root_ || this->is_slice_init_)
+	{
+	  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_tr
       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_tr
           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);
-    }
-  else
-    values = expr_to_tree(this->get_constructor(context, val_btype));
-
-  if (values == error_mark_node)
-    return error_mark_node;
+      // We need to create a unique value for the empty array literal.
+      vals = new Expression_list;
+      vals->push_back(NULL);
+    }
+  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_tr
 		       || (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 : p
   { }
 
  protected:
+  bool
+  do_is_immutable() const
+  { return true; }
+
   Type*
   do_type()
   { return Type::lookup_integer_type("uintptr"); }
Index: gcc/go/go-gcc.cc
===================================================================
--- gcc/go/go-gcc.cc	(revision 210087)
+++ gcc/go/go-gcc.cc	(working copy)
@@ -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(Bfunctio
   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* typ
     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 Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]