-2609f9b8420e2341fbbe40d7cf6af42b0fba7293
+bc7374913367fba9b10dc284af87eb539fb6c5b2
The first line of this file holds the git revision number of the last
merge done from the gofrontend repository.
}
break;
+ case Runtime::MAPASSIGN_FAST32PTR:
+ case Runtime::MAPASSIGN_FAST64PTR:
+ case Runtime::MAPASSIGN_FASTSTR:
+ {
+ // Map key escapes. The last argument is the key.
+ Node* key_node = Node::make_node(call->args()->back());
+ this->assign(this->context_->sink(), key_node);
+ }
+ break;
+
case Runtime::IFACEE2T2:
case Runtime::IFACEI2T2:
{
case BUILTIN_DELETE:
{
- // Lower to a runtime function call.
- const Expression_list* args = this->args();
- if (args == NULL || args->size() < 2)
- this->report_error(_("not enough arguments"));
- else if (args->size() > 2)
- this->report_error(_("too many arguments"));
- else if (args->front()->type()->map_type() == NULL)
- this->report_error(_("argument 1 must be a map"));
- else
- {
- // Since this function returns no value it must appear in
- // a statement by itself, so we don't have to worry about
- // order of evaluation of values around it. Evaluate the
- // map first to get order of evaluation right.
- Map_type* mt = args->front()->type()->map_type();
- Temporary_statement* map_temp =
- Statement::make_temporary(mt, args->front(), loc);
- inserter->insert(map_temp);
-
- Temporary_statement* key_temp =
- Statement::make_temporary(mt->key_type(), args->back(), loc);
- inserter->insert(key_temp);
-
- Expression* e1 = Expression::make_type_descriptor(mt, loc);
- Expression* e2 = Expression::make_temporary_reference(map_temp,
- loc);
- Expression* e3 = Expression::make_temporary_reference(key_temp,
- loc);
-
- // If the call to delete is deferred, and is in a loop,
- // then the loop will only have a single instance of the
- // temporary variable. Passing the address of the
- // temporary variable here means that the deferred call
- // will see the last value in the loop, not the current
- // value. So for this unusual case copy the value into
- // the heap.
- if (!this->is_deferred())
- e3 = Expression::make_unary(OPERATOR_AND, e3, loc);
- else
- {
- Expression* a = Expression::make_allocation(mt->key_type(),
- loc);
- Temporary_statement* atemp =
- Statement::make_temporary(NULL, a, loc);
- inserter->insert(atemp);
-
- a = Expression::make_temporary_reference(atemp, loc);
- a = Expression::make_dereference(a, NIL_CHECK_NOT_NEEDED, loc);
- Statement* s = Statement::make_assignment(a, e3, loc);
- inserter->insert(s);
-
- e3 = Expression::make_temporary_reference(atemp, loc);
- }
-
- return Runtime::make_call(Runtime::MAPDELETE, this->location(),
- 3, e1, e2, e3);
- }
+ const Expression_list* args = this->args();
+ if (args == NULL || args->size() < 2)
+ this->report_error(_("not enough arguments"));
+ else if (args->size() > 2)
+ this->report_error(_("too many arguments"));
+ else if (args->front()->type()->map_type() == NULL)
+ this->report_error(_("argument 1 must be a map"));
+ else
+ {
+ Type* key_type =
+ args->front()->type()->map_type()->key_type();
+ Expression_list::iterator pa = this->args()->begin();
+ pa++;
+ Type* arg_type = (*pa)->type();
+ std::string reason;
+ if (!Type::are_assignable(key_type, arg_type, &reason))
+ {
+ if (reason.empty())
+ go_error_at(loc, "argument 2 has incompatible type");
+ else
+ go_error_at(loc, "argument 2 has incompatible type (%s)",
+ reason.c_str());
+ this->set_is_error();
+ }
+ else if (!Type::are_identical(key_type, arg_type, 0, NULL))
+ *pa = Expression::make_cast(key_type, *pa, loc);
+ }
}
break;
Builtin_call_expression::do_flatten(Gogo* gogo, Named_object* function,
Statement_inserter* inserter)
{
+ if (this->is_error_expression())
+ {
+ go_assert(saw_errors());
+ return this;
+ }
+
Location loc = this->location();
switch (this->code_)
}
}
break;
+
+ case BUILTIN_DELETE:
+ {
+ // Lower to a runtime function call.
+ const Expression_list* args = this->args();
+
+ // Since this function returns no value it must appear in
+ // a statement by itself, so we don't have to worry about
+ // order of evaluation of values around it. Evaluate the
+ // map first to get order of evaluation right.
+ Map_type* mt = args->front()->type()->map_type();
+ Temporary_statement* map_temp =
+ Statement::make_temporary(mt, args->front(), loc);
+ inserter->insert(map_temp);
+
+ Temporary_statement* key_temp =
+ Statement::make_temporary(mt->key_type(), args->back(), loc);
+ inserter->insert(key_temp);
+
+ Expression* e1 = Expression::make_type_descriptor(mt, loc);
+ Expression* e2 = Expression::make_temporary_reference(map_temp,
+ loc);
+ Expression* e3 = Expression::make_temporary_reference(key_temp,
+ loc);
+
+ Runtime::Function code;
+ switch (mt->algorithm(gogo))
+ {
+ case Map_type::MAP_ALG_FAST32:
+ case Map_type::MAP_ALG_FAST32PTR:
+ {
+ code = Runtime::MAPDELETE_FAST32;
+ Type* uint32_type = Type::lookup_integer_type("uint32");
+ Type* uint32_ptr_type = Type::make_pointer_type(uint32_type);
+ e3 = Expression::make_unary(OPERATOR_AND, e3, loc);
+ e3 = Expression::make_unsafe_cast(uint32_ptr_type, e3,
+ loc);
+ e3 = Expression::make_dereference(e3,
+ Expression::NIL_CHECK_NOT_NEEDED,
+ loc);
+ break;
+ }
+ case Map_type::MAP_ALG_FAST64:
+ case Map_type::MAP_ALG_FAST64PTR:
+ {
+ code = Runtime::MAPDELETE_FAST64;
+ Type* uint64_type = Type::lookup_integer_type("uint64");
+ Type* uint64_ptr_type = Type::make_pointer_type(uint64_type);
+ e3 = Expression::make_unary(OPERATOR_AND, e3, loc);
+ e3 = Expression::make_unsafe_cast(uint64_ptr_type, e3,
+ loc);
+ e3 = Expression::make_dereference(e3,
+ Expression::NIL_CHECK_NOT_NEEDED,
+ loc);
+ break;
+ }
+ case Map_type::MAP_ALG_FASTSTR:
+ code = Runtime::MAPDELETE_FASTSTR;
+ break;
+ default:
+ code = Runtime::MAPDELETE;
+
+ // If the call to delete is deferred, and is in a loop,
+ // then the loop will only have a single instance of the
+ // temporary variable. Passing the address of the
+ // temporary variable here means that the deferred call
+ // will see the last value in the loop, not the current
+ // value. So for this unusual case copy the value into
+ // the heap.
+ if (!this->is_deferred())
+ e3 = Expression::make_unary(OPERATOR_AND, e3, loc);
+ else
+ {
+ Expression* a = Expression::make_allocation(mt->key_type(),
+ loc);
+ Temporary_statement* atemp =
+ Statement::make_temporary(NULL, a, loc);
+ inserter->insert(atemp);
+
+ a = Expression::make_temporary_reference(atemp, loc);
+ a = Expression::make_dereference(a, NIL_CHECK_NOT_NEEDED, loc);
+ Statement* s = Statement::make_assignment(a, e3, loc);
+ inserter->insert(s);
+
+ e3 = Expression::make_temporary_reference(atemp, loc);
+ }
+ }
+
+ return Runtime::make_call(code, loc, 3, e1, e2, e3);
+ }
}
return this;
case BUILTIN_CAP:
s = "cap";
break;
+ case BUILTIN_DELETE:
+ s = "delete";
+ break;
case BUILTIN_PRINT:
s = "print";
break;
this->index_,
loc);
+ Expression* type_expr = Expression::make_type_descriptor(type, loc);
Expression* zero = type->fat_zero_value(gogo);
-
Expression* map_index;
-
if (zero == NULL)
- map_index =
- Runtime::make_call(Runtime::MAPACCESS1, loc, 3,
- Expression::make_type_descriptor(type, loc),
- map_ref, index_ptr);
+ {
+ Runtime::Function code;
+ Expression* key;
+ switch (type->algorithm(gogo))
+ {
+ case Map_type::MAP_ALG_FAST32:
+ case Map_type::MAP_ALG_FAST32PTR:
+ {
+ Type* uint32_type = Type::lookup_integer_type("uint32");
+ Type* uint32_ptr_type = Type::make_pointer_type(uint32_type);
+ key = Expression::make_unsafe_cast(uint32_ptr_type, index_ptr,
+ loc);
+ key = Expression::make_dereference(key, NIL_CHECK_NOT_NEEDED,
+ loc);
+ code = Runtime::MAPACCESS1_FAST32;
+ break;
+ }
+ case Map_type::MAP_ALG_FAST64:
+ case Map_type::MAP_ALG_FAST64PTR:
+ {
+ Type* uint64_type = Type::lookup_integer_type("uint64");
+ Type* uint64_ptr_type = Type::make_pointer_type(uint64_type);
+ key = Expression::make_unsafe_cast(uint64_ptr_type, index_ptr,
+ loc);
+ key = Expression::make_dereference(key, NIL_CHECK_NOT_NEEDED,
+ loc);
+ code = Runtime::MAPACCESS1_FAST64;
+ break;
+ }
+ case Map_type::MAP_ALG_FASTSTR:
+ key = this->index_;
+ code = Runtime::MAPACCESS1_FASTSTR;
+ break;
+ default:
+ key = index_ptr;
+ code = Runtime::MAPACCESS1;
+ break;
+ }
+ map_index = Runtime::make_call(code, loc, 3,
+ type_expr, map_ref, key);
+ }
else
- map_index =
- Runtime::make_call(Runtime::MAPACCESS1_FAT, loc, 4,
- Expression::make_type_descriptor(type, loc),
- map_ref, index_ptr, zero);
+ map_index = Runtime::make_call(Runtime::MAPACCESS1_FAT, loc, 4,
+ type_expr, map_ref, index_ptr, zero);
Type* val_type = type->val_type();
this->value_pointer_ =
DEF_GO_RUNTIME(MAPACCESS1, "runtime.mapaccess1", P3(TYPE, MAP, POINTER),
R1(POINTER))
+// Look up a uint32 key in a map.
+DEF_GO_RUNTIME(MAPACCESS1_FAST32, "runtime.mapaccess1_fast32",
+ P3(TYPE, MAP, UINT32), R1(POINTER))
+
+// Look up a uint64 key in a map.
+DEF_GO_RUNTIME(MAPACCESS1_FAST64, "runtime.mapaccess1_fast64",
+ P3(TYPE, MAP, UINT64), R1(POINTER))
+
+// Look up a string key in a map.
+DEF_GO_RUNTIME(MAPACCESS1_FASTSTR, "runtime.mapaccess1_faststr",
+ P3(TYPE, MAP, STRING), R1(POINTER))
+
// Look up a key in a map when the value is large.
DEF_GO_RUNTIME(MAPACCESS1_FAT, "runtime.mapaccess1_fat",
P4(TYPE, MAP, POINTER, POINTER), R1(POINTER))
DEF_GO_RUNTIME(MAPACCESS2, "runtime.mapaccess2", P3(TYPE, MAP, POINTER),
R2(POINTER, BOOL))
+// Look up a uint32 key in a map returning the value and whether
+// it is present.
+DEF_GO_RUNTIME(MAPACCESS2_FAST32, "runtime.mapaccess2_fast32",
+ P3(TYPE, MAP, UINT32), R2(POINTER, BOOL))
+
+// Look up a uint64 key in a map returning the value and whether
+// it is present.
+DEF_GO_RUNTIME(MAPACCESS2_FAST64, "runtime.mapaccess2_fast64",
+ P3(TYPE, MAP, UINT64), R2(POINTER, BOOL))
+
+// Look up a string key in a map returning the value and whether
+// it is present.
+DEF_GO_RUNTIME(MAPACCESS2_FASTSTR, "runtime.mapaccess2_faststr",
+ P3(TYPE, MAP, STRING), R2(POINTER, BOOL))
+
// Look up a key in a map, returning the value and whether it is
// present, when the value is large.
DEF_GO_RUNTIME(MAPACCESS2_FAT, "runtime.mapaccess2_fat",
DEF_GO_RUNTIME(MAPASSIGN, "runtime.mapassign", P3(TYPE, MAP, POINTER),
R1(POINTER))
+// Assignment to a uint32 key in a map.
+DEF_GO_RUNTIME(MAPASSIGN_FAST32, "runtime.mapassign_fast32",
+ P3(TYPE, MAP, UINT32), R1(POINTER))
+
+// Assignment to a uint64 key in a map.
+DEF_GO_RUNTIME(MAPASSIGN_FAST64, "runtime.mapassign_fast64",
+ P3(TYPE, MAP, UINT64), R1(POINTER))
+
+// Assignment to a 32-bit pointer key in a map.
+DEF_GO_RUNTIME(MAPASSIGN_FAST32PTR, "runtime.mapassign_fast32ptr",
+ P3(TYPE, MAP, POINTER), R1(POINTER))
+
+// Assignment to a 64-bit pointer key in a map.
+DEF_GO_RUNTIME(MAPASSIGN_FAST64PTR, "runtime.mapassign_fast64ptr",
+ P3(TYPE, MAP, POINTER), R1(POINTER))
+
+// Assignment to a string key in a map.
+DEF_GO_RUNTIME(MAPASSIGN_FASTSTR, "runtime.mapassign_faststr",
+ P3(TYPE, MAP, STRING), R1(POINTER))
+
// Delete a key from a map.
DEF_GO_RUNTIME(MAPDELETE, "runtime.mapdelete", P3(TYPE, MAP, POINTER), R0())
+// Delete a uint32 key from a map.
+DEF_GO_RUNTIME(MAPDELETE_FAST32, "runtime.mapdelete_fast32",
+ P3(TYPE, MAP, UINT32), R0())
+
+// Delete a uint64 key from a map.
+DEF_GO_RUNTIME(MAPDELETE_FAST64, "runtime.mapdelete_fast64",
+ P3(TYPE, MAP, UINT64), R0())
+
+// Delete a string key from a map.
+DEF_GO_RUNTIME(MAPDELETE_FASTSTR, "runtime.mapdelete_faststr",
+ P3(TYPE, MAP, STRING), R0())
+
// Begin a range over a map.
DEF_GO_RUNTIME(MAPITERINIT, "runtime.mapiterinit", P3(TYPE, MAP, POINTER),
R0())
// call. Mark some slice assignments as not requiring a write barrier.
Statement*
-Assignment_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
+Assignment_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing,
Statement_inserter*)
{
Map_index_expression* mie = this->lhs_->map_index_expression();
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,
+ Runtime::Function code;
+ Map_type::Map_alg alg = mt->algorithm(gogo);
+ switch (alg)
+ {
+ case Map_type::MAP_ALG_FAST32:
+ {
+ code = Runtime::MAPASSIGN_FAST32;
+ Type* uint32_type = Type::lookup_integer_type("uint32");
+ Type* uint32_ptr_type = Type::make_pointer_type(uint32_type);
+ a3 = Expression::make_unsafe_cast(uint32_ptr_type, a3,
+ loc);
+ a3 = Expression::make_dereference(a3,
+ Expression::NIL_CHECK_NOT_NEEDED,
+ loc);
+ break;
+ }
+ case Map_type::MAP_ALG_FAST64:
+ {
+ code = Runtime::MAPASSIGN_FAST64;
+ Type* uint64_type = Type::lookup_integer_type("uint64");
+ Type* uint64_ptr_type = Type::make_pointer_type(uint64_type);
+ a3 = Expression::make_unsafe_cast(uint64_ptr_type, a3,
+ loc);
+ a3 = Expression::make_dereference(a3,
+ Expression::NIL_CHECK_NOT_NEEDED,
+ loc);
+ break;
+ }
+ case Map_type::MAP_ALG_FAST32PTR:
+ case Map_type::MAP_ALG_FAST64PTR:
+ {
+ code = (alg == Map_type::MAP_ALG_FAST32PTR
+ ? Runtime::MAPASSIGN_FAST32PTR
+ : Runtime::MAPASSIGN_FAST64PTR);
+ Type* ptr_type =
+ Type::make_pointer_type(Type::make_void_type());
+ Type* ptr_ptr_type = Type::make_pointer_type(ptr_type);
+ a3 = Expression::make_unsafe_cast(ptr_ptr_type, a3,
+ loc);
+ a3 = Expression::make_dereference(a3,
+ Expression::NIL_CHECK_NOT_NEEDED,
+ loc);
+ break;
+ }
+ case Map_type::MAP_ALG_FASTSTR:
+ code = Runtime::MAPASSIGN_FASTSTR;
+ a3 = ref;
+ break;
+ default:
+ code = Runtime::MAPASSIGN;
+ break;
+ }
+ Expression* call = Runtime::make_call(code, loc, 3,
a1, a2, a3);
Type* ptrval_type = Type::make_pointer_type(mt->val_type());
call = Expression::make_cast(ptrval_type, call, loc);
Expression* a4 = map_type->fat_zero_value(gogo);
Call_expression* call;
if (a4 == NULL)
- call = Runtime::make_call(Runtime::MAPACCESS2, loc, 3, a1, a2, a3);
+ {
+ Runtime::Function code;
+ Map_type::Map_alg alg = map_type->algorithm(gogo);
+ switch (alg)
+ {
+ case Map_type::MAP_ALG_FAST32:
+ case Map_type::MAP_ALG_FAST32PTR:
+ {
+ code = Runtime::MAPACCESS2_FAST32;
+ Type* uint32_type = Type::lookup_integer_type("uint32");
+ Type* uint32_ptr_type = Type::make_pointer_type(uint32_type);
+ a3 = Expression::make_unsafe_cast(uint32_ptr_type, a3,
+ loc);
+ a3 = Expression::make_dereference(a3,
+ Expression::NIL_CHECK_NOT_NEEDED,
+ loc);
+ break;
+ }
+ case Map_type::MAP_ALG_FAST64:
+ case Map_type::MAP_ALG_FAST64PTR:
+ {
+ code = Runtime::MAPACCESS2_FAST64;
+ Type* uint64_type = Type::lookup_integer_type("uint64");
+ Type* uint64_ptr_type = Type::make_pointer_type(uint64_type);
+ a3 = Expression::make_unsafe_cast(uint64_ptr_type, a3,
+ loc);
+ a3 = Expression::make_dereference(a3,
+ Expression::NIL_CHECK_NOT_NEEDED,
+ loc);
+ break;
+ }
+ case Map_type::MAP_ALG_FASTSTR:
+ code = Runtime::MAPACCESS2_FASTSTR;
+ a3 = ref;
+ break;
+ default:
+ code = Runtime::MAPACCESS2;
+ break;
+ }
+ call = Runtime::make_call(code, loc, 3, a1, a2, a3);
+ }
else
call = Runtime::make_call(Runtime::MAPACCESS2_FAT, loc, 4, a1, a2, a3, a4);
ref = Expression::make_temporary_reference(val_ptr_temp, loc);
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)
-
+ // Match the body, a single call statement delete(m, k).
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)
+ if (statements->size() != 1)
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)
+ Expression_statement* es = statements->at(0)->expression_statement();
+ if (es == NULL)
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)
+ Call_expression* call = es->expr()->call_expression();
+ if (call == NULL || !call->is_builtin()
+ || call->builtin_call_expression()->code()
+ != Builtin_call_expression::BUILTIN_DELETE)
return NULL;
- tre = ue->operand()->temporary_reference_expression();
- if (tre == NULL || tre->statement() != ts2)
+ if (!Expression::is_same_variable(call->args()->at(0), orig_range_expr)
+ || !Expression::is_same_variable(call->args()->at(1), this->index_var_))
return NULL;
// Everything matches. Rewrite to mapclear(TYPE, MAP).
// pass as the zero value to those functions. Otherwise, in the
// normal case, return NULL. The map requires the "fat" functions if
// the value size is larger than max_zero_size bytes. max_zero_size
-// must match maxZero in libgo/go/runtime/hashmap.go.
+// must match maxZero in libgo/go/runtime/map.go.
Expression*
Map_type::fat_zero_value(Gogo* gogo)
return z;
}
+// Map algorithm to use for this map type.
+
+Map_type::Map_alg
+Map_type::algorithm(Gogo* gogo)
+{
+ int64_t size;
+ bool ok = this->val_type_->backend_type_size(gogo, &size);
+ if (!ok || size > Map_type::max_val_size)
+ return MAP_ALG_SLOW;
+
+ Type* key_type = this->key_type_;
+ if (key_type->is_string_type())
+ return MAP_ALG_FASTSTR;
+ if (!key_type->compare_is_identity(gogo))
+ return MAP_ALG_SLOW;
+
+ ok = key_type->backend_type_size(gogo, &size);
+ if (!ok)
+ return MAP_ALG_SLOW;
+ if (size == 4)
+ return (key_type->has_pointer()
+ ? MAP_ALG_FAST32PTR
+ : MAP_ALG_FAST32);
+ if (size == 8)
+ {
+ if (!key_type->has_pointer())
+ return MAP_ALG_FAST64;
+ Type* ptr_type = Type::make_pointer_type(Type::make_void_type());
+ ok = ptr_type->backend_type_size(gogo, &size);
+ if (ok && size == 8)
+ return MAP_ALG_FAST64PTR;
+ // Key contains pointer but is not a single pointer.
+ // Use slow version.
+ }
+ return MAP_ALG_SLOW;
+}
+
// Return whether VAR is the map zero value.
bool
// Get the backend representation for a map type. A map type is
// represented as a pointer to a struct. The struct is hmap in
-// runtime/hashmap.go.
+// runtime/map.go.
Btype*
Map_type::do_get_backend(Gogo* gogo)
}
// Return the bucket type to use for a map type. This must correspond
-// to libgo/go/runtime/hashmap.go.
+// to libgo/go/runtime/map.go.
Type*
Map_type::bucket_type(Gogo* gogo, int64_t keysize, int64_t valsize)
// be marked as having no pointers. Arrange for the bucket to have
// no pointers by changing the type of the overflow field to uintptr
// in this case. See comment on the hmap.overflow field in
- // libgo/go/runtime/hashmap.go.
+ // libgo/go/runtime/map.go.
Type* overflow_type;
if (!key_type->has_pointer() && !val_type->has_pointer())
overflow_type = Type::lookup_integer_type("uintptr");
Expression*
fat_zero_value(Gogo*);
+ // Map algorithm to use for this map type. We may use specialized
+ // fast map routines for certain key types.
+ enum Map_alg
+ {
+ // 32-bit key.
+ MAP_ALG_FAST32,
+ // 32-bit pointer key.
+ MAP_ALG_FAST32PTR,
+ // 64-bit key.
+ MAP_ALG_FAST64,
+ // 64-bit pointer key.
+ MAP_ALG_FAST64PTR,
+ // String key.
+ MAP_ALG_FASTSTR,
+ // Anything else.
+ MAP_ALG_SLOW,
+ };
+
+ Map_alg
+ algorithm(Gogo*);
+
// Return whether VAR is the map zero value.
static bool
is_zero_value(Variable* var);
static Type*
make_map_type_descriptor_type();
- // This must be in sync with libgo/go/runtime/hashmap.go.
+ // This must be in sync with libgo/go/runtime/map.go.
static const int bucket_size = 8;
protected:
do_export(Export*) const;
private:
- // These must be in sync with libgo/go/runtime/hashmap.go.
+ // These must be in sync with libgo/go/runtime/map.go.
static const int max_key_size = 128;
static const int max_val_size = 128;
static const int max_zero_size = 1024;
"unsafe"
)
+// For gccgo, use go:linkname to rename compiler-called functions to
+// themselves, so that the compiler will export them.
+//
+//go:linkname mapaccess1_fast32 runtime.mapaccess1_fast32
+//go:linkname mapaccess2_fast32 runtime.mapaccess2_fast32
+//go:linkname mapassign_fast32 runtime.mapassign_fast32
+//go:linkname mapassign_fast32ptr runtime.mapassign_fast32ptr
+//go:linkname mapdelete_fast32 runtime.mapdelete_fast32
+
func mapaccess1_fast32(t *maptype, h *hmap, key uint32) unsafe.Pointer {
if raceenabled && h != nil {
callerpc := getcallerpc()
"unsafe"
)
+// For gccgo, use go:linkname to rename compiler-called functions to
+// themselves, so that the compiler will export them.
+//
+//go:linkname mapaccess1_fast64 runtime.mapaccess1_fast64
+//go:linkname mapaccess2_fast64 runtime.mapaccess2_fast64
+//go:linkname mapassign_fast64 runtime.mapassign_fast64
+//go:linkname mapassign_fast64ptr runtime.mapassign_fast64ptr
+//go:linkname mapdelete_fast64 runtime.mapdelete_fast64
+
func mapaccess1_fast64(t *maptype, h *hmap, key uint64) unsafe.Pointer {
if raceenabled && h != nil {
callerpc := getcallerpc()
"unsafe"
)
+// For gccgo, use go:linkname to rename compiler-called functions to
+// themselves, so that the compiler will export them.
+//
+//go:linkname mapaccess1_faststr runtime.mapaccess1_faststr
+//go:linkname mapaccess2_faststr runtime.mapaccess2_faststr
+//go:linkname mapassign_faststr runtime.mapassign_faststr
+//go:linkname mapdelete_faststr runtime.mapdelete_faststr
+
func mapaccess1_faststr(t *maptype, h *hmap, ky string) unsafe.Pointer {
if raceenabled && h != nil {
callerpc := getcallerpc()