summaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/go/gofrontend/MERGE2
-rw-r--r--gcc/go/gofrontend/escape.cc7
-rw-r--r--gcc/go/gofrontend/expressions.cc36
-rw-r--r--gcc/go/gofrontend/runtime.def18
-rw-r--r--gcc/go/gofrontend/statements.cc168
-rw-r--r--gcc/go/gofrontend/statements.h2
-rw-r--r--gcc/go/gofrontend/types.cc33
7 files changed, 164 insertions, 102 deletions
diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE
index 443de8bb240..d594ded36b3 100644
--- a/gcc/go/gofrontend/MERGE
+++ b/gcc/go/gofrontend/MERGE
@@ -1,4 +1,4 @@
-153f7b68c0c4d3cf3da0becf82eb1a3eb8b47d6e
+0ba4563a4b0dec4c01b90d7b3c9e2ce2cd58a96f
The first line of this file holds the git revision number of the last
merge done from the gofrontend repository.
diff --git a/gcc/go/gofrontend/escape.cc b/gcc/go/gofrontend/escape.cc
index 6429a9a73d5..a90c527a361 100644
--- a/gcc/go/gofrontend/escape.cc
+++ b/gcc/go/gofrontend/escape.cc
@@ -297,6 +297,7 @@ Node::op_format() const
case Runtime::MAKECHAN:
case Runtime::MAKEMAP:
case Runtime::MAKESLICE:
+ case Runtime::MAKESLICE64:
op << "make";
break;
@@ -418,7 +419,8 @@ Node::is_big(Escape_context* context) const
Func_expression* fn = call->fn()->func_expression();
if (fn != NULL
&& fn->is_runtime_function()
- && fn->runtime_code() == Runtime::MAKESLICE)
+ && (fn->runtime_code() == Runtime::MAKESLICE
+ || fn->runtime_code() == Runtime::MAKESLICE64))
{
// Second argument is length.
Expression_list::iterator p = call->args()->begin();
@@ -1240,6 +1242,7 @@ Escape_analysis_assign::expression(Expression** pexpr)
case Runtime::MAKECHAN:
case Runtime::MAKEMAP:
case Runtime::MAKESLICE:
+ case Runtime::MAKESLICE64:
case Runtime::SLICEBYTETOSTRING:
case Runtime::SLICERUNETOSTRING:
case Runtime::STRINGTOSLICEBYTE:
@@ -1849,6 +1852,7 @@ Escape_analysis_assign::assign(Node* dst, Node* src)
case Runtime::MAKECHAN:
case Runtime::MAKEMAP:
case Runtime::MAKESLICE:
+ case Runtime::MAKESLICE64:
// DST = make(...).
case Runtime::SLICEBYTETOSTRING:
// DST = string([]byte{...}).
@@ -2623,6 +2627,7 @@ Escape_analysis_flood::flood(Level level, Node* dst, Node* src,
case Runtime::MAKECHAN:
case Runtime::MAKEMAP:
case Runtime::MAKESLICE:
+ case Runtime::MAKESLICE64:
case Runtime::SLICEBYTETOSTRING:
case Runtime::SLICERUNETOSTRING:
case Runtime::STRINGTOSLICEBYTE:
diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc
index fe4d07bec20..8006888b02a 100644
--- a/gcc/go/gofrontend/expressions.cc
+++ b/gcc/go/gofrontend/expressions.cc
@@ -7091,7 +7091,7 @@ class Builtin_call_expression : public Call_expression
Expression* flatten_append(Gogo*, Named_object*, Statement_inserter*);
bool
- check_int_value(Expression*, bool is_length);
+ check_int_value(Expression*, bool is_length, bool* small);
// A pointer back to the general IR structure. This avoids a global
// variable, or passing it around everywhere.
@@ -7462,6 +7462,7 @@ Builtin_call_expression::lower_make(Statement_inserter* inserter)
++parg;
Expression* len_arg;
+ bool len_small = false;
if (parg == args->end())
{
if (is_slice)
@@ -7475,17 +7476,18 @@ Builtin_call_expression::lower_make(Statement_inserter* inserter)
{
len_arg = *parg;
len_arg->determine_type(&int_context);
- if (!this->check_int_value(len_arg, true))
+ if (!this->check_int_value(len_arg, true, &len_small))
return Expression::make_error(this->location());
++parg;
}
Expression* cap_arg = NULL;
+ bool cap_small = false;
if (is_slice && parg != args->end())
{
cap_arg = *parg;
cap_arg->determine_type(&int_context);
- if (!this->check_int_value(cap_arg, false))
+ if (!this->check_int_value(cap_arg, false, &cap_small))
return Expression::make_error(this->location());
Numeric_constant nclen;
@@ -7526,9 +7528,13 @@ Builtin_call_expression::lower_make(Statement_inserter* inserter)
inserter->insert(temp);
len_arg = Expression::make_temporary_reference(temp, loc);
cap_arg = Expression::make_temporary_reference(temp, loc);
+ cap_small = len_small;
}
- call = Runtime::make_call(Runtime::MAKESLICE, loc, 3, type_arg,
- len_arg, cap_arg);
+
+ 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);
}
else if (is_map)
{
@@ -7744,11 +7750,14 @@ Builtin_call_expression::flatten_append(Gogo* gogo, Named_object* function,
// Return whether an expression has an integer value. Report an error
// if not. This is used when handling calls to the predeclared make
-// function.
+// function. Set *SMALL if the value is known to fit in type "int".
bool
-Builtin_call_expression::check_int_value(Expression* e, bool is_length)
+Builtin_call_expression::check_int_value(Expression* e, bool is_length,
+ bool *small)
{
+ *small = false;
+
Numeric_constant nc;
if (e->numeric_constant_value(&nc))
{
@@ -7784,11 +7793,22 @@ Builtin_call_expression::check_int_value(Expression* e, bool is_length)
return false;
}
+ *small = true;
return true;
}
if (e->type()->integer_type() != NULL)
- return true;
+ {
+ int ebits = e->type()->integer_type()->bits();
+ int intbits = Type::lookup_integer_type("int")->integer_type()->bits();
+
+ // We can treat ebits == intbits as small even for an unsigned
+ // integer type, because we will convert the value to int and
+ // then reject it in the runtime if it is negative.
+ *small = ebits <= intbits;
+
+ return true;
+ }
go_error_at(e->location(), "non-integer %s argument to make",
is_length ? "len" : "cap");
diff --git a/gcc/go/gofrontend/runtime.def b/gcc/go/gofrontend/runtime.def
index 7027989810c..90bf34f7e99 100644
--- a/gcc/go/gofrontend/runtime.def
+++ b/gcc/go/gofrontend/runtime.def
@@ -31,12 +31,9 @@
// The standard C memcmp function, used for struct comparisons.
DEF_GO_RUNTIME(MEMCMP, "__go_memcmp", P3(POINTER, POINTER, UINTPTR), R1(INT))
-// Range over a string, returning the next index.
-DEF_GO_RUNTIME(STRINGITER, "runtime.stringiter", P2(STRING, INT), R1(INT))
-
-// Range over a string, returning the next index and character.
-DEF_GO_RUNTIME(STRINGITER2, "runtime.stringiter2", P2(STRING, INT),
- R2(INT, RUNE))
+// Decode a non-ASCII rune from a string.
+DEF_GO_RUNTIME(DECODERUNE, "runtime.decoderune", P2(STRING, INT),
+ R2(RUNE, INT))
// Concatenate strings.
DEF_GO_RUNTIME(CONCATSTRINGS, "runtime.concatstrings", P2(POINTER, SLICE),
@@ -87,7 +84,10 @@ DEF_GO_RUNTIME(COMPLEX128_DIV, "__go_complex128_div",
P2(COMPLEX128, COMPLEX128), R1(COMPLEX128))
// Make a slice.
-DEF_GO_RUNTIME(MAKESLICE, "runtime.makeslice", P3(TYPE, INT64, INT64),
+DEF_GO_RUNTIME(MAKESLICE, "runtime.makeslice", P3(TYPE, INT, INT),
+ R1(SLICE))
+
+DEF_GO_RUNTIME(MAKESLICE64, "runtime.makeslice64", P3(TYPE, INT64, INT64),
R1(SLICE))
@@ -119,8 +119,8 @@ DEF_GO_RUNTIME(MAPACCESS2_FAT, "runtime.mapaccess2_fat",
P4(TYPE, MAP, POINTER, POINTER), R2(POINTER, BOOL))
// Assignment to a key in a map.
-DEF_GO_RUNTIME(MAPASSIGN, "runtime.mapassign1",
- P4(TYPE, MAP, POINTER, POINTER), R0())
+DEF_GO_RUNTIME(MAPASSIGN, "runtime.mapassign", P3(TYPE, MAP, POINTER),
+ R1(POINTER))
// Delete a key from a map.
DEF_GO_RUNTIME(MAPDELETE, "runtime.mapdelete", P3(TYPE, MAP, POINTER), R0())
diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc
index dc226e8b21e..d6ab4ccd674 100644
--- a/gcc/go/gofrontend/statements.cc
+++ b/gcc/go/gofrontend/statements.cc
@@ -707,8 +707,8 @@ Assignment_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
Move_ordered_evals moe(b);
mie->traverse_subexpressions(&moe);
- // Copy key and value into temporaries so that we can take their
- // address without pushing the value onto the heap.
+ // Copy the key into a temporary so that we can take its address
+ // without pushing the value onto the heap.
// var key_temp KEY_TYPE = MAP_INDEX
Temporary_statement* key_temp = Statement::make_temporary(mt->key_type(),
@@ -716,23 +716,29 @@ Assignment_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
loc);
b->add_statement(key_temp);
+ // Copy the value into a temporary to ensure that it is
+ // evaluated before we add the key to the map. This may matter
+ // if the value is itself a reference to the map.
+
// var val_temp VAL_TYPE = RHS
Temporary_statement* val_temp = Statement::make_temporary(mt->val_type(),
this->rhs_,
loc);
b->add_statement(val_temp);
- // mapassign1(TYPE, MAP, &key_temp, &val_temp)
+ // *mapassign(TYPE, MAP, &key_temp) = RHS
Expression* a1 = Expression::make_type_descriptor(mt, loc);
Expression* a2 = mie->map();
Temporary_reference_expression* ref =
Expression::make_temporary_reference(key_temp, loc);
Expression* a3 = Expression::make_unary(OPERATOR_AND, ref, loc);
+ Expression* call = Runtime::make_call(Runtime::MAPASSIGN, loc, 3,
+ a1, a2, a3);
+ Type* ptrval_type = Type::make_pointer_type(mt->val_type());
+ call = Expression::make_cast(ptrval_type, call, loc);
+ Expression* indir = Expression::make_unary(OPERATOR_MULT, call, loc);
ref = Expression::make_temporary_reference(val_temp, loc);
- Expression* a4 = Expression::make_unary(OPERATOR_AND, ref, loc);
- Expression* call = Runtime::make_call(Runtime::MAPASSIGN, loc, 4,
- a1, a2, a3, a4);
- b->add_statement(Statement::make_statement(call, false));
+ b->add_statement(Statement::make_assignment(indir, ref, loc));
return Statement::make_block_statement(b, loc);
}
@@ -5313,7 +5319,7 @@ For_range_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing,
else if (range_type->is_string_type())
{
index_type = Type::lookup_integer_type("int");
- value_type = Type::lookup_integer_type("int32");
+ value_type = gogo->lookup_global("rune")->type_value();
}
else if (range_type->map_type() != NULL)
{
@@ -5458,7 +5464,7 @@ For_range_statement::make_range_ref(Named_object* range_object,
// Return a call to the predeclared function FUNCNAME passing a
// reference to the temporary variable ARG.
-Expression*
+Call_expression*
For_range_statement::call_builtin(Gogo* gogo, const char* funcname,
Expression* arg,
Location loc)
@@ -5664,7 +5670,7 @@ For_range_statement::lower_range_slice(Gogo* gogo,
// Lower a for range over a string.
void
-For_range_statement::lower_range_string(Gogo*,
+For_range_statement::lower_range_string(Gogo* gogo,
Block* enclosing,
Block* body_block,
Named_object* range_object,
@@ -5679,94 +5685,121 @@ For_range_statement::lower_range_string(Gogo*,
Location loc = this->location();
// The loop we generate:
+ // len_temp := len(range)
// var next_index_temp int
- // for index_temp = 0; ; index_temp = next_index_temp {
- // next_index_temp, value_temp = stringiter2(range, index_temp)
- // if next_index_temp == 0 {
- // break
+ // for index_temp = 0; index_temp < len_temp; index_temp = next_index_temp {
+ // value_temp = rune(range[index_temp])
+ // if value_temp < utf8.RuneSelf {
+ // next_index_temp = index_temp + 1
+ // } else {
+ // value_temp, next_index_temp = decoderune(range, index_temp)
// }
// index = index_temp
// value = value_temp
- // original body
+ // // original body
// }
// Set *PINIT to
+ // len_temp := len(range)
// var next_index_temp int
// index_temp = 0
+ // var value_temp rune // if value_temp not passed in
Block* init = new Block(enclosing, loc);
+ Expression* ref = this->make_range_ref(range_object, range_temp, loc);
+ Call_expression* call = this->call_builtin(gogo, "len", ref, loc);
+ Temporary_statement* len_temp =
+ Statement::make_temporary(index_temp->type(), call, loc);
+ init->add_statement(len_temp);
+
Temporary_statement* next_index_temp =
Statement::make_temporary(index_temp->type(), NULL, loc);
init->add_statement(next_index_temp);
- Expression* zexpr = Expression::make_integer_ul(0, NULL, loc);
-
- Temporary_reference_expression* ref =
+ Temporary_reference_expression* index_ref =
Expression::make_temporary_reference(index_temp, loc);
- ref->set_is_lvalue();
- Statement* s = Statement::make_assignment(ref, zexpr, loc);
-
+ index_ref->set_is_lvalue();
+ Expression* zexpr = Expression::make_integer_ul(0, index_temp->type(), loc);
+ Statement* s = Statement::make_assignment(index_ref, zexpr, loc);
init->add_statement(s);
+
+ Type* rune_type;
+ if (value_temp != NULL)
+ rune_type = value_temp->type();
+ else
+ {
+ rune_type = gogo->lookup_global("rune")->type_value();
+ value_temp = Statement::make_temporary(rune_type, NULL, loc);
+ init->add_statement(value_temp);
+ }
+
*pinit = init;
- // The loop has no condition.
+ // Set *PCOND to
+ // index_temp < len_temp
- *pcond = NULL;
+ index_ref = Expression::make_temporary_reference(index_temp, loc);
+ Expression* len_ref =
+ Expression::make_temporary_reference(len_temp, loc);
+ *pcond = Expression::make_binary(OPERATOR_LT, index_ref, len_ref, loc);
// Set *PITER_INIT to
- // next_index_temp = runtime.stringiter(range, index_temp)
- // or
- // next_index_temp, value_temp = runtime.stringiter2(range, index_temp)
- // followed by
- // if next_index_temp == 0 {
- // break
+ // value_temp = rune(range[index_temp])
+ // if value_temp < utf8.RuneSelf {
+ // next_index_temp = index_temp + 1
+ // } else {
+ // value_temp, next_index_temp = decoderune(range, index_temp)
// }
Block* iter_init = new Block(body_block, loc);
- Expression* p1 = this->make_range_ref(range_object, range_temp, loc);
- Expression* p2 = Expression::make_temporary_reference(index_temp, loc);
- Call_expression* call = Runtime::make_call((value_temp == NULL
- ? Runtime::STRINGITER
- : Runtime::STRINGITER2),
- loc, 2, p1, p2);
+ ref = this->make_range_ref(range_object, range_temp, loc);
+ index_ref = Expression::make_temporary_reference(index_temp, loc);
+ ref = Expression::make_string_index(ref, index_ref, NULL, loc);
+ ref = Expression::make_cast(rune_type, ref, loc);
+ Temporary_reference_expression* value_ref =
+ Expression::make_temporary_reference(value_temp, loc);
+ value_ref->set_is_lvalue();
+ s = Statement::make_assignment(value_ref, ref, loc);
+ iter_init->add_statement(s);
- if (value_temp == NULL)
- {
- ref = Expression::make_temporary_reference(next_index_temp, loc);
- ref->set_is_lvalue();
- s = Statement::make_assignment(ref, call, loc);
- }
- else
- {
- Expression_list* lhs = new Expression_list();
+ value_ref = Expression::make_temporary_reference(value_temp, loc);
+ Expression* rune_self = Expression::make_integer_ul(0x80, rune_type, loc);
+ Expression* cond = Expression::make_binary(OPERATOR_LT, value_ref, rune_self,
+ loc);
- ref = Expression::make_temporary_reference(next_index_temp, loc);
- ref->set_is_lvalue();
- lhs->push_back(ref);
+ Block* then_block = new Block(iter_init, loc);
- ref = Expression::make_temporary_reference(value_temp, loc);
- ref->set_is_lvalue();
- lhs->push_back(ref);
+ Temporary_reference_expression* lhs =
+ Expression::make_temporary_reference(next_index_temp, loc);
+ lhs->set_is_lvalue();
+ index_ref = Expression::make_temporary_reference(index_temp, loc);
+ Expression* one = Expression::make_integer_ul(1, index_temp->type(), loc);
+ Expression* sum = Expression::make_binary(OPERATOR_PLUS, index_ref, one,
+ loc);
+ s = Statement::make_assignment(lhs, sum, loc);
+ then_block->add_statement(s);
- Expression_list* rhs = new Expression_list();
- rhs->push_back(Expression::make_call_result(call, 0));
- rhs->push_back(Expression::make_call_result(call, 1));
+ Block* else_block = new Block(iter_init, loc);
- s = Statement::make_tuple_assignment(lhs, rhs, loc);
- }
- iter_init->add_statement(s);
+ ref = this->make_range_ref(range_object, range_temp, loc);
+ index_ref = Expression::make_temporary_reference(index_temp, loc);
+ call = Runtime::make_call(Runtime::DECODERUNE, loc, 2, ref, index_ref);
- ref = Expression::make_temporary_reference(next_index_temp, loc);
- zexpr = Expression::make_integer_ul(0, NULL, loc);
- Expression* equals = Expression::make_binary(OPERATOR_EQEQ, ref, zexpr, loc);
+ value_ref = Expression::make_temporary_reference(value_temp, loc);
+ value_ref->set_is_lvalue();
+ Expression* res = Expression::make_call_result(call, 0);
+ s = Statement::make_assignment(value_ref, res, loc);
+ else_block->add_statement(s);
- Block* then_block = new Block(iter_init, loc);
- s = Statement::make_break_statement(this->break_label(), loc);
- then_block->add_statement(s);
+ lhs = Expression::make_temporary_reference(next_index_temp, loc);
+ lhs->set_is_lvalue();
+ res = Expression::make_call_result(call, 1);
+ s = Statement::make_assignment(lhs, res, loc);
+ else_block->add_statement(s);
- s = Statement::make_if_statement(equals, then_block, NULL, loc);
+ s = Statement::make_if_statement(cond, then_block, else_block, loc);
iter_init->add_statement(s);
*piter_init = iter_init;
@@ -5776,11 +5809,10 @@ For_range_statement::lower_range_string(Gogo*,
Block* post = new Block(enclosing, loc);
- Temporary_reference_expression* lhs =
- Expression::make_temporary_reference(index_temp, loc);
- lhs->set_is_lvalue();
- Expression* rhs = Expression::make_temporary_reference(next_index_temp, loc);
- s = Statement::make_assignment(lhs, rhs, loc);
+ index_ref = Expression::make_temporary_reference(index_temp, loc);
+ index_ref->set_is_lvalue();
+ ref = Expression::make_temporary_reference(next_index_temp, loc);
+ s = Statement::make_assignment(index_ref, ref, loc);
post->add_statement(s);
*ppost = post;
diff --git a/gcc/go/gofrontend/statements.h b/gcc/go/gofrontend/statements.h
index 2d395d077ba..dac99de4cae 100644
--- a/gcc/go/gofrontend/statements.h
+++ b/gcc/go/gofrontend/statements.h
@@ -1500,7 +1500,7 @@ class For_range_statement : public Statement
Expression*
make_range_ref(Named_object*, Temporary_statement*, Location);
- Expression*
+ Call_expression*
call_builtin(Gogo*, const char* funcname, Expression* arg, Location);
void
diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc
index ace23d0c27b..0d14adf65b5 100644
--- a/gcc/go/gofrontend/types.cc
+++ b/gcc/go/gofrontend/types.cc
@@ -7319,7 +7319,7 @@ Map_type::do_get_backend(Gogo* gogo)
static Btype* backend_map_type;
if (backend_map_type == NULL)
{
- std::vector<Backend::Btyped_identifier> bfields(8);
+ std::vector<Backend::Btyped_identifier> bfields(9);
Location bloc = Linemap::predeclared_location();
@@ -7337,30 +7337,35 @@ Map_type::do_get_backend(Gogo* gogo)
bfields[2].btype = bfields[1].btype;
bfields[2].location = bloc;
- Type* uint32_type = Type::lookup_integer_type("uint32");
- bfields[3].name = "hash0";
- bfields[3].btype = uint32_type->get_backend(gogo);
+ Type* uint16_type = Type::lookup_integer_type("uint16");
+ bfields[3].name = "noverflow";
+ bfields[3].btype = uint16_type->get_backend(gogo);
bfields[3].location = bloc;
- Btype* bvt = gogo->backend()->void_type();
- Btype* bpvt = gogo->backend()->pointer_type(bvt);
- bfields[4].name = "buckets";
- bfields[4].btype = bpvt;
+ Type* uint32_type = Type::lookup_integer_type("uint32");
+ bfields[4].name = "hash0";
+ bfields[4].btype = uint32_type->get_backend(gogo);
bfields[4].location = bloc;
- bfields[5].name = "oldbuckets";
+ Btype* bvt = gogo->backend()->void_type();
+ Btype* bpvt = gogo->backend()->pointer_type(bvt);
+ bfields[5].name = "buckets";
bfields[5].btype = bpvt;
bfields[5].location = bloc;
- Type* uintptr_type = Type::lookup_integer_type("uintptr");
- bfields[6].name = "nevacuate";
- bfields[6].btype = uintptr_type->get_backend(gogo);
+ bfields[6].name = "oldbuckets";
+ bfields[6].btype = bpvt;
bfields[6].location = bloc;
- bfields[7].name = "overflow";
- bfields[7].btype = bpvt;
+ Type* uintptr_type = Type::lookup_integer_type("uintptr");
+ bfields[7].name = "nevacuate";
+ bfields[7].btype = uintptr_type->get_backend(gogo);
bfields[7].location = bloc;
+ bfields[8].name = "overflow";
+ bfields[8].btype = bpvt;
+ bfields[8].location = bloc;
+
Btype *bt = gogo->backend()->struct_type(bfields);
bt = gogo->backend()->named_type("runtime.hmap", bt, bloc);
backend_map_type = gogo->backend()->pointer_type(bt);