From dd8d9bff4599af02fdff1686728e3579124359c4 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Wed, 28 Dec 2011 00:02:39 +0000 Subject: [PATCH] compiler: Rework range over slice. From-SVN: r182697 --- gcc/go/gofrontend/statements.cc | 109 +++++++++++++++++++++++++++++++- gcc/go/gofrontend/statements.h | 5 ++ 2 files changed, 112 insertions(+), 2 deletions(-) diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc index 964b394c3bd..f6c0f8254df 100644 --- a/gcc/go/gofrontend/statements.cc +++ b/gcc/go/gofrontend/statements.cc @@ -5260,7 +5260,11 @@ For_range_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing, // original statements // } - if (range_type->array_type() != NULL) + if (range_type->is_slice_type()) + this->lower_range_slice(gogo, temp_block, body, range_object, range_temp, + index_temp, value_temp, &init, &cond, &iter_init, + &post); + else if (range_type->array_type() != NULL) this->lower_range_array(gogo, temp_block, body, range_object, range_temp, index_temp, value_temp, &init, &cond, &iter_init, &post); @@ -5346,7 +5350,7 @@ For_range_statement::call_builtin(Gogo* gogo, const char* funcname, return Expression::make_call(func, params, false, loc); } -// Lower a for range over an array or slice. +// Lower a for range over an array. void For_range_statement::lower_range_array(Gogo* gogo, @@ -5438,6 +5442,107 @@ For_range_statement::lower_range_array(Gogo* gogo, *ppost = post; } +// Lower a for range over a slice. + +void +For_range_statement::lower_range_slice(Gogo* gogo, + Block* enclosing, + Block* body_block, + Named_object* range_object, + Temporary_statement* range_temp, + Temporary_statement* index_temp, + Temporary_statement* value_temp, + Block** pinit, + Expression** pcond, + Block** piter_init, + Block** ppost) +{ + Location loc = this->location(); + + // The loop we generate: + // for_temp := range + // len_temp := len(for_temp) + // for index_temp = 0; index_temp < len_temp; index_temp++ { + // value_temp = for_temp[index_temp] + // index = index_temp + // value = value_temp + // original body + // } + // + // Using for_temp means that we don't need to check bounds when + // fetching range_temp[index_temp]. + + // Set *PINIT to + // range_temp := range + // var len_temp int + // len_temp = len(range_temp) + // index_temp = 0 + + Block* init = new Block(enclosing, loc); + + Expression* ref = this->make_range_ref(range_object, range_temp, loc); + Temporary_statement* for_temp = Statement::make_temporary(NULL, ref, loc); + init->add_statement(for_temp); + + ref = Expression::make_temporary_reference(for_temp, loc); + Expression* len_call = this->call_builtin(gogo, "len", ref, loc); + Temporary_statement* len_temp = Statement::make_temporary(index_temp->type(), + len_call, loc); + init->add_statement(len_temp); + + mpz_t zval; + mpz_init_set_ui(zval, 0UL); + Expression* zexpr = Expression::make_integer(&zval, NULL, loc); + mpz_clear(zval); + + Temporary_reference_expression* tref = + Expression::make_temporary_reference(index_temp, loc); + tref->set_is_lvalue(); + Statement* s = Statement::make_assignment(tref, zexpr, loc); + init->add_statement(s); + + *pinit = init; + + // Set *PCOND to + // index_temp < len_temp + + ref = Expression::make_temporary_reference(index_temp, loc); + Expression* ref2 = Expression::make_temporary_reference(len_temp, loc); + Expression* lt = Expression::make_binary(OPERATOR_LT, ref, ref2, loc); + + *pcond = lt; + + // Set *PITER_INIT to + // value_temp = range[index_temp] + + Block* iter_init = NULL; + if (value_temp != NULL) + { + iter_init = new Block(body_block, loc); + + ref = Expression::make_temporary_reference(for_temp, loc); + Expression* ref2 = Expression::make_temporary_reference(index_temp, loc); + Expression* index = Expression::make_index(ref, ref2, NULL, loc); + + tref = Expression::make_temporary_reference(value_temp, loc); + tref->set_is_lvalue(); + s = Statement::make_assignment(tref, index, loc); + + iter_init->add_statement(s); + } + *piter_init = iter_init; + + // Set *PPOST to + // index_temp++ + + Block* post = new Block(enclosing, loc); + tref = Expression::make_temporary_reference(index_temp, loc); + tref->set_is_lvalue(); + s = Statement::make_inc_statement(tref); + post->add_statement(s); + *ppost = post; +} + // Lower a for range over a string. void diff --git a/gcc/go/gofrontend/statements.h b/gcc/go/gofrontend/statements.h index 4548ba6f56c..016ca189569 100644 --- a/gcc/go/gofrontend/statements.h +++ b/gcc/go/gofrontend/statements.h @@ -1161,6 +1161,11 @@ class For_range_statement : public Statement Temporary_statement*, Temporary_statement*, Block**, Expression**, Block**, Block**); + void + lower_range_slice(Gogo*, Block*, Block*, Named_object*, Temporary_statement*, + Temporary_statement*, Temporary_statement*, + Block**, Expression**, Block**, Block**); + void lower_range_string(Gogo*, Block*, Block*, Named_object*, Temporary_statement*, Temporary_statement*, Temporary_statement*,