mirror of git://gcc.gnu.org/git/gcc.git
compiler: stack allocate storage for temp slices.
During the lowering phase, the variable arguments to a varargs call are
packaged up into a temporary slice object; the storage for this slice
was being unconditionally allocated on the heap. Heap allocation is not
necessary, however, if the varargs call correspond to an "append", since
the append runtime routine only reads the slice storage (as opposed to
stashing away the storage pointer). Enhance the lowering code to keep
the slice storage on the stack for append() calls, to improve
performance.
Addresses issue golang/go#17304.
Reviewed-on: https://go-review.googlesource.com/30136
From-SVN: r240853
This commit is contained in:
parent
c9616e9af9
commit
729232db0b
|
|
@ -1,4 +1,4 @@
|
||||||
60b84be3fa146d821dcd3939dad6336c89432cff
|
2431267d513804a3b1aa71adde9aefba9e3c3c59
|
||||||
|
|
||||||
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.
|
||||||
|
|
|
||||||
|
|
@ -6977,7 +6977,7 @@ Builtin_call_expression::do_lower(Gogo* gogo, Named_object* function,
|
||||||
Type* element_type = slice_type->array_type()->element_type();
|
Type* element_type = slice_type->array_type()->element_type();
|
||||||
this->lower_varargs(gogo, function, inserter,
|
this->lower_varargs(gogo, function, inserter,
|
||||||
Type::make_array_type(element_type, NULL),
|
Type::make_array_type(element_type, NULL),
|
||||||
2);
|
2, SLICE_STORAGE_DOES_NOT_ESCAPE);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -8853,7 +8853,7 @@ Call_expression::do_lower(Gogo* gogo, Named_object* function,
|
||||||
go_assert(parameters != NULL && !parameters->empty());
|
go_assert(parameters != NULL && !parameters->empty());
|
||||||
Type* varargs_type = parameters->back().type();
|
Type* varargs_type = parameters->back().type();
|
||||||
this->lower_varargs(gogo, function, inserter, varargs_type,
|
this->lower_varargs(gogo, function, inserter, varargs_type,
|
||||||
parameters->size());
|
parameters->size(), SLICE_STORAGE_MAY_ESCAPE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this is call to a method, call the method directly passing the
|
// If this is call to a method, call the method directly passing the
|
||||||
|
|
@ -8958,7 +8958,8 @@ Call_expression::do_lower(Gogo* gogo, Named_object* function,
|
||||||
void
|
void
|
||||||
Call_expression::lower_varargs(Gogo* gogo, Named_object* function,
|
Call_expression::lower_varargs(Gogo* gogo, Named_object* function,
|
||||||
Statement_inserter* inserter,
|
Statement_inserter* inserter,
|
||||||
Type* varargs_type, size_t param_count)
|
Type* varargs_type, size_t param_count,
|
||||||
|
Slice_storage_escape_disp escape_disp)
|
||||||
{
|
{
|
||||||
if (this->varargs_are_lowered_)
|
if (this->varargs_are_lowered_)
|
||||||
return;
|
return;
|
||||||
|
|
@ -9027,8 +9028,11 @@ Call_expression::lower_varargs(Gogo* gogo, Named_object* function,
|
||||||
continue;
|
continue;
|
||||||
vals->push_back(*pa);
|
vals->push_back(*pa);
|
||||||
}
|
}
|
||||||
Expression* val =
|
Slice_construction_expression* sce =
|
||||||
Expression::make_slice_composite_literal(varargs_type, vals, loc);
|
Expression::make_slice_composite_literal(varargs_type, vals, loc);
|
||||||
|
if (escape_disp == SLICE_STORAGE_DOES_NOT_ESCAPE)
|
||||||
|
sce->set_storage_does_not_escape();
|
||||||
|
Expression* val = sce;
|
||||||
gogo->lower_expression(function, inserter, &val);
|
gogo->lower_expression(function, inserter, &val);
|
||||||
new_args->push_back(val);
|
new_args->push_back(val);
|
||||||
}
|
}
|
||||||
|
|
@ -12280,7 +12284,7 @@ Array_construction_expression::do_export(Export* exp) const
|
||||||
exp->write_c_string(")");
|
exp->write_c_string(")");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dump ast representation of an array construction expressin.
|
// Dump ast representation of an array construction expression.
|
||||||
|
|
||||||
void
|
void
|
||||||
Array_construction_expression::do_dump_expression(
|
Array_construction_expression::do_dump_expression(
|
||||||
|
|
@ -12295,6 +12299,7 @@ Array_construction_expression::do_dump_expression(
|
||||||
}
|
}
|
||||||
ast_dump_context->ostream() << "]" ;
|
ast_dump_context->ostream() << "]" ;
|
||||||
ast_dump_context->dump_type(this->type_);
|
ast_dump_context->dump_type(this->type_);
|
||||||
|
this->dump_slice_storage_expression(ast_dump_context);
|
||||||
ast_dump_context->ostream() << "{" ;
|
ast_dump_context->ostream() << "{" ;
|
||||||
if (this->indexes_ == NULL)
|
if (this->indexes_ == NULL)
|
||||||
ast_dump_context->dump_expression_list(this->vals_);
|
ast_dump_context->dump_expression_list(this->vals_);
|
||||||
|
|
@ -12350,7 +12355,8 @@ Slice_construction_expression::Slice_construction_expression(
|
||||||
Expression_list* vals, Location location)
|
Expression_list* vals, Location location)
|
||||||
: Array_construction_expression(EXPRESSION_SLICE_CONSTRUCTION,
|
: Array_construction_expression(EXPRESSION_SLICE_CONSTRUCTION,
|
||||||
type, indexes, vals, location),
|
type, indexes, vals, location),
|
||||||
valtype_(NULL)
|
valtype_(NULL), array_val_(NULL), slice_storage_(NULL),
|
||||||
|
storage_escapes_(true)
|
||||||
{
|
{
|
||||||
go_assert(type->is_slice_type());
|
go_assert(type->is_slice_type());
|
||||||
|
|
||||||
|
|
@ -12371,7 +12377,6 @@ Slice_construction_expression::Slice_construction_expression(
|
||||||
this->valtype_ = Type::make_array_type(element_type, length);
|
this->valtype_ = Type::make_array_type(element_type, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Traversal.
|
// Traversal.
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|
@ -12382,23 +12387,29 @@ Slice_construction_expression::do_traverse(Traverse* traverse)
|
||||||
return TRAVERSE_EXIT;
|
return TRAVERSE_EXIT;
|
||||||
if (Type::traverse(this->valtype_, traverse) == TRAVERSE_EXIT)
|
if (Type::traverse(this->valtype_, traverse) == TRAVERSE_EXIT)
|
||||||
return TRAVERSE_EXIT;
|
return TRAVERSE_EXIT;
|
||||||
|
if (this->array_val_ != NULL
|
||||||
|
&& Expression::traverse(&this->array_val_, traverse) == TRAVERSE_EXIT)
|
||||||
|
return TRAVERSE_EXIT;
|
||||||
|
if (this->slice_storage_ != NULL
|
||||||
|
&& Expression::traverse(&this->slice_storage_, traverse) == TRAVERSE_EXIT)
|
||||||
|
return TRAVERSE_EXIT;
|
||||||
return TRAVERSE_CONTINUE;
|
return TRAVERSE_CONTINUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the backend representation for constructing a slice.
|
// Helper routine to create fixed array value underlying the slice literal.
|
||||||
|
// May be called during flattening, or later during do_get_backend().
|
||||||
|
|
||||||
Bexpression*
|
Expression*
|
||||||
Slice_construction_expression::do_get_backend(Translate_context* context)
|
Slice_construction_expression::create_array_val()
|
||||||
{
|
{
|
||||||
Array_type* array_type = this->type()->array_type();
|
Array_type* array_type = this->type()->array_type();
|
||||||
if (array_type == NULL)
|
if (array_type == NULL)
|
||||||
{
|
{
|
||||||
go_assert(this->type()->is_error());
|
go_assert(this->type()->is_error());
|
||||||
return context->backend()->error_expression();
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
Location loc = this->location();
|
Location loc = this->location();
|
||||||
Type* element_type = array_type->element_type();
|
|
||||||
go_assert(this->valtype_ != NULL);
|
go_assert(this->valtype_ != NULL);
|
||||||
|
|
||||||
Expression_list* vals = this->vals();
|
Expression_list* vals = this->vals();
|
||||||
|
|
@ -12408,11 +12419,71 @@ Slice_construction_expression::do_get_backend(Translate_context* context)
|
||||||
vals = new Expression_list;
|
vals = new Expression_list;
|
||||||
vals->push_back(NULL);
|
vals->push_back(NULL);
|
||||||
}
|
}
|
||||||
Expression* array_val =
|
return new Fixed_array_construction_expression(
|
||||||
new Fixed_array_construction_expression(this->valtype_, this->indexes(),
|
this->valtype_, this->indexes(), vals, loc);
|
||||||
vals, loc);
|
}
|
||||||
|
|
||||||
bool is_constant_initializer = array_val->is_immutable();
|
// If we're previous established that the slice storage does not
|
||||||
|
// escape, then create a separate array temp val here for it. We
|
||||||
|
// need to do this as part of flattening so as to be able to insert
|
||||||
|
// the new temp statement.
|
||||||
|
|
||||||
|
Expression*
|
||||||
|
Slice_construction_expression::do_flatten(Gogo* gogo, Named_object* no,
|
||||||
|
Statement_inserter* inserter)
|
||||||
|
{
|
||||||
|
if (this->type()->array_type() == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
// Base class flattening first
|
||||||
|
this->Array_construction_expression::do_flatten(gogo, no, inserter);
|
||||||
|
|
||||||
|
// Create an stack-allocated storage temp if storage won't escape
|
||||||
|
if (!this->storage_escapes_)
|
||||||
|
{
|
||||||
|
Location loc = this->location();
|
||||||
|
this->array_val_ = create_array_val();
|
||||||
|
go_assert(this->array_val_);
|
||||||
|
Temporary_statement* temp =
|
||||||
|
Statement::make_temporary(this->valtype_, this->array_val_, loc);
|
||||||
|
inserter->insert(temp);
|
||||||
|
this->slice_storage_ = Expression::make_temporary_reference(temp, loc);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// When dumping a slice construction expression that has an explicit
|
||||||
|
// storeage temp, emit the temp here (if we don't do this the storage
|
||||||
|
// temp appears unused in the AST dump).
|
||||||
|
|
||||||
|
void
|
||||||
|
Slice_construction_expression::
|
||||||
|
dump_slice_storage_expression(Ast_dump_context* ast_dump_context) const
|
||||||
|
{
|
||||||
|
if (this->slice_storage_ == NULL)
|
||||||
|
return;
|
||||||
|
ast_dump_context->ostream() << "storage=" ;
|
||||||
|
ast_dump_context->dump_expression(this->slice_storage_);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the backend representation for constructing a slice.
|
||||||
|
|
||||||
|
Bexpression*
|
||||||
|
Slice_construction_expression::do_get_backend(Translate_context* context)
|
||||||
|
{
|
||||||
|
if (this->array_val_ == NULL)
|
||||||
|
this->array_val_ = create_array_val();
|
||||||
|
if (this->array_val_ == NULL)
|
||||||
|
{
|
||||||
|
go_assert(this->type()->is_error());
|
||||||
|
return context->backend()->error_expression();
|
||||||
|
}
|
||||||
|
|
||||||
|
Location loc = this->location();
|
||||||
|
Array_type* array_type = this->type()->array_type();
|
||||||
|
Type* element_type = array_type->element_type();
|
||||||
|
|
||||||
|
bool is_constant_initializer = this->array_val_->is_immutable();
|
||||||
|
|
||||||
// We have to copy the initial values into heap memory if we are in
|
// 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
|
// a function or if the values are not constants. We also have to
|
||||||
|
|
@ -12424,15 +12495,21 @@ Slice_construction_expression::do_get_backend(Translate_context* context)
|
||||||
&& !context->is_const()));
|
&& !context->is_const()));
|
||||||
|
|
||||||
Expression* space;
|
Expression* space;
|
||||||
if (!copy_to_heap)
|
|
||||||
|
if (this->slice_storage_ != NULL)
|
||||||
|
{
|
||||||
|
go_assert(!this->storage_escapes_);
|
||||||
|
space = Expression::make_unary(OPERATOR_AND, this->slice_storage_, loc);
|
||||||
|
}
|
||||||
|
else if (!copy_to_heap)
|
||||||
{
|
{
|
||||||
// The initializer will only run once.
|
// The initializer will only run once.
|
||||||
space = Expression::make_unary(OPERATOR_AND, array_val, loc);
|
space = Expression::make_unary(OPERATOR_AND, this->array_val_, loc);
|
||||||
space->unary_expression()->set_is_slice_init();
|
space->unary_expression()->set_is_slice_init();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
space = Expression::make_heap_expression(array_val, loc);
|
space = Expression::make_heap_expression(this->array_val_, loc);
|
||||||
Node* n = Node::make_node(this);
|
Node* n = Node::make_node(this);
|
||||||
if ((n->encoding() & ESCAPE_MASK) == int(Node::ESCAPE_NONE))
|
if ((n->encoding() & ESCAPE_MASK) == int(Node::ESCAPE_NONE))
|
||||||
{
|
{
|
||||||
|
|
@ -12442,7 +12519,6 @@ Slice_construction_expression::do_get_backend(Translate_context* context)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build a constructor for the slice.
|
// Build a constructor for the slice.
|
||||||
|
|
||||||
Expression* len = this->valtype_->array_type()->length();
|
Expression* len = this->valtype_->array_type()->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);
|
||||||
|
|
@ -12452,7 +12528,7 @@ Slice_construction_expression::do_get_backend(Translate_context* context)
|
||||||
// Make a slice composite literal. This is used by the type
|
// Make a slice composite literal. This is used by the type
|
||||||
// descriptor code.
|
// descriptor code.
|
||||||
|
|
||||||
Expression*
|
Slice_construction_expression*
|
||||||
Expression::make_slice_composite_literal(Type* type, Expression_list* vals,
|
Expression::make_slice_composite_literal(Type* type, Expression_list* vals,
|
||||||
Location location)
|
Location location)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -374,7 +374,7 @@ class Expression
|
||||||
make_array_composite_literal(Type*, Expression_list*, Location);
|
make_array_composite_literal(Type*, Expression_list*, Location);
|
||||||
|
|
||||||
// Make a slice composite literal.
|
// Make a slice composite literal.
|
||||||
static Expression*
|
static Slice_construction_expression*
|
||||||
make_slice_composite_literal(Type*, Expression_list*, Location);
|
make_slice_composite_literal(Type*, Expression_list*, Location);
|
||||||
|
|
||||||
// Take an expression and allocate it on the heap.
|
// Take an expression and allocate it on the heap.
|
||||||
|
|
@ -1067,6 +1067,18 @@ class Expression
|
||||||
virtual void
|
virtual void
|
||||||
do_dump_expression(Ast_dump_context*) const = 0;
|
do_dump_expression(Ast_dump_context*) const = 0;
|
||||||
|
|
||||||
|
// Varargs lowering creates a slice object (unnamed compiler temp)
|
||||||
|
// to contain the variable length collection of values. The enum
|
||||||
|
// below tells the lowering routine whether it can mark that temp
|
||||||
|
// as non-escaping or not. For general varargs calls it is not always
|
||||||
|
// safe to stack-allocated the storage, but for specific cases (ex:
|
||||||
|
// call to append()) it is legal.
|
||||||
|
enum Slice_storage_escape_disp
|
||||||
|
{
|
||||||
|
SLICE_STORAGE_MAY_ESCAPE,
|
||||||
|
SLICE_STORAGE_DOES_NOT_ESCAPE
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Convert to the desired statement classification, or return NULL.
|
// Convert to the desired statement classification, or return NULL.
|
||||||
// This is a controlled dynamic cast.
|
// This is a controlled dynamic cast.
|
||||||
|
|
@ -2128,7 +2140,8 @@ class Call_expression : public Expression
|
||||||
// Let a builtin expression lower varargs.
|
// Let a builtin expression lower varargs.
|
||||||
void
|
void
|
||||||
lower_varargs(Gogo*, Named_object* function, Statement_inserter* inserter,
|
lower_varargs(Gogo*, Named_object* function, Statement_inserter* inserter,
|
||||||
Type* varargs_type, size_t param_count);
|
Type* varargs_type, size_t param_count,
|
||||||
|
Slice_storage_escape_disp escape_disp);
|
||||||
|
|
||||||
// Let a builtin expression check whether types have been
|
// Let a builtin expression check whether types have been
|
||||||
// determined.
|
// determined.
|
||||||
|
|
@ -3282,6 +3295,9 @@ protected:
|
||||||
void
|
void
|
||||||
do_dump_expression(Ast_dump_context*) const;
|
do_dump_expression(Ast_dump_context*) const;
|
||||||
|
|
||||||
|
virtual void
|
||||||
|
dump_slice_storage_expression(Ast_dump_context*) const { }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// The type of the array to construct.
|
// The type of the array to construct.
|
||||||
Type* type_;
|
Type* type_;
|
||||||
|
|
@ -3326,6 +3342,18 @@ class Slice_construction_expression : public Array_construction_expression
|
||||||
Slice_construction_expression(Type* type,
|
Slice_construction_expression(Type* type,
|
||||||
const std::vector<unsigned long>* indexes,
|
const std::vector<unsigned long>* indexes,
|
||||||
Expression_list* vals, Location location);
|
Expression_list* vals, Location location);
|
||||||
|
|
||||||
|
Expression*
|
||||||
|
do_flatten(Gogo*, Named_object*, Statement_inserter*);
|
||||||
|
|
||||||
|
// Record that the storage for this slice (e.g. vals) cannot escape,
|
||||||
|
// hence it can be stack-allocated.
|
||||||
|
void
|
||||||
|
set_storage_does_not_escape()
|
||||||
|
{
|
||||||
|
this->storage_escapes_ = false;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Note that taking the address of a slice literal is invalid.
|
// Note that taking the address of a slice literal is invalid.
|
||||||
|
|
||||||
|
|
@ -3345,9 +3373,25 @@ class Slice_construction_expression : public Array_construction_expression
|
||||||
Bexpression*
|
Bexpression*
|
||||||
do_get_backend(Translate_context*);
|
do_get_backend(Translate_context*);
|
||||||
|
|
||||||
|
void
|
||||||
|
dump_slice_storage_expression(Ast_dump_context* ast_dump_context) const;
|
||||||
|
|
||||||
|
// Create an array value for the constructed slice. Invoked during
|
||||||
|
// flattening if slice storage does not escape, otherwise invoked
|
||||||
|
// later on during do_get_backend().
|
||||||
|
Expression*
|
||||||
|
create_array_val();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// The type of the values in this slice.
|
// The type of the values in this slice.
|
||||||
Type* valtype_;
|
Type* valtype_;
|
||||||
|
// Array value expression, optionally filled in during flattening.
|
||||||
|
Expression* array_val_;
|
||||||
|
// Slice storage expression, optionally filled in during flattening.
|
||||||
|
Expression* slice_storage_;
|
||||||
|
// Normally true. Can be set to false if we know that the resulting
|
||||||
|
// storage for the slice cannot escape.
|
||||||
|
bool storage_escapes_;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Construct a map.
|
// Construct a map.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue