Commit 58dbd453 by Ian Lance Taylor

compiler: recognize and optimize map range clear

    
    Recognize
    
            for k := range m { delete(m, k) }
    
    for map m, and rewrite it to runtime.mapclear, as the gc compiler
    does.
    
    Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/169397

From-SVN: r270780
parent 5e87c280
b42744825e3f2d1d2981eedbb67d6ac6419b8122 7e590184ae1ebc02e1b2577de00cf4fe842217dc
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.
...@@ -137,6 +137,9 @@ DEF_GO_RUNTIME(MAPITERINIT, "runtime.mapiterinit", P3(TYPE, MAP, POINTER), ...@@ -137,6 +137,9 @@ DEF_GO_RUNTIME(MAPITERINIT, "runtime.mapiterinit", P3(TYPE, MAP, POINTER),
// Range over a map, moving to the next map entry. // Range over a map, moving to the next map entry.
DEF_GO_RUNTIME(MAPITERNEXT, "runtime.mapiternext", P1(POINTER), R0()) DEF_GO_RUNTIME(MAPITERNEXT, "runtime.mapiternext", P1(POINTER), R0())
// Clear a map.
DEF_GO_RUNTIME(MAPCLEAR, "runtime.mapclear", P2(TYPE, MAP), R0())
// Make a channel. // Make a channel.
DEF_GO_RUNTIME(MAKECHAN, "runtime.makechan", P2(TYPE, INT), R1(CHAN)) DEF_GO_RUNTIME(MAKECHAN, "runtime.makechan", P2(TYPE, INT), R1(CHAN))
......
...@@ -5485,6 +5485,7 @@ For_range_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing, ...@@ -5485,6 +5485,7 @@ For_range_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing,
Location loc = this->location(); Location loc = this->location();
Block* temp_block = new Block(enclosing, loc); Block* temp_block = new Block(enclosing, loc);
Expression* orig_range_expr = this->range_;
Named_object* range_object = NULL; Named_object* range_object = NULL;
Temporary_statement* range_temp = NULL; Temporary_statement* range_temp = NULL;
if (eval) if (eval)
...@@ -5500,6 +5501,22 @@ For_range_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing, ...@@ -5500,6 +5501,22 @@ For_range_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing,
} }
} }
// Try to match "range clear" patterns and rewrite to simple runtime
// calls.
if (range_type->map_type() != NULL)
{
Statement* clear = this->lower_map_range_clear(range_type,
enclosing,
orig_range_expr,
range_object,
range_temp, loc);
if (clear != NULL)
{
temp_block->add_statement(clear);
return Statement::make_block_statement(temp_block, loc);
}
}
Temporary_statement* index_temp = Statement::make_temporary(index_type, Temporary_statement* index_temp = Statement::make_temporary(index_type,
NULL, loc); NULL, loc);
temp_block->add_statement(index_temp); temp_block->add_statement(index_temp);
...@@ -6141,6 +6158,85 @@ For_range_statement::lower_range_channel(Gogo*, ...@@ -6141,6 +6158,85 @@ For_range_statement::lower_range_channel(Gogo*,
*piter_init = iter_init; *piter_init = iter_init;
} }
// Match
//
// for k := range m { delete(m, k) }
//
// Lower it to runtime.mapclear(TYPE, m) on match, return the statement
// containing the call. Return NULL otherwise.
Statement*
For_range_statement::lower_map_range_clear(Type* map_type,
Block* enclosing,
Expression* orig_range_expr,
Named_object* range_object,
Temporary_statement* range_temp,
Location loc)
{
if (this->value_var_ != NULL)
return NULL;
if (this->index_var_ == NULL)
return NULL;
// Require the loop index be a new variable. We cannot rewrite
// if it is used outside of the loop.
Var_expression* index_ve = this->index_var_->var_expression();
if (index_ve == NULL)
return NULL;
Named_object* index_no = index_ve->named_object();
if (enclosing->bindings()->lookup_local(index_no->name()) != index_no)
return NULL;
// Match the body. When lowering the builtin delete function, we have
// inserted temporaries, so we actually match for
//
// tmp1 = m
// tmp2 = k
// runtime.mapdelete(TYPE, tmp1, &tmp2)
const std::vector<Statement*>* statements = this->statements_->statements();
if (statements->size() != 3)
return NULL;
Temporary_statement* ts1 = statements->at(0)->temporary_statement();
Temporary_statement* ts2 = statements->at(1)->temporary_statement();
Expression_statement* es3 = statements->at(2)->expression_statement();
if (ts1 == NULL || ts2 == NULL || es3 == NULL
|| !Expression::is_same_variable(orig_range_expr, ts1->init())
|| !Expression::is_same_variable(this->index_var_, ts2->init()))
return NULL;
Call_expression* call = es3->expr()->call_expression();
if (call == NULL)
return NULL;
Func_expression* fe = call->fn()->func_expression();
if (fe == NULL || !fe->is_runtime_function()
|| fe->runtime_code() != Runtime::MAPDELETE)
return NULL;
Expression* a1 = call->args()->at(1);
a1 = (a1->unsafe_conversion_expression() != NULL
? a1->unsafe_conversion_expression()->expr()
: a1);
Temporary_reference_expression* tre = a1->temporary_reference_expression();
if (tre == NULL || tre->statement() != ts1)
return NULL;
Expression* a2 = call->args()->at(2);
a2 = (a2->conversion_expression() != NULL
? a2->conversion_expression()->expr()
: a2);
Unary_expression* ue = a2->unary_expression();
if (ue == NULL || ue->op() != OPERATOR_AND)
return NULL;
tre = ue->operand()->temporary_reference_expression();
if (tre == NULL || tre->statement() != ts2)
return NULL;
// Everything matches. Rewrite to mapclear(TYPE, MAP).
Expression* e1 = Expression::make_type_descriptor(map_type, loc);
Expression* e2 = this->make_range_ref(range_object, range_temp, loc);
call = Runtime::make_call(Runtime::MAPCLEAR, loc, 2, e1, e2);
return Statement::make_statement(call, true);
}
// Return the break LABEL_EXPR. // Return the break LABEL_EXPR.
Unnamed_label* Unnamed_label*
......
...@@ -1618,6 +1618,10 @@ class For_range_statement : public Statement ...@@ -1618,6 +1618,10 @@ class For_range_statement : public Statement
Temporary_statement*, Block**, Expression**, Block**, Temporary_statement*, Block**, Expression**, Block**,
Block**); Block**);
Statement*
lower_map_range_clear(Type*, Block*, Expression*, Named_object*,
Temporary_statement*, Location);
// The variable which is set to the index value. // The variable which is set to the index value.
Expression* index_var_; Expression* index_var_;
// The variable which is set to the element value. This may be // The variable which is set to the element value. This may be
......
...@@ -72,6 +72,7 @@ import ( ...@@ -72,6 +72,7 @@ import (
//go:linkname mapaccess2_fat runtime.mapaccess2_fat //go:linkname mapaccess2_fat runtime.mapaccess2_fat
//go:linkname mapassign runtime.mapassign //go:linkname mapassign runtime.mapassign
//go:linkname mapdelete runtime.mapdelete //go:linkname mapdelete runtime.mapdelete
//go:linkname mapclear runtime.mapclear
//go:linkname mapiterinit runtime.mapiterinit //go:linkname mapiterinit runtime.mapiterinit
//go:linkname mapiternext runtime.mapiternext //go:linkname mapiternext runtime.mapiternext
......
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