Browse Source

Update Standard Library; Fix Type_Info for integers

Ginger Bill 9 years ago
parent
commit
5f6b0942f4
12 changed files with 175 additions and 158 deletions
  1. 6 1
      code/demo.odin
  2. 2 1
      code/game.odin
  3. 39 64
      core/fmt.odin
  4. 62 2
      core/mem.odin
  5. 13 0
      core/os.odin
  6. 16 76
      core/runtime.odin
  7. 2 1
      src/checker/expr.cpp
  8. 7 3
      src/checker/stmt.cpp
  9. 25 6
      src/codegen/codegen.cpp
  10. 2 2
      src/codegen/ssa.cpp
  11. 0 1
      src/main.cpp
  12. 1 1
      src/tokenizer.cpp

+ 6 - 1
code/demo.odin

@@ -1,5 +1,10 @@
 #import "fmt.odin"
+#import "utf8.odin"
+#import "hash.odin"
 
 main :: proc() {
-	fmt.println("Hello")
+	s := "Hello"
+	fmt.println(s,
+	            utf8.valid_string(s),
+	            hash.murmur64(s.data, s.count))
 }

+ 2 - 1
code/game.odin

@@ -1,6 +1,7 @@
 #import "win32.odin"
 #import "fmt.odin"
 #import "math.odin"
+#import "os.odin"
 #import "opengl.odin" as gl
 
 TWO_HEARTS :: #rune "💕"
@@ -128,7 +129,7 @@ run :: proc() {
 
 	win32_proc :: proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT #no_inline {
 		if msg == WM_DESTROY || msg == WM_CLOSE || msg == WM_QUIT {
-			ExitProcess(0)
+			os.exit(0)
 			return 0
 		}
 		return DefWindowProcA(hwnd, msg, wparam, lparam)

+ 39 - 64
core/fmt.odin

@@ -1,4 +1,6 @@
 #import "os.odin"
+#import "mem.odin"
+#import "utf8.odin"
 
 PRINT_BUF_SIZE :: 1<<12
 
@@ -49,7 +51,7 @@ print_byte_buffer :: proc(buf: ^[]byte, b: []byte) {
 		n := min(buf.capacity-buf.count, b.count)
 		if n > 0 {
 			offset := ptr_offset(buf.data, buf.count)
-			memory_copy(offset, ^b[0], n)
+			mem.copy(offset, ^b[0], n)
 			buf.count += n
 		}
 	}
@@ -67,42 +69,8 @@ byte_reverse :: proc(b: []byte) {
 	}
 }
 
-encode_rune :: proc(r: rune) -> ([4]byte, int) {
-	buf: [4]byte
-	i := r as u32
-	mask: byte : 0x3f
-	if i <= 1<<7-1 {
-		buf[0] = r as byte
-		return buf, 1
-	}
-	if i <= 1<<11-1 {
-		buf[0] = 0xc0 | (r>>6) as byte
-		buf[1] = 0x80 | (r)    as byte & mask
-		return buf, 2
-	}
-
-	// Invalid or Surrogate range
-	if i > 0x0010ffff ||
-	   (i >= 0xd800 && i <= 0xdfff) {
-		r = 0xfffd
-	}
-
-	if i <= 1<<16-1 {
-		buf[0] = 0xe0 | (r>>12) as byte
-		buf[1] = 0x80 | (r>>6)  as byte & mask
-		buf[2] = 0x80 | (r)     as byte & mask
-		return buf, 3
-	}
-
-	buf[0] = 0xf0 | (r>>18) as byte
-	buf[1] = 0x80 | (r>>12) as byte & mask
-	buf[2] = 0x80 | (r>>6)  as byte & mask
-	buf[3] = 0x80 | (r)     as byte & mask
-	return buf, 4
-}
-
 print_rune_to_buffer :: proc(buf: ^[]byte, r: rune) {
-	b, n := encode_rune(r)
+	b, n := utf8.encode_rune(r)
 	print_string_to_buffer(buf, b[:n] as string)
 }
 
@@ -177,6 +145,29 @@ print_pointer_to_buffer :: proc(buffer: ^[]byte, p: rawptr) #inline {
 
 print_f32_to_buffer :: proc(buffer: ^[]byte, f: f32) #inline { print__f64(buffer, f as f64, 7) }
 print_f64_to_buffer :: proc(buffer: ^[]byte, f: f64) #inline { print__f64(buffer, f, 10) }
+print_u64_to_buffer :: proc(buffer: ^[]byte, i: u64) {
+	buf: [22]byte
+	len := 0
+	if i == 0 {
+		buf[len] = #rune "0"
+		len++
+	}
+	for i > 0 {
+		buf[len] = __NUM_TO_CHAR_TABLE[i % 10]
+		len++
+		i /= 10
+	}
+	byte_reverse(buf[:len])
+	print_string_to_buffer(buffer, buf[:len] as string)
+}
+print_i64_to_buffer :: proc(buffer: ^[]byte, i: i64) {
+	neg := i < 0
+	if neg {
+		i = -i
+	}
+	print_rune_to_buffer(buffer, #rune "-")
+	print_u64_to_buffer(buffer, i as u64)
+}
 
 print__f64 :: proc(buffer: ^[]byte, f: f64, decimal_places: int) {
 	if f == 0 {
@@ -188,22 +179,6 @@ print__f64 :: proc(buffer: ^[]byte, f: f64, decimal_places: int) {
 		f = -f
 	}
 
-	print_u64_to_buffer :: proc(buffer: ^[]byte, i: u64) {
-		buf: [22]byte
-		len := 0
-		if i == 0 {
-			buf[len] = #rune "0"
-			len++
-		}
-		for i > 0 {
-			buf[len] = __NUM_TO_CHAR_TABLE[i % 10]
-			len++
-			i /= 10
-		}
-		byte_reverse(buf[:len])
-		print_string_to_buffer(buffer, buf[:len] as string)
-	}
-
 	i := f as u64
 	print_u64_to_buffer(buffer, i)
 	f -= i as f64
@@ -374,27 +349,27 @@ print_any_to_buffer :: proc(buf: ^[]byte, arg: any)  {
 
 	case Integer:
 		if info.signed {
-			i: int = 0;
+			i: i64 = 0;
 			if arg.data != null {
 				match info.size {
-				case 1:  i = (arg.data as ^i8)^   as int
-				case 2:  i = (arg.data as ^i16)^  as int
-				case 4:  i = (arg.data as ^i32)^  as int
-				case 8:  i = (arg.data as ^i64)^  as int
+				case 1:  i = (arg.data as ^i8)^   as i64
+				case 2:  i = (arg.data as ^i16)^  as i64
+				case 4:  i = (arg.data as ^i32)^  as i64
+				case 8:  i = (arg.data as ^i64)^  as i64
 				}
 			}
-			print_int_to_buffer(buf, i)
+			print_i64_to_buffer(buf, i)
 		} else {
-			i: uint = 0;
+			i: u64 = 0;
 			if arg.data != null {
 				match info.size {
-				case 1:  i = (arg.data as ^u8)^   as uint
-				case 2:  i = (arg.data as ^u16)^  as uint
-				case 4:  i = (arg.data as ^u32)^  as uint
-				case 8:  i = (arg.data as ^u64)^  as uint
+				case 1:  i = (arg.data as ^u8)^   as u64
+				case 2:  i = (arg.data as ^u16)^  as u64
+				case 4:  i = (arg.data as ^u32)^  as u64
+				case 8:  i = (arg.data as ^u64)^  as u64
 				}
 			}
-			print_uint_to_buffer(buf, i)
+			print_u64_to_buffer(buf, i)
 		}
 
 	case Float:

+ 62 - 2
core/mem.odin

@@ -1,6 +1,67 @@
 #import "fmt.odin"
 #import "os.odin"
 
+set :: proc(data: rawptr, value: i32, len: int) -> rawptr #link_name "__mem_set" {
+	llvm_memset_64bit :: proc(dst: rawptr, val: byte, len: int, align: i32, is_volatile: bool) #foreign "llvm.memset.p0i8.i64"
+	llvm_memset_64bit(data, value as byte, len, 1, false)
+	return data
+}
+
+zero :: proc(data: rawptr, len: int) -> rawptr {
+	return set(data, 0, len)
+}
+
+copy :: proc(dst, src: rawptr, len: int) -> rawptr #link_name "__mem_copy" {
+	// NOTE(bill): This _must_ implemented like C's memmove
+	llvm_memmove_64bit :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #foreign "llvm.memmove.p0i8.p0i8.i64"
+	llvm_memmove_64bit(dst, src, len, 1, false)
+	return dst
+}
+
+copy_non_overlapping :: proc(dst, src: rawptr, len: int) -> rawptr #link_name "__mem_copy_non_overlapping" {
+	// NOTE(bill): This _must_ implemented like C's memcpy
+	llvm_memcpy_64bit :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #foreign "llvm.memcpy.p0i8.p0i8.i64"
+	llvm_memcpy_64bit(dst, src, len, 1, false)
+	return dst
+}
+
+
+compare :: proc(dst, src: rawptr, n: int) -> int #link_name "__mem_compare" {
+	// Translation of http://mgronhol.github.io/fast-strcmp/
+	a := slice_ptr(dst as ^byte, n)
+	b := slice_ptr(src as ^byte, n)
+
+	fast := n/size_of(int) + 1
+	offset := (fast-1)*size_of(int)
+	curr_block := 0
+	if n <= size_of(int) {
+		fast = 0
+	}
+
+	la := slice_ptr(^a[0] as ^int, fast)
+	lb := slice_ptr(^b[0] as ^int, fast)
+
+	for ; curr_block < fast; curr_block++ {
+		if (la[curr_block] ~ lb[curr_block]) != 0 {
+			for pos := curr_block*size_of(int); pos < n; pos++ {
+				if (a[pos] ~ b[pos]) != 0 {
+					return a[pos] as int - b[pos] as int
+				}
+			}
+		}
+
+	}
+
+	for ; offset < n; offset++ {
+		if (a[offset] ~ b[offset]) != 0 {
+			return a[offset] as int - b[offset] as int
+		}
+	}
+
+	return 0
+}
+
+
 
 kilobytes :: proc(x: int) -> int #inline { return          (x) * 1024 }
 megabytes :: proc(x: int) -> int #inline { return kilobytes(x) * 1024 }
@@ -116,8 +177,7 @@ arena_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator.Mode,
 
 		ptr := align_forward(end, alignment)
 		arena.memory.count += total_size
-		memory_zero(ptr, size)
-		return ptr
+		return zero(ptr, size)
 
 	case FREE:
 		// NOTE(bill): Free all at once

+ 13 - 0
core/os.odin

@@ -115,3 +115,16 @@ heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
 heap_free :: proc(ptr: rawptr) {
 	win32.HeapFree(win32.GetProcessHeap(), 0, ptr)
 }
+
+
+exit :: proc(code: int) {
+	win32.ExitProcess(code as u32)
+}
+
+
+
+current_thread_id :: proc() -> int {
+	GetCurrentThreadId :: proc() -> u32 #foreign #dll_import
+	return GetCurrentThreadId() as int
+}
+

+ 16 - 76
core/runtime.odin

@@ -16,11 +16,13 @@ Type_Info :: union {
 		fields:  []Member
 		packed:  bool
 		ordered: bool
+		size:    int
+		align:   int
 	}
 
 	Named: struct #ordered {
 		name: string
-		base: ^Type_Info
+		base: ^Type_Info // This will _not_ be a Type_Info.Named
 	}
 	Integer: struct #ordered {
 		size:   int // in bytes
@@ -68,15 +70,11 @@ type_info_base :: proc(info: ^Type_Info) -> ^Type_Info {
 	if info == null {
 		return null
 	}
-	for {
-		match type i : info {
-		case Type_Info.Named:
-			info = i.base
-			continue
-		}
-
-		return info
+	match type i : info {
+	case Type_Info.Named:
+		info = i.base
 	}
+	return info
 }
 
 
@@ -98,35 +96,6 @@ byte_swap64 :: proc(b: u64) -> u64 #foreign "llvm.bswap.i64"
 fmuladd32 :: proc(a, b, c: f32) -> f32 #foreign "llvm.fmuladd.f32"
 fmuladd64 :: proc(a, b, c: f64) -> f64 #foreign "llvm.fmuladd.f64"
 
-current_thread_id :: proc() -> int {
-	GetCurrentThreadId :: proc() -> u32 #foreign #dll_import
-	return GetCurrentThreadId() as int
-}
-
-memory_zero :: proc(data: rawptr, len: int) {
-	llvm_memset_64bit :: proc(dst: rawptr, val: byte, len: int, align: i32, is_volatile: bool) #foreign "llvm.memset.p0i8.i64"
-	llvm_memset_64bit(data, 0, len, 1, false)
-}
-
-memory_compare :: proc(dst, src: rawptr, len: int) -> int {
-	// TODO(bill): make a faster `memory_compare`
-	a := slice_ptr(dst as ^byte, len)
-	b := slice_ptr(src as ^byte, len)
-	for i := 0; i < len; i++ {
-		if a[i] != b[i] {
-			return (a[i] - b[i]) as int
-		}
-	}
-	return 0
-}
-
-memory_copy :: proc(dst, src: rawptr, len: int) #inline {
-	// NOTE(bill): This _must_ implemented like C's memmove
-	llvm_memmove_64bit :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #foreign "llvm.memmove.p0i8.p0i8.i64"
-	llvm_memmove_64bit(dst, src, len, 1, false)
-}
-
-
 
 
 
@@ -177,7 +146,7 @@ __check_context :: proc() {
 		c.allocator = __default_allocator()
 	}
 	if c.thread_id == 0 {
-		c.thread_id = current_thread_id()
+		c.thread_id = os.current_thread_id()
 	}
 }
 
@@ -230,7 +199,7 @@ default_resize_align :: proc(old_memory: rawptr, old_size, new_size, alignment:
 		return null
 	}
 
-	memory_copy(new_memory, old_memory, min(old_size, new_size));
+	mem.copy(new_memory, old_memory, min(old_size, new_size));
 	free(old_memory)
 	return new_memory
 }
@@ -247,21 +216,22 @@ __default_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator.Mode,
 		header := ptr as ^mem.AllocationHeader
 		ptr = mem.align_forward(ptr_offset(header, 1), alignment)
 		mem.allocation_header_fill(header, ptr, size)
-		memory_zero(ptr, size)
-		return ptr
+		return mem.zero(ptr, size)
+
 	case FREE:
 		os.heap_free(mem.allocation_header(old_memory))
 		return null
+
 	case FREE_ALL:
 		// NOTE(bill): Does nothing
+
 	case RESIZE:
 		total_size := size + alignment + size_of(mem.AllocationHeader)
 		ptr := os.heap_resize(mem.allocation_header(old_memory), total_size)
 		header := ptr as ^mem.AllocationHeader
 		ptr = mem.align_forward(ptr_offset(header, 1), alignment)
 		mem.allocation_header_fill(header, ptr, size)
-		memory_zero(ptr, size)
-		return ptr
+		return mem.zero(ptr, size)
 	}
 
 	return null
@@ -291,41 +261,11 @@ __string_eq :: proc(a, b: string) -> bool {
 	if ^a[0] == ^b[0] {
 		return true
 	}
-	return memory_compare(^a[0], ^b[0], a.count) == 0
+	return mem.compare(^a[0], ^b[0], a.count) == 0
 }
 
 __string_cmp :: proc(a, b : string) -> int {
-	// Translation of http://mgronhol.github.io/fast-strcmp/
-	n := min(a.count, b.count)
-
-	fast := n/size_of(int) + 1
-	offset := (fast-1)*size_of(int)
-	curr_block := 0
-	if n <= size_of(int) {
-		fast = 0
-	}
-
-	la := slice_ptr(^a[0] as ^int, fast)
-	lb := slice_ptr(^b[0] as ^int, fast)
-
-	for ; curr_block < fast; curr_block++ {
-		if (la[curr_block] ~ lb[curr_block]) != 0 {
-			for pos := curr_block*size_of(int); pos < n; pos++ {
-				if (a[pos] ~ b[pos]) != 0 {
-					return a[pos] as int - b[pos] as int
-				}
-			}
-		}
-
-	}
-
-	for ; offset < n; offset++ {
-		if (a[offset] ~ b[offset]) != 0 {
-			return a[offset] as int - b[offset] as int
-		}
-	}
-
-	return 0
+	return mem.compare(a.data, b.data, min(a.count, b.count))
 }
 
 __string_ne :: proc(a, b : string) -> bool #inline { return !__string_eq(a, b) }

+ 2 - 1
src/checker/expr.cpp

@@ -1200,6 +1200,7 @@ b32 check_value_is_expressible(Checker *c, ExactValue in_value, Type *type, Exac
 			return false;
 		if (out_value) *out_value = v;
 		i64 i = v.value_integer;
+		u64 u = *cast(u64 *)&i;
 		i64 s = 8*type_size_of(c->sizes, c->allocator, type);
 		u64 umax = ~0ull;
 		if (s < 64) {
@@ -1221,7 +1222,7 @@ b32 check_value_is_expressible(Checker *c, ExactValue in_value, Type *type, Exac
 		case Basic_u32:
 		case Basic_u64:
 		case Basic_uint:
-			return !(i < 0 || cast(u64)i > umax);
+			return !(u < 0 || u > umax);
 
 		case Basic_UntypedInteger:
 			return true;

+ 7 - 3
src/checker/stmt.cpp

@@ -1017,10 +1017,14 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
 				auto *tuple = &proc_type->Proc.results->Tuple;
 				variables = tuple->variables;
 			}
-			check_init_variables(c, variables, result_count,
-			                     rs->results, make_string("return statement"));
+			if (gb_array_count(rs->results) == 0) {
+				error(ast_node_token(node), "Expected %td return values, got 0", result_count);
+			} else {
+				check_init_variables(c, variables, result_count,
+				                     rs->results, make_string("return statement"));
+			}
 		} else if (gb_array_count(rs->results) > 0) {
-			error(ast_node_token(rs->results[0]), "No result values expected");
+			error(ast_node_token(rs->results[0]), "No return values expected");
 		}
 	case_end;
 

+ 25 - 6
src/codegen/codegen.cpp

@@ -352,17 +352,15 @@ void ssa_gen_tree(ssaGen *s) {
 					case Basic_i16:
 					case Basic_i32:
 					case Basic_i64:
-					// case Basic_i128:
 					case Basic_u8:
 					case Basic_u16:
 					case Basic_u32:
 					case Basic_u64:
-					// case Basic_u128:
 					case Basic_int:
 					case Basic_uint: {
 						tag = ssa_add_local_generated(proc, t_type_info_integer);
-						b32 is_unsigned = (basic_types[t->Basic.kind].flags & BasicFlag_Unsigned) != 0;
-						ssaValue *bits      = ssa_make_const_int(a, type_size_of(m->sizes, a, t));
+						b32 is_unsigned = (t->Basic.flags & BasicFlag_Unsigned) != 0;
+						ssaValue *bits = ssa_make_const_int(a, type_size_of(m->sizes, a, t));
 						ssaValue *is_signed = ssa_make_const_bool(a, !is_unsigned);
 						ssa_emit_store(proc, ssa_emit_struct_gep(proc, tag, v_zero32, t_int_ptr),  bits);
 						ssa_emit_store(proc, ssa_emit_struct_gep(proc, tag, v_one32,  t_bool_ptr), is_signed);
@@ -434,8 +432,12 @@ void ssa_gen_tree(ssaGen *s) {
 						{
 							ssaValue *packed  = ssa_make_const_bool(a, t->Record.struct_is_packed);
 							ssaValue *ordered = ssa_make_const_bool(a, t->Record.struct_is_ordered);
-							ssa_emit_store(proc, ssa_emit_struct_gep(proc, tag, v_one32, t_bool_ptr), packed);
-							ssa_emit_store(proc, ssa_emit_struct_gep(proc, tag, v_two32, t_bool_ptr), ordered);
+							ssaValue *size    = ssa_make_const_int(a, type_size_of(m->sizes, a, t));
+							ssaValue *align   = ssa_make_const_int(a, type_align_of(m->sizes, a, t));
+							ssa_emit_store(proc, ssa_emit_struct_gep(proc, tag, 1, t_bool_ptr), packed);
+							ssa_emit_store(proc, ssa_emit_struct_gep(proc, tag, 2, t_bool_ptr), ordered);
+							ssa_emit_store(proc, ssa_emit_struct_gep(proc, tag, 3, t_int_ptr),  size);
+							ssa_emit_store(proc, ssa_emit_struct_gep(proc, tag, 4, t_int_ptr),  align);
 						}
 
 						ssaValue *memory = type_info_member_offset(proc, type_info_member_data, t->Record.field_count, &type_info_member_index);
@@ -476,9 +478,21 @@ void ssa_gen_tree(ssaGen *s) {
 					} break;
 					case TypeRecord_Union:
 						tag = ssa_add_local_generated(proc, t_type_info_union);
+						{
+							ssaValue *size    = ssa_make_const_int(a, type_size_of(m->sizes, a, t));
+							ssaValue *align   = ssa_make_const_int(a, type_align_of(m->sizes, a, t));
+							ssa_emit_store(proc, ssa_emit_struct_gep(proc, tag, 3, t_int_ptr),  size);
+							ssa_emit_store(proc, ssa_emit_struct_gep(proc, tag, 4, t_int_ptr),  align);
+						}
 						break;
 					case TypeRecord_RawUnion: {
 						tag = ssa_add_local_generated(proc, t_type_info_raw_union);
+						{
+							ssaValue *size    = ssa_make_const_int(a, type_size_of(m->sizes, a, t));
+							ssaValue *align   = ssa_make_const_int(a, type_align_of(m->sizes, a, t));
+							ssa_emit_store(proc, ssa_emit_struct_gep(proc, tag, 3, t_int_ptr),  size);
+							ssa_emit_store(proc, ssa_emit_struct_gep(proc, tag, 4, t_int_ptr),  align);
+						}
 
 						ssaValue *memory = type_info_member_offset(proc, type_info_member_data, t->Record.field_count, &type_info_member_index);
 
@@ -590,6 +604,11 @@ void ssa_gen_tree(ssaGen *s) {
 				case Type_Tuple: {
 					tag = ssa_add_local_generated(proc, t_type_info_tuple);
 
+					{
+						ssaValue *align   = ssa_make_const_int(a, type_align_of(m->sizes, a, t));
+						ssa_emit_store(proc, ssa_emit_struct_gep(proc, tag, 4, t_int_ptr),  align);
+					}
+
 					ssaValue *memory = type_info_member_offset(proc, type_info_member_data, t->Tuple.variable_count, &type_info_member_index);
 
 					for (isize i = 0; i < t->Tuple.variable_count; i++) {

+ 2 - 2
src/codegen/ssa.cpp

@@ -2369,7 +2369,7 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
 					args[1] = src;
 					args[2] = byte_count;
 
-					ssa_emit_global_call(proc, "memory_copy", args, 3);
+					ssa_emit_global_call(proc, "__mem_copy", args, 3);
 
 					return len;
 				} break;
@@ -2418,7 +2418,7 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
 					args[1] = item;
 					args[2] = byte_count;
 
-					ssa_emit_global_call(proc, "memory_copy", args, 3);
+					ssa_emit_global_call(proc, "__mem_copy", args, 3);
 
 					// Increment slice length
 					Token add = {Token_Add};

+ 0 - 1
src/main.cpp

@@ -106,7 +106,6 @@ ArchData make_arch_data(ArchKind kind) {
 	return data;
 }
 
-
 int main(int argc, char **argv) {
 	if (argc < 2) {
 		gb_printf_err("using: %s [run] <filename> \n", argv[0]);

+ 1 - 1
src/tokenizer.cpp

@@ -770,7 +770,7 @@ Token tokenizer_get_token(Tokenizer *t) {
 				isize comment_scope = 1;
 				advance_to_next_rune(t);
 				while (comment_scope > 0) {
-					if (curr_rune == '/') {
+					if (t->curr_rune == '/') {
 						advance_to_next_rune(t);
 						if (t->curr_rune == '*') {
 							advance_to_next_rune(t);