Преглед изворни кода

Support any comparable type for map keys

gingerBill пре 4 година
родитељ
комит
5ab7ec5b16
4 измењених фајлова са 214 додато и 28 уклоњено
  1. 32 10
      src/check_type.cpp
  2. 87 9
      src/ir.cpp
  3. 89 9
      src/llvm_backend.cpp
  4. 6 0
      src/types.cpp

+ 32 - 10
src/check_type.cpp

@@ -2849,26 +2849,48 @@ void init_map_internal_types(Type *type) {
 }
 
 void add_map_key_type_dependencies(CheckerContext *ctx, Type *key) {
+	key = core_type(key);
+
 	if (is_type_cstring(key)) {
 		add_package_dependency(ctx, "runtime", "default_hasher_cstring");
 	} else if (is_type_string(key)) {
 		add_package_dependency(ctx, "runtime", "default_hasher_string");
 	} else if (!is_type_polymorphic(key)) {
-		if (!is_type_simple_compare(key)) {
+		if (!is_type_comparable(key)) {
 			return;
 		}
 
-		if (is_type_struct(key)) {
+		if (key->kind == Type_Struct) {
 			add_package_dependency(ctx, "runtime", "default_hasher_n");
-		}
+			if (!is_type_simple_compare(key)) {
+				for_array(i, key->Struct.fields) {
+					Entity *field = key->Struct.fields[i];
+					add_map_key_type_dependencies(ctx, field->type);
+				}
+			}
+		} else if (key->kind == Type_EnumeratedArray) {
+			add_package_dependency(ctx, "runtime", "default_hasher_n");
+			if (!is_type_simple_compare(key->EnumeratedArray.elem)) {
+				add_map_key_type_dependencies(ctx, key->EnumeratedArray.elem);
+			}
+		} else if (key->kind == Type_Array) {
+			add_package_dependency(ctx, "runtime", "default_hasher_n");
+			if (!is_type_simple_compare(key->Array.elem)) {
+				add_map_key_type_dependencies(ctx, key->Array.elem);
+			}
+		} else {
+			if (!is_type_simple_compare(key)) {
+				GB_PANIC("HERE");
+			}
 
-		i64 sz = type_size_of(key);
-		switch (sz) {
-		case  1: add_package_dependency(ctx, "runtime", "default_hasher1");  break;
-		case  2: add_package_dependency(ctx, "runtime", "default_hasher2");  break;
-		case  4: add_package_dependency(ctx, "runtime", "default_hasher4");  break;
-		case  8: add_package_dependency(ctx, "runtime", "default_hasher8");  break;
-		case 16: add_package_dependency(ctx, "runtime", "default_hasher16"); break;
+			i64 sz = type_size_of(key);
+			switch (sz) {
+			case  1: add_package_dependency(ctx, "runtime", "default_hasher1");  break;
+			case  2: add_package_dependency(ctx, "runtime", "default_hasher2");  break;
+			case  4: add_package_dependency(ctx, "runtime", "default_hasher4");  break;
+			case  8: add_package_dependency(ctx, "runtime", "default_hasher8");  break;
+			case 16: add_package_dependency(ctx, "runtime", "default_hasher16"); break;
+			}
 		}
 	}
 }

+ 87 - 9
src/ir.cpp

@@ -4967,7 +4967,7 @@ irValue *ir_get_equal_proc_for_type(irModule *m, Type *type) {
 
 irValue *ir_get_hasher_proc_for_type(irModule *m, Type *type) {
 	Type *original_type = type;
-	type = base_type(type);
+	type = core_type(type);
 	Type *pt = alloc_type_pointer(type);
 
 	GB_ASSERT(is_type_valid_for_keys(type));
@@ -5006,14 +5006,92 @@ irValue *ir_get_hasher_proc_for_type(irModule *m, Type *type) {
 
 	if (type->kind == Type_Struct) {
 		type_set_offsets(type);
-		GB_ASSERT(is_type_simple_compare(type));
-		i64 sz = type_size_of(type);
-		auto args = array_make<irValue *>(permanent_allocator(), 3);
-		args[0] = data;
-		args[1] = seed;
-		args[2] = ir_const_int(sz);
-		irValue *res = ir_emit_runtime_call(proc, "default_hasher_n", args);
-		ir_emit(proc, ir_instr_return(proc, res));
+		if (is_type_simple_compare(type)) {
+			i64 sz = type_size_of(type);
+			auto args = array_make<irValue *>(permanent_allocator(), 3);
+			args[0] = data;
+			args[1] = seed;
+			args[2] = ir_const_int(sz);
+			irValue *res = ir_emit_runtime_call(proc, "default_hasher_n", args);
+			ir_emit(proc, ir_instr_return(proc, res));
+		} else {
+			data = ir_emit_conv(proc, data, t_u8_ptr);
+
+			auto args = array_make<irValue *>(permanent_allocator(), 2);
+			for_array(i, type->Struct.fields) {
+				i64 offset = type->Struct.offsets[i];
+				Entity *field = type->Struct.fields[i];
+				irValue *field_hasher = ir_get_hasher_proc_for_type(m, field->type);
+				irValue *ptr = ir_emit_ptr_offset(proc, data, ir_const_uintptr(offset));
+
+				args[0] = ptr;
+				args[1] = seed;
+				seed = ir_emit_call(proc, field_hasher, args);
+			}
+			ir_emit(proc, ir_instr_return(proc, seed));
+		}
+	} else if (type->kind == Type_Array) {
+		if (is_type_simple_compare(type)) {
+			i64 sz = type_size_of(type);
+			auto args = array_make<irValue *>(permanent_allocator(), 3);
+			args[0] = data;
+			args[1] = seed;
+			args[2] = ir_const_int(sz);
+			irValue *res = ir_emit_runtime_call(proc, "default_hasher_n", args);
+			ir_emit(proc, ir_instr_return(proc, res));
+		} else {
+			irValue *pres = ir_add_local_generated(proc, t_uintptr, false);
+			ir_emit_store(proc, pres, seed);
+
+			auto args = array_make<irValue *>(permanent_allocator(), 2);
+			irValue *elem_hasher = ir_get_hasher_proc_for_type(m, type->Array.elem);
+
+			auto loop_data = ir_loop_start(proc, type->Array.count, t_i32);
+
+			data = ir_emit_conv(proc, data, pt);
+
+			irValue *ptr = ir_emit_array_ep(proc, data, loop_data.idx);
+			args[0] = ptr;
+			args[1] = ir_emit_load(proc, pres);
+			irValue *new_seed = ir_emit_call(proc, elem_hasher, args);
+			ir_emit_store(proc, pres, new_seed);
+
+			ir_loop_end(proc, loop_data);
+
+			irValue *res = ir_emit_load(proc, pres);
+			ir_emit(proc, ir_instr_return(proc, res));
+		}
+	} else if (type->kind == Type_EnumeratedArray) {
+		if (is_type_simple_compare(type)) {
+			i64 sz = type_size_of(type);
+			auto args = array_make<irValue *>(permanent_allocator(), 3);
+			args[0] = data;
+			args[1] = seed;
+			args[2] = ir_const_int(sz);
+			irValue *res = ir_emit_runtime_call(proc, "default_hasher_n", args);
+			ir_emit(proc, ir_instr_return(proc, res));
+		} else {
+			irValue *pres = ir_add_local_generated(proc, t_uintptr, false);
+			ir_emit_store(proc, pres, seed);
+
+			auto args = array_make<irValue *>(permanent_allocator(), 2);
+			irValue *elem_hasher = ir_get_hasher_proc_for_type(m, type->Array.elem);
+
+			auto loop_data = ir_loop_start(proc, type->Array.count, t_i32);
+
+			data = ir_emit_conv(proc, data, pt);
+
+			irValue *ptr = ir_emit_array_ep(proc, data, loop_data.idx);
+			args[0] = ptr;
+			args[1] = ir_emit_load(proc, pres);
+			irValue *new_seed = ir_emit_call(proc, elem_hasher, args);
+			ir_emit_store(proc, pres, new_seed);
+
+			ir_loop_end(proc, loop_data);
+
+			irValue *res = ir_emit_load(proc, pres);
+			ir_emit(proc, ir_instr_return(proc, res));
+		}
 	} else if (is_type_cstring(type)) {
 		auto args = array_make<irValue *>(permanent_allocator(), 2);
 		args[0] = data;

+ 89 - 9
src/llvm_backend.cpp

@@ -9251,7 +9251,7 @@ lbValue lb_get_equal_proc_for_type(lbModule *m, Type *type) {
 
 lbValue lb_get_hasher_proc_for_type(lbModule *m, Type *type) {
 	Type *original_type = type;
-	type = base_type(type);
+	type = core_type(type);
 	GB_ASSERT(is_type_valid_for_keys(type));
 
 	Type *pt = alloc_type_pointer(type);
@@ -9284,14 +9284,94 @@ lbValue lb_get_hasher_proc_for_type(lbModule *m, Type *type) {
 
 	if (type->kind == Type_Struct)  {
 		type_set_offsets(type);
-		GB_ASSERT(is_type_simple_compare(type));
-		i64 sz = type_size_of(type);
-		auto args = array_make<lbValue>(permanent_allocator(), 3);
-		args[0] = data;
-		args[1] = seed;
-		args[2] = lb_const_int(m, t_int, sz);
-		lbValue res = lb_emit_runtime_call(p, "default_hasher_n", args);
-		LLVMBuildRet(p->builder, res.value);
+		if (is_type_simple_compare(type)) {
+			i64 sz = type_size_of(type);
+			auto args = array_make<lbValue>(permanent_allocator(), 3);
+			args[0] = data;
+			args[1] = seed;
+			args[2] = lb_const_int(m, t_int, sz);
+			lbValue res = lb_emit_runtime_call(p, "default_hasher_n", args);
+			LLVMBuildRet(p->builder, res.value);
+		} else {
+			data = lb_emit_conv(p, data, t_u8_ptr);
+
+			auto args = array_make<lbValue>(permanent_allocator(), 2);
+			for_array(i, type->Struct.fields) {
+				i64 offset = type->Struct.offsets[i];
+				Entity *field = type->Struct.fields[i];
+				lbValue field_hasher = lb_get_hasher_proc_for_type(m, field->type);
+				lbValue ptr = lb_emit_ptr_offset(p, data, lb_const_int(m, t_uintptr, offset));
+
+				args[0] = ptr;
+				args[1] = seed;
+				seed = lb_emit_call(p, field_hasher, args);
+			}
+			LLVMBuildRet(p->builder, seed.value);
+		}
+	} else if (type->kind == Type_Array) {
+		if (is_type_simple_compare(type)) {
+			i64 sz = type_size_of(type);
+			auto args = array_make<lbValue>(permanent_allocator(), 3);
+			args[0] = data;
+			args[1] = seed;
+			args[2] = lb_const_int(m, t_int, sz);
+			lbValue res = lb_emit_runtime_call(p, "default_hasher_n", args);
+			LLVMBuildRet(p->builder, res.value);
+		} else {
+			lbAddr pres = lb_add_local_generated(p, t_uintptr, false);
+			lb_addr_store(p, pres, seed);
+
+			auto args = array_make<lbValue>(permanent_allocator(), 2);
+			lbValue elem_hasher = lb_get_hasher_proc_for_type(m, type->Array.elem);
+
+			auto loop_data = lb_loop_start(p, type->Array.count, t_i32);
+
+			data = lb_emit_conv(p, data, pt);
+
+			lbValue ptr = lb_emit_array_ep(p, data, loop_data.idx);
+			args[0] = ptr;
+			args[1] = lb_addr_load(p, pres);
+			lbValue new_seed = lb_emit_call(p, elem_hasher, args);
+			lb_addr_store(p, pres, new_seed);
+
+			lb_loop_end(p, loop_data);
+
+			lbValue res = lb_addr_load(p, pres);
+			LLVMBuildRet(p->builder, res.value);
+		}
+	} else if (type->kind == Type_EnumeratedArray) {
+		if (is_type_simple_compare(type)) {
+			i64 sz = type_size_of(type);
+			auto args = array_make<lbValue>(permanent_allocator(), 3);
+			args[0] = data;
+			args[1] = seed;
+			args[2] = lb_const_int(m, t_int, sz);
+			lbValue res = lb_emit_runtime_call(p, "default_hasher_n", args);
+			LLVMBuildRet(p->builder, res.value);
+		} else {
+			lbAddr res = lb_add_local_generated(p, t_uintptr, false);
+			lb_addr_store(p, res, seed);
+
+			auto args = array_make<lbValue>(permanent_allocator(), 2);
+			lbValue elem_hasher = lb_get_hasher_proc_for_type(m, type->EnumeratedArray.elem);
+
+			auto loop_data = lb_loop_start(p, type->EnumeratedArray.count, t_i32);
+
+			data = lb_emit_conv(p, data, pt);
+
+			lbValue ptr = lb_emit_array_ep(p, data, loop_data.idx);
+			args[0] = ptr;
+			args[1] = lb_addr_load(p, res);
+			lbValue new_seed = lb_emit_call(p, elem_hasher, args);
+			lb_addr_store(p, res, new_seed);
+
+			lb_loop_end(p, loop_data);
+
+			lbValue vres = lb_addr_load(p, res);
+			LLVMBuildRet(p->builder, vres.value);
+		}
+
+
 	} else if (is_type_cstring(type)) {
 		auto args = array_make<lbValue>(permanent_allocator(), 2);
 		args[0] = data;

+ 6 - 0
src/types.cpp

@@ -1542,6 +1542,8 @@ bool is_type_valid_for_keys(Type *t) {
 	if (is_type_untyped(t)) {
 		return false;
 	}
+	return is_type_comparable(t);
+#if 0
 	if (is_type_integer(t)) {
 		return true;
 	}
@@ -1560,8 +1562,12 @@ bool is_type_valid_for_keys(Type *t) {
 	if (is_type_simple_compare(t)) {
 		return true;
 	}
+	if (is_type_comparable(t)) {
+		return true;
+	}
 
 	return false;
+#endif
 }
 
 bool is_type_valid_bit_set_elem(Type *t) {