Commit fdcef314 by Ian Lance Taylor

compiler: move slice construction to callers of makeslice

    
    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
parent 575eb8f5
c257303eaef143663216e483857d5b259e05753f c8a9bccbc524381d150c84907a61ac257c1b07cc
The first line of this file holds the git revision number of the last The first line of this file holds the git revision number of the last
merge done from the gofrontend repository. merge done from the gofrontend repository.
...@@ -1737,6 +1737,16 @@ Escape_analysis_assign::expression(Expression** pexpr) ...@@ -1737,6 +1737,16 @@ Escape_analysis_assign::expression(Expression** pexpr)
} }
break; 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: case Expression::EXPRESSION_HEAP:
{ {
Node* pointer_node = Node::make_node(*pexpr); Node* pointer_node = Node::make_node(*pexpr);
...@@ -2263,6 +2273,8 @@ Escape_analysis_assign::assign(Node* dst, Node* src) ...@@ -2263,6 +2273,8 @@ Escape_analysis_assign::assign(Node* dst, Node* src)
// DST = map[T]V{...}. // DST = map[T]V{...}.
case Expression::EXPRESSION_STRUCT_CONSTRUCTION: case Expression::EXPRESSION_STRUCT_CONSTRUCTION:
// DST = T{...}. // DST = T{...}.
case Expression::EXPRESSION_SLICE_VALUE:
// DST = slice{ptr, len, cap}
case Expression::EXPRESSION_ALLOCATION: case Expression::EXPRESSION_ALLOCATION:
// DST = new(T). // DST = new(T).
case Expression::EXPRESSION_BOUND_METHOD: case Expression::EXPRESSION_BOUND_METHOD:
......
...@@ -7787,21 +7787,29 @@ Builtin_call_expression::lower_make(Statement_inserter* inserter) ...@@ -7787,21 +7787,29 @@ Builtin_call_expression::lower_make(Statement_inserter* inserter)
Expression* call; Expression* call;
if (is_slice) 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) if (cap_arg == NULL)
{ {
cap_small = len_small; cap_small = len_small;
if (len_arg->numeric_constant_value(&nclen) if (len_temp == NULL)
&& nclen.to_unsigned_long(&vlen) == Numeric_constant::NC_UL_VALID) cap_arg = len_arg->copy();
cap_arg = Expression::make_integer_ul(vlen, len_arg->type(), loc); else
else cap_arg = Expression::make_temporary_reference(len_temp, loc);
{ }
Temporary_statement* temp = Statement::make_temporary(NULL, else if (!cap_arg->is_constant())
len_arg, {
loc); Temporary_statement* cap_temp = Statement::make_temporary(NULL,
inserter->insert(temp); cap_arg,
len_arg = Expression::make_temporary_reference(temp, loc); loc);
cap_arg = Expression::make_temporary_reference(temp, loc); inserter->insert(cap_temp);
} cap_arg = Expression::make_temporary_reference(cap_temp, loc);
} }
Type* et = type->array_type()->element_type(); Type* et = type->array_type()->element_type();
...@@ -7809,7 +7817,12 @@ Builtin_call_expression::lower_make(Statement_inserter* inserter) ...@@ -7809,7 +7817,12 @@ Builtin_call_expression::lower_make(Statement_inserter* inserter)
Runtime::Function code = Runtime::MAKESLICE; Runtime::Function code = Runtime::MAKESLICE;
if (!len_small || !cap_small) if (!len_small || !cap_small)
code = Runtime::MAKESLICE64; 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) else if (is_map)
{ {
...@@ -13585,9 +13598,13 @@ Slice_construction_expression::do_get_backend(Translate_context* context) ...@@ -13585,9 +13598,13 @@ Slice_construction_expression::do_get_backend(Translate_context* context)
go_assert(this->storage_escapes_ || this->element_count() == 0); go_assert(this->storage_escapes_ || this->element_count() == 0);
space = Expression::make_heap_expression(this->array_val_, loc); 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. // Build a constructor for the slice.
Expression* len = this->valtype_->array_type()->length(); Expression* len = at->length();
Expression* slice_val = Expression* slice_val =
Expression::make_slice_value(this->type(), space, len, len, loc); Expression::make_slice_value(this->type(), space, len, len, loc);
return slice_val->get_backend(context); return slice_val->get_backend(context);
...@@ -15354,72 +15371,33 @@ Expression::make_slice_info(Expression* slice, Slice_info slice_info, ...@@ -15354,72 +15371,33 @@ Expression::make_slice_info(Expression* slice, Slice_info slice_info,
return new Slice_info_expression(slice, slice_info, location); return new Slice_info_expression(slice, slice_info, location);
} }
// An expression that represents a slice value: a struct with value pointer, // Class Slice_value_expression.
// 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_;
};
int int
Slice_value_expression::do_traverse(Traverse* traverse) Slice_value_expression::do_traverse(Traverse* traverse)
{ {
if (Type::traverse(this->type_, traverse) == TRAVERSE_EXIT 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->len_, traverse) == TRAVERSE_EXIT
|| Expression::traverse(&this->cap_, traverse) == TRAVERSE_EXIT) || Expression::traverse(&this->cap_, traverse) == TRAVERSE_EXIT)
return TRAVERSE_EXIT; return TRAVERSE_EXIT;
return TRAVERSE_CONTINUE; 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* Bexpression*
Slice_value_expression::do_get_backend(Translate_context* context) Slice_value_expression::do_get_backend(Translate_context* context)
{ {
std::vector<Bexpression*> vals(3); 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[1] = this->len_->get_backend(context);
vals[2] = this->cap_->get_backend(context); vals[2] = this->cap_->get_backend(context);
...@@ -15434,7 +15412,7 @@ Slice_value_expression::do_dump_expression( ...@@ -15434,7 +15412,7 @@ Slice_value_expression::do_dump_expression(
{ {
ast_dump_context->ostream() << "slicevalue("; ast_dump_context->ostream() << "slicevalue(";
ast_dump_context->ostream() << "values: "; ast_dump_context->ostream() << "values: ";
this->valptr_->dump_expression(ast_dump_context); this->valmem_->dump_expression(ast_dump_context);
ast_dump_context->ostream() << ", length: "; ast_dump_context->ostream() << ", length: ";
this->len_->dump_expression(ast_dump_context); this->len_->dump_expression(ast_dump_context);
ast_dump_context->ostream() << ", capacity: "; ast_dump_context->ostream() << ", capacity: ";
...@@ -15443,11 +15421,14 @@ Slice_value_expression::do_dump_expression( ...@@ -15443,11 +15421,14 @@ Slice_value_expression::do_dump_expression(
} }
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) Expression* cap, Location location)
{ {
go_assert(at->is_slice_type()); 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. // An expression that evaluates to some characteristic of a non-empty interface.
......
...@@ -61,6 +61,7 @@ class Map_construction_expression; ...@@ -61,6 +61,7 @@ class Map_construction_expression;
class Type_guard_expression; class Type_guard_expression;
class Heap_expression; class Heap_expression;
class Receive_expression; class Receive_expression;
class Slice_value_expression;
class Conditional_expression; class Conditional_expression;
class Compound_expression; class Compound_expression;
class Numeric_constant; class Numeric_constant;
...@@ -841,6 +842,12 @@ class Expression ...@@ -841,6 +842,12 @@ class Expression
receive_expression() receive_expression()
{ return this->convert<Receive_expression, EXPRESSION_RECEIVE>(); } { 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 // If this is a conditional expression, return the Conditional_expression
// structure. Otherwise, return NULL. // structure. Otherwise, return NULL.
Conditional_expression* Conditional_expression*
...@@ -3955,6 +3962,56 @@ class Receive_expression : public Expression ...@@ -3955,6 +3962,56 @@ class Receive_expression : public Expression
Temporary_statement* temp_receiver_; 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. // Conditional expressions.
class Conditional_expression : public Expression class Conditional_expression : public Expression
......
...@@ -85,10 +85,10 @@ DEF_GO_RUNTIME(COMPLEX128_DIV, "__go_complex128_div", ...@@ -85,10 +85,10 @@ DEF_GO_RUNTIME(COMPLEX128_DIV, "__go_complex128_div",
// Make a slice. // Make a slice.
DEF_GO_RUNTIME(MAKESLICE, "runtime.makeslice", P3(TYPE, INT, INT), DEF_GO_RUNTIME(MAKESLICE, "runtime.makeslice", P3(TYPE, INT, INT),
R1(SLICE)) R1(POINTER))
DEF_GO_RUNTIME(MAKESLICE64, "runtime.makeslice64", P3(TYPE, INT64, INT64), 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. // Make a map with a hint and an (optional, unused) map structure.
......
...@@ -41,6 +41,9 @@ class Mark_address_taken : public Traverse ...@@ -41,6 +41,9 @@ class Mark_address_taken : public Traverse
expression(Expression**); expression(Expression**);
private: private:
Call_expression*
find_makeslice_call(Expression*);
// General IR. // General IR.
Gogo* gogo_; Gogo* gogo_;
// The function we are traversing. // The function we are traversing.
...@@ -97,6 +100,31 @@ Mark_address_taken::statement(Block* block, size_t* pindex, Statement* s) ...@@ -97,6 +100,31 @@ Mark_address_taken::statement(Block* block, size_t* pindex, Statement* s)
return TRAVERSE_CONTINUE; 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. // Mark variable addresses taken.
int int
...@@ -142,16 +170,12 @@ Mark_address_taken::expression(Expression** pexpr) ...@@ -142,16 +170,12 @@ Mark_address_taken::expression(Expression** pexpr)
} }
// Rewrite non-escaping makeslice with constant size to stack allocation. // Rewrite non-escaping makeslice with constant size to stack allocation.
Unsafe_type_conversion_expression* uce = Slice_value_expression* sve = expr->slice_value_expression();
expr->unsafe_conversion_expression(); if (sve != NULL)
if (uce != NULL
&& uce->type()->is_slice_type()
&& Node::make_node(uce->expr())->encoding() == Node::ESCAPE_NONE
&& uce->expr()->call_expression() != NULL)
{ {
Call_expression* call = uce->expr()->call_expression(); Call_expression* call = this->find_makeslice_call(sve->valmem());
if (call->fn()->func_expression() != NULL if (call != NULL
&& call->fn()->func_expression()->runtime_code() == Runtime::MAKESLICE) && Node::make_node(call)->encoding() == Node::ESCAPE_NONE)
{ {
Expression* len_arg = call->args()->at(1); Expression* len_arg = call->args()->at(1);
Expression* cap_arg = call->args()->at(2); Expression* cap_arg = call->args()->at(2);
...@@ -164,8 +188,7 @@ Mark_address_taken::expression(Expression** pexpr) ...@@ -164,8 +188,7 @@ Mark_address_taken::expression(Expression** pexpr)
&& nclen.to_unsigned_long(&vlen) == Numeric_constant::NC_UL_VALID && nclen.to_unsigned_long(&vlen) == Numeric_constant::NC_UL_VALID
&& nccap.to_unsigned_long(&vcap) == 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, // Stack allocate an array and make a slice value from it.
// which is allocated on stack.
Location loc = expr->location(); Location loc = expr->location();
Type* elmt_type = expr->type()->array_type()->element_type(); Type* elmt_type = expr->type()->array_type()->element_type();
Expression* len_expr = Expression* len_expr =
...@@ -173,10 +196,12 @@ Mark_address_taken::expression(Expression** pexpr) ...@@ -173,10 +196,12 @@ Mark_address_taken::expression(Expression** pexpr)
Type* array_type = Type::make_array_type(elmt_type, len_expr); Type* array_type = Type::make_array_type(elmt_type, len_expr);
Expression* alloc = Expression::make_allocation(array_type, loc); Expression* alloc = Expression::make_allocation(array_type, loc);
alloc->allocation_expression()->set_allocate_on_stack(); alloc->allocation_expression()->set_allocate_on_stack();
Expression* array = Expression::make_unary(OPERATOR_MULT, alloc, loc); Type* ptr_type = Type::make_pointer_type(elmt_type);
Expression* zero = Expression::make_integer_ul(0, len_arg->type(), loc); Expression* ptr = Expression::make_unsafe_cast(ptr_type, alloc,
Expression* slice = loc);
Expression::make_array_index(array, zero, len_arg, cap_arg, loc); Expression* slice =
Expression::make_slice_value(expr->type(), ptr, len_arg,
cap_arg, loc);
*pexpr = slice; *pexpr = slice;
} }
} }
......
...@@ -45,7 +45,7 @@ func allocatePersistent1K() { ...@@ -45,7 +45,7 @@ func allocatePersistent1K() {
// Allocate transient memory using reflect.Call. // Allocate transient memory using reflect.Call.
func allocateReflectTransient() { func allocateReflectTransient() {
memSink = make([]byte, 2<<20) memSink = make([]byte, 3<<20)
} }
func allocateReflect() { func allocateReflect() {
...@@ -106,7 +106,7 @@ func TestMemoryProfiler(t *testing.T) { ...@@ -106,7 +106,7 @@ func TestMemoryProfiler(t *testing.T) {
// GC means that sometimes the value is not collected. // GC means that sometimes the value is not collected.
fmt.Sprintf(`(0|%v): (0|%v) \[%v: %v\] @( 0x[0-9,a-f]+)+ 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 # 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 { for _, test := range tests {
......
...@@ -61,7 +61,7 @@ func panicmakeslicecap() { ...@@ -61,7 +61,7 @@ func panicmakeslicecap() {
panic(errorString("makeslice: cap out of range")) 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, // 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 // 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, // 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 { ...@@ -76,11 +76,10 @@ func makeslice(et *_type, len, cap int) slice {
panicmakeslicecap() panicmakeslicecap()
} }
p := mallocgc(et.size*uintptr(cap), et, true) return mallocgc(et.size*uintptr(cap), et, true)
return slice{p, len, cap}
} }
func makeslice64(et *_type, len64, cap64 int64) slice { func makeslice64(et *_type, len64, cap64 int64) unsafe.Pointer {
len := int(len64) len := int(len64)
if int64(len) != len64 { if int64(len) != len64 {
panicmakeslicelen() panicmakeslicelen()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment