Browse Source

Allow 128 bit map keys

Ginger Bill 8 years ago
parent
commit
eba2c74bff
8 changed files with 108 additions and 84 deletions
  1. 9 9
      core/_preload.odin
  2. 60 54
      core/fmt.odin
  3. 18 5
      src/check_expr.c
  4. 2 1
      src/checker.c
  5. 1 0
      src/common.c
  6. 8 8
      src/ir.c
  7. 3 0
      src/map.c
  8. 7 7
      src/types.c

+ 9 - 9
core/_preload.odin

@@ -26,7 +26,7 @@
 // The compiler relies upon this _exact_ order
 TypeInfoEnumValue :: raw_union {
 	f: f64,
-	i: i64,
+	i: i128,
 }
 // NOTE(bill): This must match the compiler's
 CallingConvention :: enum {
@@ -537,24 +537,24 @@ __slice_append :: proc(slice_: rawptr, elem_size, elem_align: int,
 
 // Map stuff
 
-__default_hash :: proc(data: []byte) -> u64 {
-	fnv64a :: proc(data: []byte) -> u64 {
-		h: u64 = 0xcbf29ce484222325;
+__default_hash :: proc(data: []byte) -> u128 {
+	fnv128a :: proc(data: []byte) -> u128 {
+		h: u128 = 0x6c62272e07bb014262b821756295c58d;
 		for b in data {
-			h = (h ~ u64(b)) * 0x100000001b3;
+			h = (h ~ u128(b)) * 0x1000000000000000000013b;
 		}
 		return h;
 	}
-	return fnv64a(data);
+	return fnv128a(data);
 }
-__default_hash_string :: proc(s: string) -> u64 {
+__default_hash_string :: proc(s: string) -> u128 {
 	return __default_hash([]byte(s));
 }
 
 __INITIAL_MAP_CAP :: 16;
 
 __MapKey :: struct #ordered {
-	hash: u64,
+	hash: u128,
 	str:  string,
 }
 
@@ -699,7 +699,7 @@ __dynamic_map_hash_equal :: proc(h: __MapHeader, a, b: __MapKey) -> bool {
 __dynamic_map_find :: proc(using h: __MapHeader, key: __MapKey) -> __MapFindResult {
 	fr := __MapFindResult{-1, -1, -1};
 	if len(m.hashes) > 0 {
-		fr.hash_index = int(key.hash % u64(len(m.hashes)));
+		fr.hash_index = int(key.hash % u128(len(m.hashes)));
 		fr.entry_index = m.hashes[fr.hash_index];
 		for fr.entry_index >= 0 {
 			entry := __dynamic_map_get_entry(h, fr.entry_index);

+ 60 - 54
core/fmt.odin

@@ -13,6 +13,26 @@ StringBuffer :: union {
 	Dynamic{buf: [dynamic]byte},
 }
 
+FmtInfo :: struct {
+	minus:     bool,
+	plus:      bool,
+	space:     bool,
+	zero:      bool,
+	hash:      bool,
+	width_set: bool,
+	prec_set:  bool,
+
+	width:     int,
+	prec:      int,
+
+	reordered:      bool,
+	good_arg_index: bool,
+
+	buf: ^StringBuffer,
+	arg: any, // Temporary
+}
+
+
 make_string_buffer_from_slice :: proc(b: []byte) -> StringBuffer {
 	return StringBuffer.Static{b};
 }
@@ -21,7 +41,13 @@ make_string_dynamic_buffer :: proc() -> StringBuffer {
 	return StringBuffer.Dynamic{make([dynamic]byte)};
 }
 string_buffer_data :: proc(buf: ^StringBuffer) -> []byte {
-	return string_buffer_data(buf^);
+	match b in buf {
+	case StringBuffer.Static:
+		return b.buf[..];
+	case StringBuffer.Dynamic:
+		return b.buf[..];
+	}
+	return nil;
 }
 string_buffer_data :: proc(buf: StringBuffer) -> []byte {
 	match b in buf {
@@ -66,23 +92,15 @@ write_rune :: proc(buf: ^StringBuffer, r: rune) {
 	write_bytes(buf, b[0..<n]);
 }
 
-FmtInfo :: struct {
-	minus:     bool,
-	plus:      bool,
-	space:     bool,
-	zero:      bool,
-	hash:      bool,
-	width_set: bool,
-	prec_set:  bool,
-
-	width:     int,
-	prec:      int,
-
-	reordered:      bool,
-	good_arg_index: bool,
-
-	buf: ^StringBuffer,
-	arg: any, // Temporary
+write_int :: proc(buf: ^StringBuffer, i: i128, base: int) {
+	b: [129]byte;
+	s := strconv.append_bits(b[0..<0], u128(i), base, true, 128, strconv.digits, 0);
+	write_string(buf, s);
+}
+write_int :: proc(buf: ^StringBuffer, i: i64, base: int) {
+	b: [129]byte;
+	s := strconv.append_bits(b[0..<0], u128(i), base, true, 64, strconv.digits, 0);
+	write_string(buf, s);
 }
 
 
@@ -114,15 +132,13 @@ fprintf :: proc(fd: os.Handle, fmt: string, args: ..any) -> int {
 }
 
 
-print :: proc(args: ..any) -> int {
-	return fprint(os.stdout, ..args);
-}
-println :: proc(args: ..any) -> int {
-	return fprintln(os.stdout, ..args);
-}
-printf :: proc(fmt: string, args: ..any) -> int {
-	return fprintf(os.stdout, fmt, ..args);
-}
+// print* procedures return the number of bytes written
+print       :: proc(args: ..any)              -> int { return fprint(os.stdout, ..args); }
+print_err   :: proc(args: ..any)              -> int { return fprint(os.stderr, ..args); }
+println     :: proc(args: ..any)              -> int { return fprintln(os.stdout, ..args); }
+println_err :: proc(args: ..any)              -> int { return fprintln(os.stderr, ..args); }
+printf      :: proc(fmt: string, args: ..any) -> int { return fprintf(os.stdout, fmt, ..args); }
+printf_err  :: proc(fmt: string, args: ..any) -> int { return fprintf(os.stderr, fmt, ..args); }
 
 
 // aprint* procedures return a string that was allocated with the current context
@@ -144,10 +160,7 @@ aprintf :: proc(fmt: string, args: ..any) -> string {
 }
 
 
-// bprint* procedures
-
-
-// aprint* procedure return a string that was allocated with the current context
+// bprint* procedures return a string that was allocated with the current context
 // They must be freed accordingly
 bprint :: proc(buf: []byte, args: ..any) -> string {
 	sb := make_string_buffer_from_slice(buf[0..<0..<len(buf)]);
@@ -376,16 +389,6 @@ write_type :: proc(buf: ^StringBuffer, ti: ^TypeInfo) {
 	}
 }
 
-write_int :: proc(buf: ^StringBuffer, i: i128, base: int) {
-	b: [129]byte;
-	s := strconv.append_bits(b[0..<0], u128(i), base, true, 128, strconv.digits, 0);
-	write_string(buf, s);
-}
-write_int :: proc(buf: ^StringBuffer, i: i64, base: int) {
-	b: [129]byte;
-	s := strconv.append_bits(b[0..<0], u128(i), base, true, 64, strconv.digits, 0);
-	write_string(buf, s);
-}
 
 _parse_int :: proc(s: string, offset: int) -> (result: int, offset: int, ok: bool) {
 	is_digit :: proc(r: rune) -> bool #inline {
@@ -703,23 +706,26 @@ fmt_enum :: proc(fi: ^FmtInfo, v: any, verb: rune) {
 		case 'd', 'f':
 			fmt_arg(fi, any{v.data, type_info_base(e.base)}, verb);
 		case 's', 'v':
-			i: i64;
+			i: i128;
 			f: f64;
 			ok := false;
 			a := any{v.data, type_info_base(e.base)};
 			match v in a {
-			case i8:   i = i64(v);
-			case i16:  i = i64(v);
-			case i32:  i = i64(v);
-			case i64:  i = i64(v);
-			case int:  i = i64(v);
-			case u8:   i = i64(v);
-			case u16:  i = i64(v);
-			case u32:  i = i64(v);
-			case u64:  i = i64(v);
-			case uint: i = i64(v);
-			case f32:  f = f64(v); i = transmute(i64, f);
-			case f64:  f = f64(v); i = transmute(i64, f);
+			case i8:   i = i128(v);
+			case i16:  i = i128(v);
+			case i32:  i = i128(v);
+			case i64:  i = i128(v);
+			case i128: i = i128(v);
+			case int:  i = i128(v);
+			case u8:   i = i128(v);
+			case u16:  i = i128(v);
+			case u32:  i = i128(v);
+			case u64:  i = i128(v);
+			case u128: i = i128(v);
+			case uint: i = i128(v);
+
+			case f32:  f = f64(v); i = i128(transmute(i64, f));
+			case f64:  f = f64(v); i = i128(transmute(i64, f));
 			}
 
 			if types.is_string(e.base) {

+ 18 - 5
src/check_expr.c

@@ -2250,6 +2250,23 @@ bool check_is_vector_elem(Checker *c, AstNode *expr) {
 	return false;
 }
 
+bool check_is_not_addressable(Checker *c, Operand *o) {
+	if (o->mode != Addressing_Variable) {
+		return true;
+	}
+	if (is_type_bit_field_value(o->type)) {
+		return true;
+	}
+	if (check_is_expr_vector_index(c, o->expr)) {
+		return true;
+	}
+	if (check_is_vector_elem(c, o->expr)) {
+		return true;
+	}
+
+	return false;
+}
+
 void check_unary_expr(Checker *c, Operand *o, Token op, AstNode *node) {
 	switch (op.kind) {
 	case Token_And: { // Pointer address
@@ -2257,11 +2274,7 @@ void check_unary_expr(Checker *c, Operand *o, Token op, AstNode *node) {
 			o->type = make_type_pointer(c->allocator, o->type);
 			return;
 		}
-
-		if (o->mode != Addressing_Variable ||
-		    check_is_expr_vector_index(c, o->expr) ||
-		    check_is_vector_elem(c, o->expr) ||
-		    is_type_bit_field_value(o->type)) {
+		if (check_is_not_addressable(c, o)) {
 			if (ast_node_expect(node, AstNode_UnaryExpr)) {
 				ast_node(ue, UnaryExpr, node);
 				gbString str = expr_to_string(ue->expr);

+ 2 - 1
src/checker.c

@@ -310,8 +310,8 @@ typedef struct CheckerInfo {
 	MapEntity            uses;            // Key: AstNode * | Identifier -> Entity
 	MapScope             scopes;          // Key: AstNode * | Node       -> Scope
 	MapExprInfo          untyped;         // Key: AstNode * | Expression -> ExprInfo
-	MapDeclInfo          entities;        // Key: Entity *
 	MapEntity            implicits;       // Key: AstNode *
+	MapDeclInfo          entities;        // Key: Entity *
 	MapEntity            foreigns;        // Key: String
 	MapAstFile           files;           // Key: String (full path)
 	MapIsize             type_info_map;   // Key: Type *
@@ -698,6 +698,7 @@ void init_universal_scope(void) {
 	t_u8_ptr       = make_type_pointer(a, t_u8);
 	t_int_ptr      = make_type_pointer(a, t_int);
 	t_i64_ptr      = make_type_pointer(a, t_i64);
+	t_i128_ptr     = make_type_pointer(a, t_i128);
 	t_f64_ptr      = make_type_pointer(a, t_f64);
 	t_byte_slice   = make_type_slice(a, t_byte);
 	t_string_slice = make_type_slice(a, t_string);

+ 1 - 0
src/common.c

@@ -17,6 +17,7 @@ gbAllocator heap_allocator(void) {
 #include "string.c"
 #include "array.c"
 #include "integer128.c"
+#include "murmurhash3.c"
 
 gb_global String global_module_path = {0};
 gb_global bool global_module_path_set = false;

+ 8 - 8
src/ir.c

@@ -1656,24 +1656,25 @@ irValue *ir_gen_map_header(irProcedure *proc, irValue *map_val, Type *map_type)
 }
 
 irValue *ir_gen_map_key(irProcedure *proc, irValue *key, Type *key_type) {
+	Type *hash_type = t_u128;
 	irValue *v = ir_add_local_generated(proc, t_map_key);
 	Type *t = base_type(ir_type(key));
 	key = ir_emit_conv(proc, key, key_type);
 	if (is_type_integer(t)) {
-		ir_emit_store(proc, ir_emit_struct_ep(proc, v, 0), ir_emit_conv(proc, key, t_u64));
+		ir_emit_store(proc, ir_emit_struct_ep(proc, v, 0), ir_emit_conv(proc, key, hash_type));
 	} else if (is_type_pointer(t)) {
 		irValue *p = ir_emit_conv(proc, key, t_uint);
-		ir_emit_store(proc, ir_emit_struct_ep(proc, v, 0), ir_emit_conv(proc, p, t_u64));
+		ir_emit_store(proc, ir_emit_struct_ep(proc, v, 0), ir_emit_conv(proc, p, hash_type));
 	} else if (is_type_float(t)) {
 		irValue *bits = NULL;
 		i64 size = type_size_of(proc->module->allocator, t);
 		switch (8*size) {
-		case 32: bits = ir_emit_transmute(proc, key, t_u32); break;
-		case 64: bits = ir_emit_transmute(proc, key, t_u64); break;
+		case 32:  bits = ir_emit_transmute(proc, key, t_u32); break;
+		case 64:  bits = ir_emit_transmute(proc, key, t_u64);  break;
 		default: GB_PANIC("Unhandled float size: %lld bits", size); break;
 		}
 
-		ir_emit_store(proc, ir_emit_struct_ep(proc, v, 0), ir_emit_conv(proc, bits, t_u64));
+		ir_emit_store(proc, ir_emit_struct_ep(proc, v, 0), ir_emit_conv(proc, bits, hash_type));
 	} else if (is_type_string(t)) {
 		irValue *str = ir_emit_conv(proc, key, t_string);
 		irValue *hashed_str = NULL;
@@ -7823,9 +7824,8 @@ void ir_gen_tree(irGen *s) {
 									ExactValue value = fields[i]->Constant.value;
 
 									if (is_value_int) {
-										i64 i = i128_to_i64(value.value_integer);
-										value_ep = ir_emit_conv(proc, value_ep, t_i64_ptr);
-										ir_emit_store(proc, value_ep, ir_const_i64(a, i));
+										value_ep = ir_emit_conv(proc, value_ep, t_i128_ptr);
+										ir_emit_store(proc, value_ep, ir_value_constant(a, t_i128, value));
 									} else {
 										GB_ASSERT(is_type_float(t->Record.enum_base_type));
 										f64 f = value.value_float;

+ 3 - 0
src/map.c

@@ -39,6 +39,8 @@ gb_inline HashKey hashing_proc(void const *data, isize len) {
 	h.kind = HashKey_Default;
 	// h.key = gb_murmur64(data, len);
 	h.key = gb_fnv64a(data, len);
+	// h.key = MurmurHash3_128(data, len, 0x3803cb8e);
+
 	return h;
 }
 
@@ -51,6 +53,7 @@ gb_inline HashKey hash_string(String s) {
 
 gb_inline HashKey hash_pointer(void *ptr) {
 	HashKey h = {HashKey_Default};
+	// h.key = u128_from_u64(cast(u64)cast(uintptr)ptr);
 	h.key = cast(u64)cast(uintptr)ptr;
 	h.ptr = ptr;
 	h.kind = HashKey_Default;

+ 7 - 7
src/types.c

@@ -304,11 +304,12 @@ gb_global Type *t_untyped_nil        = &basic_types[Basic_UntypedNil];
 gb_global Type *t_byte               = &basic_type_aliases[0];
 gb_global Type *t_rune               = &basic_type_aliases[1];
 
-gb_global Type *t_u8_ptr  = NULL;
-gb_global Type *t_int_ptr = NULL;
-gb_global Type *t_i64_ptr = NULL;
-gb_global Type *t_f64_ptr = NULL;
-gb_global Type *t_byte_slice = NULL;
+gb_global Type *t_u8_ptr       = NULL;
+gb_global Type *t_int_ptr      = NULL;
+gb_global Type *t_i64_ptr      = NULL;
+gb_global Type *t_i128_ptr     = NULL;
+gb_global Type *t_f64_ptr      = NULL;
+gb_global Type *t_byte_slice   = NULL;
 gb_global Type *t_string_slice = NULL;
 
 
@@ -874,8 +875,7 @@ bool is_type_valid_for_keys(Type *t) {
 		return false;
 	}
 	if (is_type_integer(t)) {
-		// NOTE(bill): Not (u|i)128
-		return t->Basic.size <= 8;
+		return true;
 	}
 	if (is_type_float(t)) {
 		return true;