compiler: move slice construction to callers of makeslice
authorIan Lance Taylor <ian@gcc.gnu.org>
Mon, 7 Jan 2019 21:44:06 +0000 (21:44 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Mon, 7 Jan 2019 21:44:06 +0000 (21:44 +0000)
    This is the gccgo version of https://golang.org/cl/141822:

        Only return a pointer p to the new slices backing array from makeslice.
        Makeslice callers then construct sliceheader{p, len, cap} explictly
        instead of makeslice returning the slice.

    This change caused the GCC backend to break the runtime/pprof test by
    merging together the identical functions allocateReflectTransient and
    allocateTransient2M.  This caused the traceback to be other than
    expected.  Fix that by making the functions not identical.

    This is a step toward updating libgo to the Go1.12beta1 release.

    Reviewed-on: https://go-review.googlesource.com/c/155937

From-SVN: r267660

gcc/go/gofrontend/MERGE
gcc/go/gofrontend/escape.cc
gcc/go/gofrontend/expressions.cc
gcc/go/gofrontend/expressions.h
gcc/go/gofrontend/runtime.def
gcc/go/gofrontend/wb.cc
libgo/go/runtime/pprof/mprof_test.go
libgo/go/runtime/slice.go

index d6fe5f6afb969fb478311d436d849f37e98b0d10..7c7370a5954af1a1868994ef4c3286f167743e24 100644 (file)
@@ -1,4 +1,4 @@
-c257303eaef143663216e483857d5b259e05753f
+c8a9bccbc524381d150c84907a61ac257c1b07cc
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
index b56b4d0b57dc8e64be69487c76999f602f2eeb7d..e1c98094831f3de097424856116c212bf65d34ee 100644 (file)
@@ -1737,6 +1737,16 @@ Escape_analysis_assign::expression(Expression** pexpr)
       }
       break;
 
+    case Expression::EXPRESSION_SLICE_VALUE:
+      {
+       // Connect the pointer field to the slice value.
+       Node* slice_node = Node::make_node(*pexpr);
+       Node* ptr_node =
+         Node::make_node((*pexpr)->slice_value_expression()->valmem());
+       this->assign(slice_node, ptr_node);
+      }
+      break;
+
     case Expression::EXPRESSION_HEAP:
       {
        Node* pointer_node = Node::make_node(*pexpr);
@@ -2263,6 +2273,8 @@ Escape_analysis_assign::assign(Node* dst, Node* src)
          // DST = map[T]V{...}.
        case Expression::EXPRESSION_STRUCT_CONSTRUCTION:
          // DST = T{...}.
+       case Expression::EXPRESSION_SLICE_VALUE:
+         // DST = slice{ptr, len, cap}
        case Expression::EXPRESSION_ALLOCATION:
          // DST = new(T).
        case Expression::EXPRESSION_BOUND_METHOD:
index ef8a917c290c757ed3c9a2b97f8d8fd653021642..71f18002733d810fb0016ba23d23b6094fa765e8 100644 (file)
@@ -7787,21 +7787,29 @@ Builtin_call_expression::lower_make(Statement_inserter* inserter)
   Expression* call;
   if (is_slice)
     {
+      Temporary_statement* len_temp = NULL;
+      if (!len_arg->is_constant())
+       {
+         len_temp = Statement::make_temporary(NULL, len_arg, loc);
+         inserter->insert(len_temp);
+         len_arg = Expression::make_temporary_reference(len_temp, loc);
+       }
+
       if (cap_arg == NULL)
        {
           cap_small = len_small;
-          if (len_arg->numeric_constant_value(&nclen)
-              && nclen.to_unsigned_long(&vlen) == Numeric_constant::NC_UL_VALID)
-            cap_arg = Expression::make_integer_ul(vlen, len_arg->type(), loc);
-          else
-            {
-              Temporary_statement* temp = Statement::make_temporary(NULL,
-                                                                    len_arg,
-                                                                    loc);
-              inserter->insert(temp);
-              len_arg = Expression::make_temporary_reference(temp, loc);
-              cap_arg = Expression::make_temporary_reference(temp, loc);
-            }
+         if (len_temp == NULL)
+           cap_arg = len_arg->copy();
+         else
+           cap_arg = Expression::make_temporary_reference(len_temp, loc);
+       }
+      else if (!cap_arg->is_constant())
+       {
+         Temporary_statement* cap_temp = Statement::make_temporary(NULL,
+                                                                   cap_arg,
+                                                                   loc);
+         inserter->insert(cap_temp);
+         cap_arg = Expression::make_temporary_reference(cap_temp, loc);
        }
 
       Type* et = type->array_type()->element_type();
@@ -7809,7 +7817,12 @@ Builtin_call_expression::lower_make(Statement_inserter* inserter)
       Runtime::Function code = Runtime::MAKESLICE;
       if (!len_small || !cap_small)
        code = Runtime::MAKESLICE64;
-      call = Runtime::make_call(code, loc, 3, type_arg, len_arg, cap_arg);
+      Expression* mem = Runtime::make_call(code, loc, 3, type_arg, len_arg,
+                                          cap_arg);
+      mem = Expression::make_unsafe_cast(Type::make_pointer_type(et), mem,
+                                        loc);
+      call = Expression::make_slice_value(type, mem, len_arg->copy(),
+                                         cap_arg->copy(), loc);
     }
   else if (is_map)
     {
@@ -13585,9 +13598,13 @@ Slice_construction_expression::do_get_backend(Translate_context* context)
       go_assert(this->storage_escapes_ || this->element_count() == 0);
       space = Expression::make_heap_expression(this->array_val_, loc);
     }
+  Array_type* at = this->valtype_->array_type();
+  Type* et = at->element_type();
+  space = Expression::make_unsafe_cast(Type::make_pointer_type(et),
+                                      space, loc);
 
   // Build a constructor for the slice.
-  Expression* len = this->valtype_->array_type()->length();
+  Expression* len = at->length();
   Expression* slice_val =
     Expression::make_slice_value(this->type(), space, len, len, loc);
   return slice_val->get_backend(context);
@@ -15354,72 +15371,33 @@ Expression::make_slice_info(Expression* slice, Slice_info slice_info,
   return new Slice_info_expression(slice, slice_info, location);
 }
 
-// An expression that represents a slice value: a struct with value pointer,
-// length, and capacity fields.
-
-class Slice_value_expression : public Expression
-{
- public:
-  Slice_value_expression(Type* type, Expression* valptr, Expression* len,
-                         Expression* cap, Location location)
-      : Expression(EXPRESSION_SLICE_VALUE, location),
-        type_(type), valptr_(valptr), len_(len), cap_(cap)
-  { }
-
- protected:
-  int
-  do_traverse(Traverse*);
-
-  Type*
-  do_type()
-  { return this->type_; }
-
-  void
-  do_determine_type(const Type_context*)
-  { go_unreachable(); }
-
-  Expression*
-  do_copy()
-  {
-    return new Slice_value_expression(this->type_->copy_expressions(),
-                                     this->valptr_->copy(),
-                                      this->len_->copy(), this->cap_->copy(),
-                                      this->location());
-  }
-
-  Bexpression*
-  do_get_backend(Translate_context* context);
-
-  void
-  do_dump_expression(Ast_dump_context*) const;
-
- private:
-  // The type of the slice value.
-  Type* type_;
-  // The pointer to the values in the slice.
-  Expression* valptr_;
-  // The length of the slice.
-  Expression* len_;
-  // The capacity of the slice.
-  Expression* cap_;
-};
+// Class Slice_value_expression.
 
 int
 Slice_value_expression::do_traverse(Traverse* traverse)
 {
   if (Type::traverse(this->type_, traverse) == TRAVERSE_EXIT
-      || Expression::traverse(&this->valptr_, traverse) == TRAVERSE_EXIT
+      || Expression::traverse(&this->valmem_, traverse) == TRAVERSE_EXIT
       || Expression::traverse(&this->len_, traverse) == TRAVERSE_EXIT
       || Expression::traverse(&this->cap_, traverse) == TRAVERSE_EXIT)
     return TRAVERSE_EXIT;
   return TRAVERSE_CONTINUE;
 }
 
+Expression*
+Slice_value_expression::do_copy()
+{
+  return new Slice_value_expression(this->type_->copy_expressions(),
+                                   this->valmem_->copy(),
+                                   this->len_->copy(), this->cap_->copy(),
+                                   this->location());
+}
+
 Bexpression*
 Slice_value_expression::do_get_backend(Translate_context* context)
 {
   std::vector<Bexpression*> vals(3);
-  vals[0] = this->valptr_->get_backend(context);
+  vals[0] = this->valmem_->get_backend(context);
   vals[1] = this->len_->get_backend(context);
   vals[2] = this->cap_->get_backend(context);
 
@@ -15434,7 +15412,7 @@ Slice_value_expression::do_dump_expression(
 {
   ast_dump_context->ostream() << "slicevalue(";
   ast_dump_context->ostream() << "values: ";
-  this->valptr_->dump_expression(ast_dump_context);
+  this->valmem_->dump_expression(ast_dump_context);
   ast_dump_context->ostream() << ", length: ";
   this->len_->dump_expression(ast_dump_context);
   ast_dump_context->ostream() << ", capacity: ";
@@ -15443,11 +15421,14 @@ Slice_value_expression::do_dump_expression(
 }
 
 Expression*
-Expression::make_slice_value(Type* at, Expression* valptr, Expression* len,
+Expression::make_slice_value(Type* at, Expression* valmem, Expression* len,
                              Expression* cap, Location location)
 {
   go_assert(at->is_slice_type());
-  return new Slice_value_expression(at, valptr, len, cap, location);
+  go_assert(valmem->is_nil_expression()
+           || (at->array_type()->element_type()
+               == valmem->type()->points_to()));
+  return new Slice_value_expression(at, valmem, len, cap, location);
 }
 
 // An expression that evaluates to some characteristic of a non-empty interface.
index a18322cfb91a4866e3dc14f5a7b16ec50e962a80..db40d8d0d213c6e7571ea47a627007b678e709cf 100644 (file)
@@ -61,6 +61,7 @@ class Map_construction_expression;
 class Type_guard_expression;
 class Heap_expression;
 class Receive_expression;
+class Slice_value_expression;
 class Conditional_expression;
 class Compound_expression;
 class Numeric_constant;
@@ -841,6 +842,12 @@ class Expression
   receive_expression()
   { return this->convert<Receive_expression, EXPRESSION_RECEIVE>(); }
 
+  // If this is a slice value expression, return the Slice_valiue_expression
+  // structure.  Otherwise, return NULL.
+  Slice_value_expression*
+  slice_value_expression()
+  { return this->convert<Slice_value_expression, EXPRESSION_SLICE_VALUE>(); }
+
   // If this is a conditional expression, return the Conditional_expression
   // structure.  Otherwise, return NULL.
   Conditional_expression*
@@ -3955,6 +3962,56 @@ class Receive_expression : public Expression
   Temporary_statement* temp_receiver_;
 };
 
+// An expression that represents a slice value: a struct with value pointer,
+// length, and capacity fields.
+
+class Slice_value_expression : public Expression
+{
+ public:
+  Slice_value_expression(Type* type, Expression* valmem, Expression* len,
+                         Expression* cap, Location location)
+    : Expression(EXPRESSION_SLICE_VALUE, location),
+      type_(type), valmem_(valmem), len_(len), cap_(cap)
+  { }
+
+  // The memory holding the values in the slice.  The type should be a
+  // pointer to the element value of the slice.
+  Expression*
+  valmem() const
+  { return this->valmem_; }
+
+ protected:
+  int
+  do_traverse(Traverse*);
+
+  Type*
+  do_type()
+  { return this->type_; }
+
+  void
+  do_determine_type(const Type_context*)
+  { }
+
+  Expression*
+  do_copy();
+
+  Bexpression*
+  do_get_backend(Translate_context* context);
+
+  void
+  do_dump_expression(Ast_dump_context*) const;
+
+ private:
+  // The type of the slice value.
+  Type* type_;
+  // The memory holding the values in the slice.
+  Expression* valmem_;
+  // The length of the slice.
+  Expression* len_;
+  // The capacity of the slice.
+  Expression* cap_;
+};
+
 // Conditional expressions.
 
 class Conditional_expression : public Expression
index ed759e80780ddbfe0733e859762b06b8ccee629a..ded62514832a2a429deefa1fff309e6320a3423a 100644 (file)
@@ -85,10 +85,10 @@ DEF_GO_RUNTIME(COMPLEX128_DIV, "__go_complex128_div",
 
 // Make a slice.
 DEF_GO_RUNTIME(MAKESLICE, "runtime.makeslice", P3(TYPE, INT, INT),
-              R1(SLICE))
+              R1(POINTER))
 
 DEF_GO_RUNTIME(MAKESLICE64, "runtime.makeslice64", P3(TYPE, INT64, INT64),
-              R1(SLICE))
+              R1(POINTER))
 
 
 // Make a map with a hint and an (optional, unused) map structure.
index ccd318d0440d238a3dd3560a26bff2db949735d0..8620e405b2e34e67ab5e3a13c143a3ec05b2831c 100644 (file)
@@ -41,6 +41,9 @@ class Mark_address_taken : public Traverse
   expression(Expression**);
 
  private:
+  Call_expression*
+  find_makeslice_call(Expression*);
+
   // General IR.
   Gogo* gogo_;
   // The function we are traversing.
@@ -97,6 +100,31 @@ Mark_address_taken::statement(Block* block, size_t* pindex, Statement* s)
   return TRAVERSE_CONTINUE;
 }
 
+// Look through the expression of a Slice_value_expression's valmem to
+// find an call to makeslice.
+
+Call_expression*
+Mark_address_taken::find_makeslice_call(Expression* expr)
+{
+  Unsafe_type_conversion_expression* utce =
+    expr->unsafe_conversion_expression();
+  if (utce != NULL)
+    expr = utce->expr();
+
+  Call_expression* call = expr->call_expression();
+  if (call == NULL)
+    return NULL;
+
+  Func_expression* fe = call->fn()->func_expression();
+  if (fe != NULL && fe->runtime_code() == Runtime::MAKESLICE)
+    return call;
+
+  // We don't worry about MAKESLICE64 bcause we don't want to use a
+  // stack allocation for a large slice anyhow.
+
+  return NULL;
+}
+
 // Mark variable addresses taken.
 
 int
@@ -142,16 +170,12 @@ Mark_address_taken::expression(Expression** pexpr)
     }
 
   // Rewrite non-escaping makeslice with constant size to stack allocation.
-  Unsafe_type_conversion_expression* uce =
-    expr->unsafe_conversion_expression();
-  if (uce != NULL
-      && uce->type()->is_slice_type()
-      && Node::make_node(uce->expr())->encoding() == Node::ESCAPE_NONE
-      && uce->expr()->call_expression() != NULL)
+  Slice_value_expression* sve = expr->slice_value_expression();
+  if (sve != NULL)
     {
-      Call_expression* call = uce->expr()->call_expression();
-      if (call->fn()->func_expression() != NULL
-          && call->fn()->func_expression()->runtime_code() == Runtime::MAKESLICE)
+      Call_expression* call = this->find_makeslice_call(sve->valmem());
+      if (call != NULL
+         && Node::make_node(call)->encoding() == Node::ESCAPE_NONE)
         {
           Expression* len_arg = call->args()->at(1);
           Expression* cap_arg = call->args()->at(2);
@@ -164,8 +188,7 @@ Mark_address_taken::expression(Expression** pexpr)
               && nclen.to_unsigned_long(&vlen) == Numeric_constant::NC_UL_VALID
               && nccap.to_unsigned_long(&vcap) == Numeric_constant::NC_UL_VALID)
             {
-              // Turn it into a slice expression of an addressable array,
-              // which is allocated on stack.
+             // Stack allocate an array and make a slice value from it.
               Location loc = expr->location();
               Type* elmt_type = expr->type()->array_type()->element_type();
               Expression* len_expr =
@@ -173,10 +196,12 @@ Mark_address_taken::expression(Expression** pexpr)
               Type* array_type = Type::make_array_type(elmt_type, len_expr);
               Expression* alloc = Expression::make_allocation(array_type, loc);
               alloc->allocation_expression()->set_allocate_on_stack();
-              Expression* array = Expression::make_unary(OPERATOR_MULT, alloc, loc);
-              Expression* zero = Expression::make_integer_ul(0, len_arg->type(), loc);
-              Expression* slice =
-                Expression::make_array_index(array, zero, len_arg, cap_arg, loc);
+             Type* ptr_type = Type::make_pointer_type(elmt_type);
+             Expression* ptr = Expression::make_unsafe_cast(ptr_type, alloc,
+                                                            loc);
+             Expression* slice =
+               Expression::make_slice_value(expr->type(), ptr, len_arg,
+                                            cap_arg, loc);
               *pexpr = slice;
             }
         }
index f428827232a9c59023e16228bc322b640a7fe3d7..6fe892b46f40a8ef928ee5a85e01e78d1c07cf83 100644 (file)
@@ -45,7 +45,7 @@ func allocatePersistent1K() {
 // Allocate transient memory using reflect.Call.
 
 func allocateReflectTransient() {
-       memSink = make([]byte, 2<<20)
+       memSink = make([]byte, 3<<20)
 }
 
 func allocateReflect() {
@@ -106,7 +106,7 @@ func TestMemoryProfiler(t *testing.T) {
                // GC means that sometimes the value is not collected.
                fmt.Sprintf(`(0|%v): (0|%v) \[%v: %v\] @( 0x[0-9,a-f]+)+
 #      0x[0-9,a-f]+    pprof\.allocateReflectTransient\+0x[0-9,a-f]+   .*/mprof_test.go:48
-`, memoryProfilerRun, (2<<20)*memoryProfilerRun, memoryProfilerRun, (2<<20)*memoryProfilerRun),
+`, memoryProfilerRun, (3<<20)*memoryProfilerRun, memoryProfilerRun, (3<<20)*memoryProfilerRun),
        }
 
        for _, test := range tests {
index 2e874cc2fbc06d441bd04b9dbe0c05393d01455f..7f9db4efa9ef9e858e824ce77d97913cbed79a3c 100644 (file)
@@ -61,7 +61,7 @@ func panicmakeslicecap() {
        panic(errorString("makeslice: cap out of range"))
 }
 
-func makeslice(et *_type, len, cap int) slice {
+func makeslice(et *_type, len, cap int) unsafe.Pointer {
        // NOTE: The len > maxElements check here is not strictly necessary,
        // but it produces a 'len out of range' error instead of a 'cap out of range' error
        // when someone does make([]T, bignumber). 'cap out of range' is true too,
@@ -76,11 +76,10 @@ func makeslice(et *_type, len, cap int) slice {
                panicmakeslicecap()
        }
 
-       p := mallocgc(et.size*uintptr(cap), et, true)
-       return slice{p, len, cap}
+       return mallocgc(et.size*uintptr(cap), et, true)
 }
 
-func makeslice64(et *_type, len64, cap64 int64) slice {
+func makeslice64(et *_type, len64, cap64 int64) unsafe.Pointer {
        len := int(len64)
        if int64(len) != len64 {
                panicmakeslicelen()