From 9561dc33cef4c5881034d429524a0498331a740e Mon Sep 17 00:00:00 2001 From: Ginger Bill Date: Mon, 19 Sep 2016 21:33:52 +0100 Subject: [PATCH] enum_to_string --- build.bat | 5 +- code/demo.odin | 201 ++++++++++++++++++++++++++++++++++--- code/punity.odin | 12 +-- code/test.odin | 2 +- core/fmt.odin | 98 +++++++++++------- core/os.odin | 9 +- core/runtime.odin | 37 +++++-- src/checker/checker.cpp | 32 ++++-- src/checker/expr.cpp | 74 ++++++++++++-- src/checker/stmt.cpp | 44 +++++--- src/checker/type.cpp | 18 ++-- src/codegen/codegen.cpp | 137 +++++++++++++++++++++---- src/codegen/print_llvm.cpp | 46 ++++----- src/codegen/ssa.cpp | 75 +++++++++----- src/exact_value.cpp | 6 +- src/main.cpp | 9 +- src/parser.cpp | 69 +++++++++---- 17 files changed, 660 insertions(+), 214 deletions(-) diff --git a/build.bat b/build.bat index 2e3e58471..9aa3715a6 100644 --- a/build.bat +++ b/build.bat @@ -6,7 +6,7 @@ set exe_name=odin.exe :: Debug = 0, Release = 1 set release_mode=0 -set compiler_flags= -nologo -Oi -TP -W4 -fp:fast -fp:except- -Gm- -MP -FC -Z7 -GS- -EHsc- -GR- +set compiler_flags= -nologo -Oi -TP -W4 -fp:fast -fp:except- -Gm- -MP -FC -GS- -EHsc- -GR- if %release_mode% EQU 0 ( rem Debug set compiler_flags=%compiler_flags% -Od -MDd -Z7 @@ -28,12 +28,11 @@ set libs= kernel32.lib user32.lib gdi32.lib opengl32.lib set linker_flags= -incremental:no -opt:ref -subsystem:console - if %release_mode% EQU 0 ( rem Debug set linker_flags=%linker_flags% -debug set libs=%libs% src\utf8proc\utf8proc_debug.lib ) else ( rem Release - set linker_flags=%linker_flags% + set linker_flags=%linker_flags% -debug set libs=%libs% src\utf8proc\utf8proc.lib ) diff --git a/code/demo.odin b/code/demo.odin index 5da0ee6bb..3eb810e82 100644 --- a/code/demo.odin +++ b/code/demo.odin @@ -1,19 +1,192 @@ -#import "punity.odin" as pn -#import "test.odin" as t1 -#import "sub/test.odin" as t2 +#import "fmt.odin" as fmt + +// #foreign_system_library "Ws2_32" + +// WSADESCRIPTION_LEN :: 256 +// WSASYS_STATUS_LEN :: 128 +// WSADATA :: struct #ordered { +// version: i16 +// high_version: i16 + + +// max_sockets: u16 +// max_udp_dg: u16 +// vendor_info: ^byte +// description: [WSADESCRIPTION_LEN+1]byte +// system_status: [WSASYS_STATUS_LEN+1]byte +// } + +// addrinfo :: struct #ordered { +// flags: i32 +// family: i32 +// socktype: i32 +// protocol: i32 +// addrlen: uint +// canonname: ^u8 +// addr: ^sockaddr +// next: ^addrinfo +// } + +// sockaddr :: struct #ordered { +// family: u16 +// data: [14]byte +// } + + +// SOCKET :: type uint +// INVALID_SOCKET :: ~(0 as SOCKET) + +// AF_UNSPEC :: 0 // unspecified +// AF_UNIX :: 1 // local to host (pipes, portals) +// AF_INET :: 2 // internetwork: UDP, TCP, etc. +// AF_IMPLINK :: 3 // arpanet imp addresses +// AF_PUP :: 4 // pup protocols: e.g. BSP +// AF_CHAOS :: 5 // mit CHAOS protocols +// AF_NS :: 6 // XEROX NS protocols +// AF_ISO :: 7 // ISO protocols +// AF_OSI :: AF_ISO // OSI is ISO +// AF_ECMA :: 8 // european computer manufacturers +// AF_DATAKIT :: 9 // datakit protocols +// AF_CCITT :: 10 // CCITT protocols, X.25 etc +// AF_SNA :: 11 // IBM SNA +// AF_DECnet :: 12 // DECnet +// AF_DLI :: 13 // Direct data link interface +// AF_LAT :: 14 // LAT +// AF_HYLINK :: 15 // NSC Hyperchannel +// AF_APPLETALK :: 16 // AppleTalk +// AF_ROUTE :: 17 // Internal Routing Protocol +// AF_LINK :: 18 // Link layer interface +// pseudo_AF_XTP :: 19 // eXpress Transfer Protocol (no AF) +// AF_COIP :: 20 // connection-oriented IP, aka ST II +// AF_CNT :: 21 // Computer Network Technology +// pseudo_AF_RTIP :: 22 // Help Identify RTIP packets +// AF_IPX :: 23 // Novell Internet Protocol +// AF_SIP :: 24 // Simple Internet Protocol +// pseudo_AF_PIP :: 25 // Help Identify PIP packets +// AF_MAX :: 26 + +// SOCK_STREAM :: 1 +// SOCKET_ERROR :: -1 +// IPPROTO_TCP :: 6 +// AI_PASSIVE :: 0x0020 +// SOMAXCONN :: 128 + +// SD_RECEIVE :: 0 +// SD_SEND :: 1 +// SD_BOTH :: 2 + +// WSAStartup :: proc(version_requested: i16, data: ^WSADATA) -> i32 #foreign #dll_import +// WSACleanup :: proc() -> i32 #foreign #dll_import +// getaddrinfo :: proc(node_name, service_name: ^u8, hints: ^addrinfo, result: ^^addrinfo) -> i32 #foreign #dll_import +// freeaddrinfo :: proc(ai: ^addrinfo) #foreign #dll_import +// socket :: proc(af, type_, protocol: i32) -> SOCKET #foreign #dll_import +// closesocket :: proc(s: SOCKET) -> i32 #foreign #dll_import +// bind :: proc(s: SOCKET, name: ^sockaddr, name_len: i32) -> i32 #foreign #dll_import +// listen :: proc(s: SOCKET, back_log: i32) -> i32 #foreign #dll_import +// accept :: proc(s: SOCKET, addr: ^sockaddr, addr_len: i32) -> SOCKET #foreign #dll_import +// recv :: proc(s: SOCKET, buf: ^byte, len: i32, flags: i32) -> i32 #foreign #dll_import +// send :: proc(s: SOCKET, buf: ^byte, len: i32, flags: i32) -> i32 #foreign #dll_import +// shutdown :: proc(s: SOCKET, how: i32) -> i32 #foreign #dll_import +// WSAGetLastError :: proc() -> i32 #foreign #dll_import + +// to_c_string :: proc(s: string) -> ^byte { +// c_str := new_slice(byte, s.count+1) +// assert(c_str.data != null) +// copy(c_str, s as []byte) +// c_str[s.count] = 0 +// return c_str.data +// } + +// main :: proc() { +// wsa: WSADATA +// res: ^addrinfo = null +// hints: addrinfo +// s, client: SOCKET + +// if WSAStartup(2 | (2 << 8), ^wsa) != 0 { +// fmt.println("WSAStartup failed: ", WSAGetLastError()) +// return +// } +// defer WSACleanup() + +// hints.family = AF_INET +// hints.socktype = SOCK_STREAM +// hints.protocol = IPPROTO_TCP +// hints.flags = AI_PASSIVE + +// if getaddrinfo(null, to_c_string("8080"), ^hints, ^res) != 0 { +// fmt.println("getaddrinfo failed: ", WSAGetLastError()) +// return +// } +// defer freeaddrinfo(res) + +// s = socket(res.family, res.socktype, res.protocol) +// if s == INVALID_SOCKET { +// fmt.println("socket failed: ", WSAGetLastError()) +// return +// } +// defer closesocket(s) + +// bind(s, res.addr, res.addrlen as i32) +// listen(s, SOMAXCONN) + +// client = accept(s, null, null) +// if client == INVALID_SOCKET { +// fmt.println("socket failed: ", WSAGetLastError()) +// return +// } +// defer closesocket(client) + +// html := +// `HTTP/1.1 200 OK +// Connection: close +// Content-type: text/html + +// +// +// Demo Title +// +// +//

Odin Server Demo

+// +// +// ` + +// buf: [1024]byte +// for { +// bytes := recv(client, ^buf[0], buf.count as i32, 0) +// if bytes > 0 { +// // fmt.println(buf[:bytes] as string) +// bytes_sent := send(client, html.data, (html.count-1) as i32, 0) +// if bytes_sent == SOCKET_ERROR { +// fmt.println("send failed: ", WSAGetLastError()) +// return +// } +// break +// } else if bytes == 0 { +// fmt.println("Connection closing...") +// break +// } else { +// fmt.println("recv failed: ", WSAGetLastError()) +// return +// } +// } + +// shutdown(client, SD_SEND) +// } main :: proc() { - t1.thing() - t2.thing() + Fruit :: enum { + APPLE, + BANANA, + GRAPE, + MELON, + } - // init :: proc(c: ^pn.Core) { - // } + s1 := enum_to_string(Fruit.APPLE) + e := Fruit.APPLE + s2 := enum_to_string(e) - // step :: proc(c: ^pn.Core) { - // if pn.key_down(pn.Key.ESCAPE) { - // c.running = false - // } - // } - - // pn.run(init, step) + fmt.println(s1) + fmt.println(s2) } diff --git a/code/punity.odin b/code/punity.odin index 4c0253acc..e09fd60c5 100644 --- a/code/punity.odin +++ b/code/punity.odin @@ -1,5 +1,6 @@ #import "win32.odin" as win32 -#import "fmt.odin" as fmt +#import "fmt.odin" as fmt +#import "os.odin" as os CANVAS_WIDTH :: 128 CANVAS_HEIGHT :: 128 @@ -357,7 +358,7 @@ run :: proc(user_init, user_step: proc(c: ^Core)) { } if RegisterClassExA(^window_class) == 0 { - fmt.println_err("RegisterClassExA failed") + fmt.fprintln(os.stderr, "RegisterClassExA failed") return } @@ -377,8 +378,7 @@ run :: proc(user_init, user_step: proc(c: ^Core)) { win32_window := CreateWindowExA(0, window_class.class_name, - WINDOW_TITLE.data, - // wt.data, + wt.data, style, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, @@ -386,7 +386,7 @@ run :: proc(user_init, user_step: proc(c: ^Core)) { null); if win32_window == null { - fmt.println_err("CreateWindowExA failed") + fmt.fprintln(os.stderr, "CreateWindowExA failed") return } @@ -434,7 +434,7 @@ run :: proc(user_init, user_step: proc(c: ^Core)) { { data: [128]byte buf := data[:0] - fmt.print_to_buffer(^buf, "Punity: % ms\x00", dt*1000) + fmt.printf_to_buffer(^buf, "Punity: % ms\x00", dt*1000) win32.SetWindowTextA(win32_window, buf.data) } diff --git a/code/test.odin b/code/test.odin index c4636a7b7..a5df7c4d0 100644 --- a/code/test.odin +++ b/code/test.odin @@ -1,5 +1,5 @@ #import "fmt.odin" as fmt -thing :: proc() { +thing :: proc() #link_name "frankerooney" { fmt.println("Hello!") } diff --git a/core/fmt.odin b/core/fmt.odin index 0c7e3a696..d838b236e 100644 --- a/core/fmt.odin +++ b/core/fmt.odin @@ -1,5 +1,60 @@ #import "os.odin" as os +PRINT_BUF_SIZE :: 1<<12 + +fprint :: proc(f: ^os.File, args: ..any) { + data: [PRINT_BUF_SIZE]byte + buf := data[:0] + prev_string := false + + for i := 0; i < args.count; i++ { + arg := args[i] + is_string := arg.data != null && type_info_is_string(arg.type_info) + if i > 0 && is_string && !prev_string { + print_space_to_buffer(^buf) + } + print_any_to_buffer(^buf, arg) + prev_string = is_string; + } + + os.write(f, buf) +} + +fprintln :: proc(f: ^os.File, args: ..any) { + data: [PRINT_BUF_SIZE]byte + buf := data[:0] + + for i := 0; i < args.count; i++ { + if i > 0 { + append(^buf, #rune " ") + } + print_any_to_buffer(^buf, args[i]) + } + + print_nl_to_buffer(^buf) + os.write(f, buf) +} +fprintf :: proc(f: ^os.File, fmt: string, args: ..any) { + data: [PRINT_BUF_SIZE]byte + buf := data[:0] + printf_to_buffer(^buf, fmt, ..args) + os.write(f, buf) +} + + +print :: proc(args: ..any) { + fprint(os.stdout, ..args) +} +println :: proc(args: ..any) { + fprintln(os.stdout, ..args) +} +printf :: proc(fmt: string, args: ..any) { + fprintf(os.stdout, fmt, ..args) +} + + + + print_byte_buffer :: proc(buf: ^[]byte, b: []byte) { if buf.count < buf.capacity { n := min(buf.capacity-buf.count, b.count) @@ -68,7 +123,7 @@ print_nl_to_buffer :: proc(buf: ^[]byte) { print_rune_to_buffer(buf, #rune "\ print_int_to_buffer :: proc(buf: ^[]byte, i: int) { print_int_base_to_buffer(buf, i, 10); } -PRINT__NUM_TO_CHAR_TABLE :: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@$" +__NUM_TO_CHAR_TABLE :: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@$" print_int_base_to_buffer :: proc(buffer: ^[]byte, i, base: int) { buf: [65]byte @@ -83,7 +138,7 @@ print_int_base_to_buffer :: proc(buffer: ^[]byte, i, base: int) { len++ } for i > 0 { - buf[len] = PRINT__NUM_TO_CHAR_TABLE[i % base] + buf[len] = __NUM_TO_CHAR_TABLE[i % base] len++ i /= base } @@ -108,7 +163,7 @@ print_uint_base_to_buffer :: proc(buffer: ^[]byte, i, base: uint, min_width: int len++ } for i > 0 { - buf[len] = PRINT__NUM_TO_CHAR_TABLE[i % base] + buf[len] = __NUM_TO_CHAR_TABLE[i % base] len++ i /= base } @@ -149,7 +204,7 @@ print__f64 :: proc(buffer: ^[]byte, f: f64, decimal_places: int) { len++ } for i > 0 { - buf[len] = PRINT__NUM_TO_CHAR_TABLE[i % 10] + buf[len] = __NUM_TO_CHAR_TABLE[i % 10] len++ i /= 10 } @@ -334,7 +389,6 @@ print_any_to_buffer :: proc(buf: ^[]byte, arg: any) { 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 16: i = (arg.data as ^i128)^ as int } } print_int_to_buffer(buf, i) @@ -346,7 +400,6 @@ print_any_to_buffer :: proc(buf: ^[]byte, arg: any) { 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 16: i = (arg.data as ^u128)^ as uint } } print_uint_to_buffer(buf, i) @@ -488,7 +541,7 @@ type_info_is_string :: proc(info: ^Type_Info) -> bool { } -print_to_buffer :: proc(buf: ^[]byte, fmt: string, args: ..any) { +printf_to_buffer :: proc(buf: ^[]byte, fmt: string, args: ..any) { is_digit :: proc(r: rune) -> bool #inline { return r >= #rune "0" && r <= #rune "9" } @@ -550,34 +603,3 @@ print_to_buffer :: proc(buf: ^[]byte, fmt: string, args: ..any) { print_string_to_buffer(buf, fmt[prev:]) } - -PRINT_BUF_SIZE :: 1<<12 - -print_to_file :: proc(f: ^os.File, fmt: string, args: ..any) { - data: [PRINT_BUF_SIZE]byte - buf := data[:0] - print_to_buffer(^buf, fmt, ..args) - os.write(f, buf) -} - -println_to_file :: proc(f: ^os.File, fmt: string, args: ..any) { - data: [PRINT_BUF_SIZE]byte - buf := data[:0] - print_to_buffer(^buf, fmt, ..args) - print_nl_to_buffer(^buf) - os.write(f, buf) -} - - -print :: proc(fmt: string, args: ..any) { - print_to_file(os.get_standard_file(os.File_Standard.OUTPUT), fmt, ..args) -} -print_err :: proc(fmt: string, args: ..any) { - print_to_file(os.get_standard_file(os.File_Standard.ERROR), fmt, ..args) -} -println :: proc(fmt: string, args: ..any) { - println_to_file(os.get_standard_file(os.File_Standard.OUTPUT), fmt, ..args) -} -println_err :: proc(fmt: string, args: ..any) { - println_to_file(os.get_standard_file(os.File_Standard.ERROR), fmt, ..args) -} diff --git a/core/os.odin b/core/os.odin index 4c2ef0b41..6f60119f4 100644 --- a/core/os.odin +++ b/core/os.odin @@ -46,6 +46,11 @@ File_Standard :: type enum { __std_files := __set_file_standards(); +stdin := ^__std_files[File_Standard.INPUT] +stdout := ^__std_files[File_Standard.OUTPUT] +stderr := ^__std_files[File_Standard.ERROR] + + __set_file_standards :: proc() -> [File_Standard.COUNT as int]File { return [File_Standard.COUNT as int]File{ File{handle = win32.GetStdHandle(win32.STD_INPUT_HANDLE)}, @@ -54,10 +59,6 @@ __set_file_standards :: proc() -> [File_Standard.COUNT as int]File { } } -get_standard_file :: proc(std: File_Standard) -> ^File { - return ^__std_files[std] -} - read_entire_file :: proc(name: string) -> (string, bool) { buf: [300]byte diff --git a/core/runtime.odin b/core/runtime.odin index f8a07dd9b..98c2ab6ec 100644 --- a/core/runtime.odin +++ b/core/runtime.odin @@ -17,7 +17,6 @@ Type_Info :: union { ordered: bool } - Named: struct #ordered { name: string base: ^Type_Info @@ -59,6 +58,8 @@ Type_Info :: union { Raw_Union: Record Enum: struct #ordered { base: ^Type_Info + values: []i64 + names: []string } } @@ -170,7 +171,7 @@ __string_ge :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) > __assert :: proc(msg: string) { - fmt.print_err("%", msg) + fmt.fprintln(os.stderr, msg) __debug_trap() } @@ -179,8 +180,8 @@ __bounds_check_error :: proc(file: string, line, column: int, if 0 <= index && index < count { return } - fmt.println_err("%(%:%) Index % is out of bounds range [0, %)", - file, line, column, index, count) + fmt.fprintf(os.stderr, "%(%:%) Index % is out of bounds range [0, %)\n", + file, line, column, index, count) __debug_trap() } @@ -189,8 +190,8 @@ __slice_expr_error :: proc(file: string, line, column: int, if 0 <= low && low <= high && high <= max { return } - fmt.println_err("%(%:%) Invalid slice indices: [%:%:%]", - file, line, column, low, high, max) + fmt.fprintf(os.stderr, "%(%:%) Invalid slice indices: [%:%:%]\n", + file, line, column, low, high, max) __debug_trap() } __substring_expr_error :: proc(file: string, line, column: int, @@ -198,8 +199,8 @@ __substring_expr_error :: proc(file: string, line, column: int, if 0 <= low && low <= high { return } - fmt.println_err("%(%:%) Invalid substring indices: [%:%:%]", - file, line, column, low, high) + fmt.fprintf(os.stderr, "%(%:%) Invalid substring indices: [%:%:%]\n", + file, line, column, low, high) __debug_trap() } @@ -341,5 +342,25 @@ __default_allocator :: proc() -> Allocator { } +__enum_to_string :: proc(info: ^Type_Info, value: i64) -> string { + for { + match type i : info { + case Type_Info.Named: + info = i.base + continue + } + break + } + match type ti : info { + case Type_Info.Enum: + fmt.println("Here: ", ti.values.count) + for i := 0; i < ti.values.count; i++ { + if ti.values[i] == value { + return ti.names[i] + } + } + } + return "" +} diff --git a/src/checker/checker.cpp b/src/checker/checker.cpp index cc7099e96..483b6c0ef 100644 --- a/src/checker/checker.cpp +++ b/src/checker/checker.cpp @@ -159,6 +159,8 @@ enum BuiltinProcId { BuiltinProc_max, BuiltinProc_abs, + BuiltinProc_enum_to_string, + BuiltinProc_Count, }; @@ -200,6 +202,8 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_Count] = { {STR_LIT("max"), 2, false, Expr_Expr}, {STR_LIT("abs"), 1, false, Expr_Expr}, + {STR_LIT("enum_to_string"), 1, false, Expr_Expr}, + }; struct CheckerContext { @@ -358,6 +362,9 @@ void scope_lookup_parent_entity(Scope *scope, String name, Scope **scope_, Entit // Do not return imported entities even #load ones continue; } + if (!is_entity_exported(e)) { + continue; + } if (entity_) *entity_ = e; if (scope_) *scope_ = shared; return; @@ -409,7 +416,7 @@ Entity *scope_insert_entity(Scope *s, Entity *entity) { void check_scope_usage(Checker *c, Scope *scope) { // TODO(bill): Use this? -#if 0 +#if 1 gb_for_array(i, scope->elements.entries) { auto *entry = scope->elements.entries + i; Entity *e = entry->value; @@ -445,7 +452,7 @@ void add_global_entity(Entity *entity) { return; // NOTE(bill): `untyped thing` } if (scope_insert_entity(universal_scope, entity)) { - GB_PANIC("Compiler error: double declaration"); + compiler_error("double declaration"); } } @@ -492,10 +499,6 @@ void init_universal_scope(void) { entity->Builtin.id = id; add_global_entity(entity); } - -// Custom Runtime Types - { - } } @@ -1112,12 +1115,27 @@ void check_parsed_files(Checker *c) { ExpressionInfo *info = &entry->value; if (info != NULL && expr != NULL) { if (is_type_typed(info->type)) { - GB_PANIC("%s (type %s) is typed!", expr_to_string(expr), info->type); + compiler_error("%s (type %s) is typed!", expr_to_string(expr), info->type); } add_type_and_value(&c->info, expr, info->mode, info->type, info->value); } } #endif + + gb_for_array(i, c->parser->files) { + AstFile *f = &c->parser->files[i]; + Scope *scope = f->scope; + gb_for_array(j, scope->elements.entries) { + Entity *e = scope->elements.entries[j].value; + switch (e->kind) { + case Entity_ImportName: { + if (!e->ImportName.used) { + warning(e->token, "Unused import name: %.*s", LIT(e->ImportName.name)); + } + } break; + } + } + } } diff --git a/src/checker/expr.cpp b/src/checker/expr.cpp index a16315d4c..05e539bac 100644 --- a/src/checker/expr.cpp +++ b/src/checker/expr.cpp @@ -385,25 +385,34 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls, // TODO(bill): Cleanup struct field reordering +// TODO(bill): Inline sorting procedure? gb_global BaseTypeSizes __checker_sizes = {}; gb_global gbAllocator __checker_allocator = {}; GB_COMPARE_PROC(cmp_struct_entity_size) { - // Rule: Biggest to smallest - // if same size, order by order in source + // Rule: + // Biggest to smallest alignment + // if same alignment: biggest to smallest size + // if same size: order by source order Entity *x = *(Entity **)a; Entity *y = *(Entity **)b; GB_ASSERT(x != NULL); GB_ASSERT(y != NULL); GB_ASSERT(x->kind == Entity_Variable); GB_ASSERT(y->kind == Entity_Variable); + i64 xa = type_align_of(__checker_sizes, __checker_allocator, x->type); + i64 ya = type_align_of(__checker_sizes, __checker_allocator, y->type); i64 xs = type_size_of(__checker_sizes, __checker_allocator, x->type); i64 ys = type_size_of(__checker_sizes, __checker_allocator, y->type); - if (xs == ys) { - i32 diff = x->Variable.field_index - y->Variable.field_index; - return diff < 0 ? -1 : diff > 0; + + if (xa == ya) { + if (xs == ys) { + i32 diff = x->Variable.field_index - y->Variable.field_index; + return diff < 0 ? -1 : diff > 0; + } + return xs > ys ? -1 : xs < ys; } - return xs > ys ? -1 : xs < ys; + return xa > ya ? -1 : xa < ya; } void check_struct_type(Checker *c, Type *struct_type, AstNode *node, CycleChecker *cycle_checker) { @@ -746,6 +755,11 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type, Cycl error(n->Ident, "Undeclared name: %.*s", LIT(n->Ident.string)); } + o->type = t_invalid; + o->mode = Addressing_Invalid; + if (named_type != NULL) { + set_base_type(named_type, t_invalid); + } return; } add_entity_use(&c->info, n, e); @@ -761,7 +775,7 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type, Cycl check_entity_decl(c, e, NULL, named_type, cycle_checker); if (e->type == NULL) { - GB_PANIC("Compiler error: How did this happen? type: %s; identifier: %.*s\n", type_to_string(e->type), LIT(n->Ident.string)); + compiler_error("Compiler error: How did this happen? type: %s; identifier: %.*s\n", type_to_string(e->type), LIT(n->Ident.string)); return; } @@ -820,7 +834,7 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type, Cycl return; default: - GB_PANIC("Compiler error: Unknown EntityKind"); + compiler_error("Compiler error: Unknown EntityKind"); break; } @@ -2785,6 +2799,44 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) operand->type = type; } break; + + case BuiltinProc_enum_to_string: { + Type *type = get_base_type(operand->type); + if (!is_type_enum(type)) { + gbString type_str = type_to_string(operand->type); + defer (gb_string_free(type_str)); + error(ast_node_token(call), + "Expected an enum to `enum_to_string`, got `%s`", + type_str); + return false; + } + + if (operand->mode == Addressing_Constant) { + ExactValue value = make_exact_value_string(make_string("")); + if (operand->value.kind == ExactValue_Integer) { + i64 index = operand->value.value_integer; + for (isize i = 0; i < type->Record.other_field_count; i++) { + Entity *f = type->Record.other_fields[i]; + if (f->kind == Entity_Constant && f->Constant.value.kind == ExactValue_Integer) { + i64 fv = f->Constant.value.value_integer; + if (index == fv) { + value = make_exact_value_string(f->token.string); + break; + } + } + } + } + + operand->value = value; + operand->type = t_string; + return true; + } + + add_type_info_type(c, operand->type); + + operand->mode = Addressing_Value; + operand->type = t_string; + } break; } return true; @@ -2832,8 +2884,10 @@ void check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNode Entity **sig_params = proc_type->Proc.params->Tuple.variables; gb_for_array(arg_index, ce->args) { check_multi_expr(c, operand, ce->args[arg_index]); - if (operand->mode == Addressing_Invalid) + if (operand->mode == Addressing_Invalid) { + param_index++; continue; + } if (operand->type->kind != Type_Tuple) { check_not_tuple(c, operand); isize index = param_index; @@ -3083,7 +3137,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint case Type_Record: { if (!is_type_struct(t)) break; - if (gb_array_count(cl->elems) == 0) { + if (cl->elems == NULL || gb_array_count(cl->elems) == 0) { break; // NOTE(bill): No need to init } { // Checker values diff --git a/src/checker/stmt.cpp b/src/checker/stmt.cpp index a8e590728..9acf62c6d 100644 --- a/src/checker/stmt.cpp +++ b/src/checker/stmt.cpp @@ -8,9 +8,12 @@ enum StmtFlag : u32 { void check_stmt(Checker *c, AstNode *node, u32 flags); -void check_proc_decl(Checker *c, Entity *e, DeclInfo *d, b32 check_body_later); +void check_proc_decl(Checker *c, Entity *e, DeclInfo *d); void check_stmt_list(Checker *c, AstNodeArray stmts, u32 flags) { + // TODO(bill): Allow declaration (expect variable) in any order + // even within a procedure + b32 ft_ok = (flags & Stmt_FallthroughAllowed) != 0; u32 f = flags & (~Stmt_FallthroughAllowed); @@ -321,7 +324,7 @@ void check_init_constant(Checker *c, Entity *e, Operand *operand) { } if (!is_type_constant_type(operand->type)) { // NOTE(bill): no need to free string as it's panicking - GB_PANIC("Compiler error: Type `%s` not constant!!!", type_to_string(operand->type)); + compiler_error("Type `%s` not constant!!!", type_to_string(operand->type)); } if (e->type == NULL) // NOTE(bill): type inference @@ -482,7 +485,7 @@ b32 are_signatures_similar_enough(Type *a_, Type *b_) { return true; } -void check_proc_decl(Checker *c, Entity *e, DeclInfo *d, b32 check_body_later) { +void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) { GB_ASSERT(e->type == NULL); Type *proc_type = make_type_proc(c->allocator, e->scope, NULL, 0, NULL, 0, false); @@ -494,6 +497,7 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d, b32 check_body_later) { b32 is_foreign = (pd->tags & ProcTag_foreign) != 0; + b32 is_link_name = (pd->tags & ProcTag_link_name) != 0; b32 is_inline = (pd->tags & ProcTag_inline) != 0; b32 is_no_inline = (pd->tags & ProcTag_no_inline) != 0; @@ -527,11 +531,7 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d, b32 check_body_later) { d->scope = c->context.scope; GB_ASSERT(pd->body->kind == AstNode_BlockStmt); - if (check_body_later) { - check_procedure_later(c, c->curr_ast_file, e->token, d, proc_type, pd->body); - } else { - check_proc_body(c, e->token, d, proc_type, pd->body); - } + check_procedure_later(c, c->curr_ast_file, e->token, d, proc_type, pd->body); } if (is_foreign) { @@ -557,6 +557,23 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d, b32 check_body_later) { } else { map_set(fp, key, e); } + } else if (is_link_name) { + auto *fp = &c->info.foreign_procs; + auto *proc_decl = &d->proc_decl->ProcDecl; + String name = proc_decl->link_name; + + HashKey key = hash_string(name); + auto *found = map_get(fp, key); + if (found) { + Entity *f = *found; + TokenPos pos = f->token.pos; + error(ast_node_token(d->proc_decl), + "Non unique #link_name for procedure `%.*s`\n" + "\tother at %.*s(%td:%td)", + LIT(name), LIT(pos.file), pos.line, pos.column); + } else { + map_set(fp, key, e); + } } } @@ -610,7 +627,9 @@ void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type, Cyc if (found) { d = *found; } else { - GB_PANIC("`%.*s` should been declared!", LIT(e->token.string)); + e->type = t_invalid; + return; + // GB_PANIC("`%.*s` should been declared!", LIT(e->token.string)); } } @@ -620,7 +639,7 @@ void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type, Cyc // defer (c->context.scope = prev); if (e->kind == Entity_Procedure) { - check_proc_decl(c, e, d, true); + check_proc_decl(c, e, d); return; } @@ -644,7 +663,7 @@ void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type, Cyc } break; case Entity_Procedure: { - check_proc_decl(c, e, d, true); + check_proc_decl(c, e, d); } break; @@ -1261,6 +1280,7 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { // NOTE(bill): Dummy type Type *tag_ptr_type = make_type_pointer(c->allocator, tag_type); Entity *tag_var = make_entity_variable(c->allocator, c->context.scope, ms->var->Ident, tag_ptr_type); + tag_var->Variable.used = true; add_entity(c, c->context.scope, ms->var, tag_var); add_entity_use(&c->info, ms->var, tag_var); } @@ -1481,7 +1501,7 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { DeclInfo *decl = make_declaration_info(c->allocator, e->scope); decl->proc_decl = node; - check_proc_decl(c, e, decl, false); + check_proc_decl(c, e, decl); case_end; case_ast_node(td, TypeDecl, node); diff --git a/src/checker/type.cpp b/src/checker/type.cpp index 96b0149f7..6caf12141 100644 --- a/src/checker/type.cpp +++ b/src/checker/type.cpp @@ -7,12 +7,10 @@ enum BasicKind { Basic_i16, Basic_i32, Basic_i64, - Basic_i128, Basic_u8, Basic_u16, Basic_u32, Basic_u64, - Basic_u128, Basic_f32, Basic_f64, Basic_int, @@ -296,12 +294,10 @@ gb_global Type basic_types[] = { {0, Type_Basic, {Basic_i16, BasicFlag_Integer, STR_LIT("i16")}}, {0, Type_Basic, {Basic_i32, BasicFlag_Integer, STR_LIT("i32")}}, {0, Type_Basic, {Basic_i64, BasicFlag_Integer, STR_LIT("i64")}}, - {0, Type_Basic, {Basic_i128, BasicFlag_Integer, STR_LIT("i128")}}, {0, Type_Basic, {Basic_u8, BasicFlag_Integer | BasicFlag_Unsigned, STR_LIT("u8")}}, {0, Type_Basic, {Basic_u16, BasicFlag_Integer | BasicFlag_Unsigned, STR_LIT("u16")}}, {0, Type_Basic, {Basic_u32, BasicFlag_Integer | BasicFlag_Unsigned, STR_LIT("u32")}}, {0, Type_Basic, {Basic_u64, BasicFlag_Integer | BasicFlag_Unsigned, STR_LIT("u64")}}, - {0, Type_Basic, {Basic_u128, BasicFlag_Integer | BasicFlag_Unsigned, STR_LIT("u128")}}, {0, Type_Basic, {Basic_f32, BasicFlag_Float, STR_LIT("f32")}}, {0, Type_Basic, {Basic_f64, BasicFlag_Float, STR_LIT("f64")}}, {0, Type_Basic, {Basic_int, BasicFlag_Integer, STR_LIT("int")}}, @@ -328,12 +324,10 @@ gb_global Type *t_i8 = &basic_types[Basic_i8]; gb_global Type *t_i16 = &basic_types[Basic_i16]; gb_global Type *t_i32 = &basic_types[Basic_i32]; gb_global Type *t_i64 = &basic_types[Basic_i64]; -gb_global Type *t_i128 = &basic_types[Basic_i128]; gb_global Type *t_u8 = &basic_types[Basic_u8]; gb_global Type *t_u16 = &basic_types[Basic_u16]; gb_global Type *t_u32 = &basic_types[Basic_u32]; gb_global Type *t_u64 = &basic_types[Basic_u64]; -gb_global Type *t_u128 = &basic_types[Basic_u128]; gb_global Type *t_f32 = &basic_types[Basic_f32]; gb_global Type *t_f64 = &basic_types[Basic_f64]; gb_global Type *t_int = &basic_types[Basic_int]; @@ -602,7 +596,12 @@ b32 are_types_identical(Type *x, Type *y) { break; case TypeRecord_Enum: - return are_types_identical(x->Record.enum_base, y->Record.enum_base); + if (are_types_identical(x->Record.enum_base, y->Record.enum_base)) { + if (x->Record.field_count == y->Record.field_count) { + return x->Record.fields == y->Record.fields; + } + } + return false; } } } @@ -679,12 +678,10 @@ gb_global i64 basic_type_sizes[] = { 2, // Basic_i16 4, // Basic_i32 8, // Basic_i64 - 16, // Basic_i128 1, // Basic_u8 2, // Basic_u16 4, // Basic_u32 8, // Basic_u64 - 16, // Basic_u128 4, // Basic_f32 8, // Basic_f64 }; @@ -954,7 +951,8 @@ i64 type_align_of(BaseTypeSizes s, gbAllocator allocator, Type *t) { } break; } - return gb_clamp(next_pow2(type_size_of(s, allocator, t)), 1, s.max_align); + // return gb_clamp(next_pow2(type_size_of(s, allocator, t)), 1, s.max_align); + return gb_clamp(next_pow2(type_size_of(s, allocator, t)), 1, s.word_size); } i64 *type_set_offsets_of(BaseTypeSizes s, gbAllocator allocator, Entity **fields, isize field_count, b32 is_packed) { diff --git a/src/codegen/codegen.cpp b/src/codegen/codegen.cpp index 9c71ea917..54ec5f2ba 100644 --- a/src/codegen/codegen.cpp +++ b/src/codegen/codegen.cpp @@ -67,16 +67,6 @@ String ssa_mangle_name(ssaGen *s, String path, String name) { } void ssa_gen_tree(ssaGen *s) { - if (v_zero == NULL) { - v_zero = ssa_make_const_int (gb_heap_allocator(), 0); - v_one = ssa_make_const_int (gb_heap_allocator(), 1); - v_zero32 = ssa_make_const_i32 (gb_heap_allocator(), 0); - v_one32 = ssa_make_const_i32 (gb_heap_allocator(), 1); - v_two32 = ssa_make_const_i32 (gb_heap_allocator(), 2); - v_false = ssa_make_const_bool(gb_heap_allocator(), false); - v_true = ssa_make_const_bool(gb_heap_allocator(), true); - } - struct ssaGlobalVariable { ssaValue *var, *init; DeclInfo *decl; @@ -85,9 +75,35 @@ void ssa_gen_tree(ssaGen *s) { ssaModule *m = &s->module; CheckerInfo *info = m->info; gbAllocator a = m->allocator; + + if (v_zero == NULL) { + v_zero = ssa_make_const_int (m->allocator, 0); + v_one = ssa_make_const_int (m->allocator, 1); + v_zero32 = ssa_make_const_i32 (m->allocator, 0); + v_one32 = ssa_make_const_i32 (m->allocator, 1); + v_two32 = ssa_make_const_i32 (m->allocator, 2); + v_false = ssa_make_const_bool(m->allocator, false); + v_true = ssa_make_const_bool(m->allocator, true); + } + + isize global_variable_max_count = 0; + + gb_for_array(i, info->entities.entries) { + auto *entry = &info->entities.entries[i]; + Entity *e = cast(Entity *)cast(uintptr)entry->key.key; + if (e->kind == Entity_Variable) { + global_variable_max_count++; + } + } + + + gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&m->tmp_arena); + defer (gb_temp_arena_memory_end(tmp)); + gbArray(ssaGlobalVariable) global_variables; - gb_array_init(global_variables, gb_heap_allocator()); - defer (gb_array_free(global_variables)); + gb_array_init_reserve(global_variables, m->tmp_allocator, global_variable_max_count); + + gb_for_array(i, info->entities.entries) { auto *entry = &info->entities.entries[i]; @@ -123,7 +139,7 @@ void ssa_gen_tree(ssaGen *s) { ExactValue v = tav->value; if (v.kind == ExactValue_String) { // NOTE(bill): The printer will fix the value correctly - g->Global.value = ssa_add_global_string_array(m, v.value_string); + // g->Global.value = ssa_add_global_string_array(m, v.value_string); } else { g->Global.value = ssa_make_value_constant(a, tav->type, v); } @@ -147,6 +163,8 @@ void ssa_gen_tree(ssaGen *s) { } if (pd->foreign_name.len > 0) { name = pd->foreign_name; + } else if (pd->link_name.len > 0) { + name = pd->link_name; } ssaValue *p = ssa_make_value_procedure(a, m, e, e->type, decl->type_expr, body, name); @@ -171,7 +189,18 @@ void ssa_gen_tree(ssaGen *s) { ssaDebugInfo *compile_unit = m->debug_info.entries[0].value; GB_ASSERT(compile_unit->kind == ssaDebugInfo_CompileUnit); ssaDebugInfo *all_procs = ssa_alloc_debug_info(m->allocator, ssaDebugInfo_AllProcs); - gb_array_init(all_procs->AllProcs.procs, gb_heap_allocator()); + + isize all_proc_max_count = 0; + gb_for_array(i, m->debug_info.entries) { + auto *entry = &m->debug_info.entries[i]; + ssaDebugInfo *di = entry->value; + di->id = i; + if (di->kind == ssaDebugInfo_Proc) { + all_proc_max_count++; + } + } + + gb_array_init_reserve(all_procs->AllProcs.procs, m->allocator, all_proc_max_count); map_set(&m->debug_info, hash_pointer(all_procs), all_procs); // NOTE(bill): This doesn't need to be mapped compile_unit->CompileUnit.all_procs = all_procs; @@ -250,10 +279,12 @@ void ssa_gen_tree(ssaGen *s) { // Useful types Type *t_int_ptr = make_type_pointer(a, t_int); + Type *t_i64_ptr = make_type_pointer(a, t_i64); Type *t_bool_ptr = make_type_pointer(a, t_bool); Type *t_string_ptr = make_type_pointer(a, t_string); Type *t_type_info_ptr_ptr = make_type_pointer(a, t_type_info_ptr); - + Type *t_i64_slice_ptr = make_type_pointer(a, make_type_slice(a, t_i64)); + Type *t_string_slice_ptr = make_type_pointer(a, make_type_slice(a, t_string)); auto get_type_info_ptr = [](ssaProcedure *proc, ssaValue *type_info_data, Type *type) -> ssaValue * { return ssa_emit_struct_gep(proc, type_info_data, @@ -302,12 +333,12 @@ void ssa_gen_tree(ssaGen *s) { case Basic_i16: case Basic_i32: case Basic_i64: - case Basic_i128: + // case Basic_i128: case Basic_u8: case Basic_u16: case Basic_u32: case Basic_u64: - case Basic_u128: + // case Basic_u128: case Basic_int: case Basic_uint: { tag = ssa_add_local_generated(proc, t_type_info_integer); @@ -467,8 +498,72 @@ void ssa_gen_tree(ssaGen *s) { if (enum_base == NULL) { enum_base = t_int; } - ssaValue *gep = get_type_info_ptr(proc, type_info_data, enum_base); - ssa_emit_store(proc, ssa_emit_struct_gep(proc, tag, v_zero32, t_type_info_ptr_ptr), gep); + ssaValue *base = ssa_emit_struct_gep(proc, tag, v_zero32, t_type_info_ptr_ptr); + ssa_emit_store(proc, base, get_type_info_ptr(proc, type_info_data, enum_base)); + + if (t->Record.other_field_count > 0) { + Entity **fields = t->Record.other_fields; + isize count = t->Record.other_field_count; + ssaValue *value_array = NULL; + ssaValue *name_array = NULL; + + + { + Token token = {Token_Identifier}; + i32 id = cast(i32)entry_index; + char name_base[] = "__$enum_values"; + isize name_len = gb_size_of(name_base) + 10; + token.string.text = gb_alloc_array(a, u8, name_len); + token.string.len = gb_snprintf(cast(char *)token.string.text, name_len, + "%s-%d", name_base, id)-1; + Entity *e = make_entity_variable(a, NULL, token, make_type_array(a, t_i64, count)); + value_array = ssa_make_value_global(a, e, NULL); + value_array->Global.is_private = true; + ssa_module_add_value(m, e, value_array); + map_set(&m->members, hash_string(token.string), value_array); + } + { + Token token = {Token_Identifier}; + i32 id = cast(i32)entry_index; + char name_base[] = "__$enum_names"; + isize name_len = gb_size_of(name_base) + 10; + token.string.text = gb_alloc_array(a, u8, name_len); + token.string.len = gb_snprintf(cast(char *)token.string.text, name_len, + "%s-%d", name_base, id)-1; + Entity *e = make_entity_variable(a, NULL, token, make_type_array(a, t_string, count)); + name_array = ssa_make_value_global(a, e, NULL); + name_array->Global.is_private = true; + ssa_module_add_value(m, e, name_array); + map_set(&m->members, hash_string(token.string), name_array); + } + + for (isize i = 0; i < count; i++) { + ssaValue *value_gep = ssa_emit_struct_gep(proc, value_array, i, t_i64_ptr); + ssaValue *name_gep = ssa_emit_struct_gep(proc, name_array, i, t_string_ptr); + + ssa_emit_store(proc, value_gep, ssa_make_const_i64(a, fields[i]->Constant.value.value_integer)); + ssa_emit_store(proc, name_gep, ssa_emit_global_string(proc, fields[i]->token.string)); + } + + ssaValue *v_count = ssa_make_const_int(a, count); + + + ssaValue *values = ssa_emit_struct_gep(proc, tag, v_one32, t_i64_slice_ptr); + ssaValue *names = ssa_emit_struct_gep(proc, tag, v_two32, t_string_slice_ptr); + ssaValue *value_slice = ssa_add_local_generated(proc, type_deref(t_i64_slice_ptr)); + ssaValue *name_slice = ssa_add_local_generated(proc, type_deref(t_string_slice_ptr)); + + ssa_emit_store(proc, ssa_emit_struct_gep(proc, value_slice, v_zero32, t_i64_ptr), ssa_array_elem(proc, value_array)); + ssa_emit_store(proc, ssa_emit_struct_gep(proc, value_slice, v_one32, t_int_ptr), v_count); + ssa_emit_store(proc, ssa_emit_struct_gep(proc, value_slice, v_two32, t_int_ptr), v_count); + + ssa_emit_store(proc, ssa_emit_struct_gep(proc, name_slice, v_zero32, t_string_ptr), ssa_array_elem(proc, name_array)); + ssa_emit_store(proc, ssa_emit_struct_gep(proc, name_slice, v_one32, t_int_ptr), v_count); + ssa_emit_store(proc, ssa_emit_struct_gep(proc, name_slice, v_two32, t_int_ptr), v_count); + + ssa_emit_store(proc, values, ssa_emit_load(proc, value_slice)); + ssa_emit_store(proc, names, ssa_emit_load(proc, name_slice)); + } } break; } } break; @@ -515,10 +610,10 @@ void ssa_gen_tree(ssaGen *s) { ssaValue *variadic = ssa_emit_struct_gep(proc, tag, v_two32, t_bool_ptr); if (t->Proc.params) { - ssa_emit_store(proc, params, get_type_info_ptr(proc, type_info_data, t->Proc.params)); + ssa_emit_store(proc, params, get_type_info_ptr(proc, type_info_data, t->Proc.params)); } if (t->Proc.results) { - ssa_emit_store(proc, results, get_type_info_ptr(proc, type_info_data, t->Proc.results)); + ssa_emit_store(proc, results, get_type_info_ptr(proc, type_info_data, t->Proc.results)); } ssa_emit_store(proc, variadic, ssa_make_const_bool(a, t->Proc.variadic)); diff --git a/src/codegen/print_llvm.cpp b/src/codegen/print_llvm.cpp index aaaea2cb0..b13644a5f 100644 --- a/src/codegen/print_llvm.cpp +++ b/src/codegen/print_llvm.cpp @@ -142,12 +142,12 @@ void ssa_print_type(ssaFileBuffer *f, ssaModule *m, Type *t) { case Basic_i16: ssa_fprintf(f, "i16"); break; case Basic_i32: ssa_fprintf(f, "i32"); break; case Basic_i64: ssa_fprintf(f, "i64"); break; - case Basic_i128: ssa_fprintf(f, "i128"); break; + // case Basic_i128: ssa_fprintf(f, "i128"); break; case Basic_u8: ssa_fprintf(f, "i8"); break; case Basic_u16: ssa_fprintf(f, "i16"); break; case Basic_u32: ssa_fprintf(f, "i32"); break; case Basic_u64: ssa_fprintf(f, "i64"); break; - case Basic_u128: ssa_fprintf(f, "i128"); break; + // case Basic_u128: ssa_fprintf(f, "i128"); break; case Basic_f32: ssa_fprintf(f, "float"); break; case Basic_f64: ssa_fprintf(f, "double"); break; case Basic_rawptr: ssa_fprintf(f, "%%..rawptr"); break; @@ -346,27 +346,27 @@ void ssa_print_value(ssaFileBuffer *f, ssaModule *m, ssaValue *value, Type *type if (scope != NULL) { in_global_scope = scope->is_global || scope->is_init; } - if (type_hint != NULL && is_type_string(type_hint)) { - ssa_fprintf(f, "{i8* getelementptr inbounds ("); - ssa_print_type(f, m, value->Global.entity->type); - ssa_fprintf(f, ", "); - ssa_print_type(f, m, value->Global.entity->type); - ssa_fprintf(f, "* "); + // if (type_hint != NULL && is_type_string(type_hint)) { + // ssa_fprintf(f, "{i8* getelementptr inbounds ("); + // ssa_print_type(f, m, value->Global.entity->type); + // ssa_fprintf(f, ", "); + // ssa_print_type(f, m, value->Global.entity->type); + // ssa_fprintf(f, "* "); + // ssa_print_encoded_global(f, value->Global.entity->token.string, in_global_scope); + // ssa_fprintf(f, ", "); + // ssa_print_type(f, m, t_int); + // ssa_fprintf(f, " 0, i32 0), "); + // ssa_print_type(f, m, t_int); + // ssa_fprintf(f, " %lld}", 0); + // } else { ssa_print_encoded_global(f, value->Global.entity->token.string, in_global_scope); - ssa_fprintf(f, ", "); - ssa_print_type(f, m, t_int); - ssa_fprintf(f, " 0, i32 0), "); - ssa_print_type(f, m, t_int); - ssa_fprintf(f, " %lld}", 0); - } else { - ssa_print_encoded_global(f, value->Global.entity->token.string, in_global_scope); - } + // } } break; case ssaValue_Param: ssa_print_encoded_local(f, value->Param.entity->token.string); break; case ssaValue_Proc: - ssa_print_encoded_global(f, value->Proc.name, (value->Proc.tags & ProcTag_foreign) != 0); + ssa_print_encoded_global(f, value->Proc.name, (value->Proc.tags & (ProcTag_foreign|ProcTag_link_name)) != 0); break; case ssaValue_Instr: ssa_fprintf(f, "%%%d", value->id); @@ -788,11 +788,7 @@ void ssa_print_proc(ssaFileBuffer *f, ssaModule *m, ssaProcedure *proc) { } ssa_fprintf(f, " "); - if (are_strings_equal(proc->name, make_string("main"))) { - ssa_print_encoded_global(f, proc->name, true); - } else { - ssa_print_encoded_global(f, proc->name, (proc->tags & ProcTag_foreign) != 0); - } + ssa_print_encoded_global(f, proc->name, (proc->tags & (ProcTag_foreign|ProcTag_link_name)) != 0); ssa_fprintf(f, "("); if (proc_type->param_count > 0) { @@ -818,12 +814,6 @@ void ssa_print_proc(ssaFileBuffer *f, ssaModule *m, ssaProcedure *proc) { ssa_fprintf(f, "noinline "); } - // if (proc->tags & ProcTag_stdcall) { - // ssa_fprintf(f, "\"cc\"=\"64\" "); - // } - // if (proc->tags & ProcTag_fastcall) { - // ssa_fprintf(f, "\"cc\"=\"65\" "); - // } if (proc->module->generate_debug_info && proc->entity != NULL) { ssaDebugInfo *di = *map_get(&proc->module->debug_info, hash_pointer(proc->entity)); diff --git a/src/codegen/ssa.cpp b/src/codegen/ssa.cpp index 630c702ab..dd230577c 100644 --- a/src/codegen/ssa.cpp +++ b/src/codegen/ssa.cpp @@ -46,7 +46,9 @@ struct ssaModule { CheckerInfo * info; BaseTypeSizes sizes; gbArena arena; + gbArena tmp_arena; gbAllocator allocator; + gbAllocator tmp_allocator; b32 generate_debug_info; u32 stmt_state_flags; @@ -364,7 +366,9 @@ void ssa_init_module(ssaModule *m, Checker *c) { isize token_count = c->parser->total_token_count; isize arena_size = 4 * token_count * gb_size_of(ssaValue); gb_arena_init_from_allocator(&m->arena, gb_heap_allocator(), arena_size); - m->allocator = gb_arena_allocator(&m->arena); + gb_arena_init_from_allocator(&m->tmp_arena, gb_heap_allocator(), arena_size); + m->allocator = gb_arena_allocator(&m->arena); + m->tmp_allocator = gb_arena_allocator(&m->tmp_arena); m->info = &c->info; m->sizes = c->sizes; @@ -770,6 +774,9 @@ ssaValue *ssa_make_const_int(gbAllocator a, i64 i) { ssaValue *ssa_make_const_i32(gbAllocator a, i64 i) { return ssa_make_value_constant(a, t_i32, make_exact_value_integer(i)); } +ssaValue *ssa_make_const_i64(gbAllocator a, i64 i) { + return ssa_make_value_constant(a, t_i64, make_exact_value_integer(i)); +} ssaValue *ssa_make_const_bool(gbAllocator a, b32 b) { return ssa_make_value_constant(a, t_bool, make_exact_value_bool(b != 0)); } @@ -1066,8 +1073,10 @@ ssaValue *ssa_lvalue_load(ssaProcedure *proc, ssaAddr lval) { void ssa_begin_procedure_body(ssaProcedure *proc) { - gb_array_init(proc->blocks, gb_heap_allocator()); + gb_array_init(proc->blocks, gb_heap_allocator()); gb_array_init(proc->defer_stmts, gb_heap_allocator()); + gb_array_init(proc->children, gb_heap_allocator()); + proc->decl_block = ssa_add_block(proc, proc->type_expr, make_string("decls")); proc->entry_block = ssa_add_block(proc, proc->type_expr, make_string("entry")); proc->curr_block = proc->entry_block; @@ -1466,7 +1475,7 @@ ssaValue *ssa_add_local_slice(ssaProcedure *proc, Type *slice_type, ssaValue *ba ssaValue *ssa_add_global_string_array(ssaModule *m, String string) { - gbAllocator a = gb_heap_allocator(); + gbAllocator a = m->allocator; isize max_len = 4+8+1; u8 *str = cast(u8 *)gb_alloc_array(a, u8, max_len); @@ -2005,9 +2014,6 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue case_end; case_ast_node(pl, ProcLit, expr); - if (proc->children == NULL) { - gb_array_init(proc->children, gb_heap_allocator()); - } // NOTE(bill): Generate a new name // parent$count isize name_len = proc->name.len + 1 + 8 + 1; @@ -2456,6 +2462,20 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue ssaValue *cond = ssa_emit_comp(proc, lt, x, v_zero); return ssa_emit_select(proc, cond, neg_x, x); } break; + + + case BuiltinProc_enum_to_string: { + ssa_emit_comment(proc, make_string("enum_to_string")); + ssaValue *x = ssa_build_expr(proc, ce->args[0]); + Type *t = ssa_type(x); + ssaValue *ti = ssa_type_info(proc, t); + + + ssaValue **args = gb_alloc_array(proc->module->allocator, ssaValue *, 2); + args[0] = ti; + args[1] = ssa_emit_conv(proc, x, t_i64); + return ssa_emit_global_call(proc, "__enum_to_string", args, 2); + } break; } } } @@ -2673,7 +2693,6 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) { String selector = unparen_expr(se->selector)->Ident.string; Type *type = get_base_type(type_of_expr(proc->module->info, se->expr)); - if (type == t_invalid) { // Imports Entity *imp = entity_of_ident(proc->module->info, se->expr); @@ -3039,13 +3058,15 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) { case_end; case_ast_node(vd, VarDecl, node); + ssaModule *m = proc->module; + gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&m->tmp_arena); + defer (gb_temp_arena_memory_end(tmp)); + if (gb_array_count(vd->names) == gb_array_count(vd->values)) { // 1:1 assigment gbArray(ssaAddr) lvals; gbArray(ssaValue *) inits; - gb_array_init_reserve(lvals, gb_heap_allocator(), gb_array_count(vd->names)); - gb_array_init_reserve(inits, gb_heap_allocator(), gb_array_count(vd->names)); - defer (gb_array_free(lvals)); - defer (gb_array_free(inits)); + gb_array_init_reserve(lvals, m->tmp_allocator, gb_array_count(vd->names)); + gb_array_init_reserve(inits, m->tmp_allocator, gb_array_count(vd->names)); gb_for_array(i, vd->names) { AstNode *name = vd->names[i]; @@ -3079,10 +3100,8 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) { } else { // Tuple(s) gbArray(ssaAddr) lvals; gbArray(ssaValue *) inits; - gb_array_init_reserve(lvals, gb_heap_allocator(), gb_array_count(vd->names)); - gb_array_init_reserve(inits, gb_heap_allocator(), gb_array_count(vd->names)); - defer (gb_array_free(lvals)); - defer (gb_array_free(inits)); + gb_array_init_reserve(lvals, m->tmp_allocator, gb_array_count(vd->names)); + gb_array_init_reserve(inits, m->tmp_allocator, gb_array_count(vd->names)); gb_for_array(i, vd->names) { AstNode *name = vd->names[i]; @@ -3118,15 +3137,15 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) { case_end; case_ast_node(pd, ProcDecl, node); - if (proc->children == NULL) { - gb_array_init(proc->children, gb_heap_allocator()); - } - - if (pd->body != NULL) { // NOTE(bill): Generate a new name // parent$name-guid - String pd_name = pd->name->Ident.string; + String original_name = pd->name->Ident.string; + String pd_name = original_name; + if (pd->link_name.len > 0) { + pd_name = pd->link_name; + } + isize name_len = proc->name.len + 1 + pd_name.len + 1 + 10 + 1; u8 *name_text = gb_alloc_array(proc->module->allocator, u8, name_len); i32 guid = cast(i32)gb_array_count(proc->children); @@ -3205,11 +3224,15 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) { case_ast_node(as, AssignStmt, node); ssa_emit_comment(proc, make_string("AssignStmt")); + + ssaModule *m = proc->module; + gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&m->tmp_arena); + defer (gb_temp_arena_memory_end(tmp)); + switch (as->op.kind) { case Token_Eq: { gbArray(ssaAddr) lvals; - gb_array_init(lvals, gb_heap_allocator()); - defer (gb_array_free(lvals)); + gb_array_init(lvals, m->tmp_allocator); gb_for_array(i, as->lhs) { AstNode *lhs = as->lhs[i]; @@ -3227,8 +3250,7 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) { ssa_lvalue_store(proc, lvals[0], init); } else { gbArray(ssaValue *) inits; - gb_array_init_reserve(inits, gb_heap_allocator(), gb_array_count(lvals)); - defer (gb_array_free(inits)); + gb_array_init_reserve(inits, m->tmp_allocator, gb_array_count(lvals)); gb_for_array(i, as->rhs) { ssaValue *init = ssa_build_expr(proc, as->rhs[i]); @@ -3241,8 +3263,7 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) { } } else { gbArray(ssaValue *) inits; - gb_array_init_reserve(inits, gb_heap_allocator(), gb_array_count(lvals)); - defer (gb_array_free(inits)); + gb_array_init_reserve(inits, m->tmp_allocator, gb_array_count(lvals)); gb_for_array(i, as->rhs) { ssaValue *init = ssa_build_expr(proc, as->rhs[i]); diff --git a/src/exact_value.cpp b/src/exact_value.cpp index 44e291af0..7e0292a09 100644 --- a/src/exact_value.cpp +++ b/src/exact_value.cpp @@ -190,7 +190,7 @@ ExactValue exact_unary_operator_value(Token op, ExactValue v, i32 precision) { } failure: - GB_PANIC("Invalid unary operation, %.*s", LIT(token_strings[op.kind])); + compiler_error("Invalid unary operation, %.*s", LIT(token_strings[op.kind])); ExactValue error_value = {}; return error_value; @@ -212,7 +212,7 @@ i32 exact_value_order(ExactValue v) { return 4; default: - GB_PANIC("How'd you get here? Invalid Value.kind"); + compiler_error("How'd you get here? Invalid Value.kind"); return -1; } } @@ -249,7 +249,7 @@ void match_exact_values(ExactValue *x, ExactValue *y) { break; } - GB_PANIC("How'd you get here? Invalid ExactValueKind"); + compiler_error("How'd you get here? Invalid ExactValueKind"); } // TODO(bill): Allow for pointer arithmetic? Or are pointer slices good enough? diff --git a/src/main.cpp b/src/main.cpp index cfbc6ba17..765c80b50 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -40,6 +40,7 @@ i32 win32_exec_command_line_app(char *fmt, ...) { } } + #if defined(DISPLAY_TIMING) #define INIT_TIMER() f64 start_time = gb_time_now(), end_time = 0, total_time = 0 #define PRINT_TIMER(section) do { \ @@ -82,7 +83,7 @@ int main(int argc, char **argv) { if (!init_parser(&parser)) return 1; - defer (destroy_parser(&parser)); + // defer (destroy_parser(&parser)); if (parse_files(&parser, init_filename) != ParseFile_None) return 1; @@ -99,7 +100,7 @@ int main(int argc, char **argv) { sizes.max_align = 16; init_checker(&checker, &parser, sizes); - defer (destroy_checker(&checker)); + // defer (destroy_checker(&checker)); check_parsed_files(&checker); @@ -110,7 +111,7 @@ int main(int argc, char **argv) { ssaGen ssa = {}; if (!ssa_gen_init(&ssa, &checker)) return 1; - defer (ssa_gen_destroy(&ssa)); + // defer (ssa_gen_destroy(&ssa)); ssa_gen_tree(&ssa); @@ -146,7 +147,7 @@ int main(int argc, char **argv) { #if 1 gbString lib_str = gb_string_make(gb_heap_allocator(), "-lKernel32.lib"); - defer (gb_string_free(lib_str)); + // defer (gb_string_free(lib_str)); char lib_str_buf[1024] = {}; gb_for_array(i, parser.system_libraries) { String lib = parser.system_libraries[i]; diff --git a/src/parser.cpp b/src/parser.cpp index 94f684af9..87cee80fa 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -63,14 +63,15 @@ enum ProcTag : u64 { ProcTag_no_bounds_check = GB_BIT(1), ProcTag_foreign = GB_BIT(10), - ProcTag_inline = GB_BIT(11), - ProcTag_no_inline = GB_BIT(12), - ProcTag_dll_import = GB_BIT(13), - ProcTag_dll_export = GB_BIT(14), + ProcTag_link_name = GB_BIT(11), + ProcTag_inline = GB_BIT(12), + ProcTag_no_inline = GB_BIT(13), + ProcTag_dll_import = GB_BIT(14), + ProcTag_dll_export = GB_BIT(15), - ProcTag_stdcall = GB_BIT(15), - ProcTag_fastcall = GB_BIT(16), - // ProcTag_cdecl = GB_BIT(17), + ProcTag_stdcall = GB_BIT(16), + ProcTag_fastcall = GB_BIT(17), + // ProcTag_cdecl = GB_BIT(18), }; enum VarDeclTag { @@ -237,6 +238,7 @@ AST_NODE_KIND(_DeclBegin, "", struct{}) \ AstNode *body; \ u64 tags; \ String foreign_name; \ + String link_name; \ }) \ AST_NODE_KIND(TypeDecl, "type declaration", struct { Token token; AstNode *name, *type; }) \ AST_NODE_KIND(ImportDecl, "import declaration", struct { \ @@ -806,13 +808,14 @@ gb_inline AstNode *make_proc_type(AstFile *f, Token token, AstNodeArray params, return result; } -gb_inline AstNode *make_proc_decl(AstFile *f, AstNode *name, AstNode *proc_type, AstNode *body, u64 tags, String foreign_name) { +gb_inline AstNode *make_proc_decl(AstFile *f, AstNode *name, AstNode *proc_type, AstNode *body, u64 tags, String foreign_name, String link_name) { AstNode *result = make_node(f, AstNode_ProcDecl); result->ProcDecl.name = name; result->ProcDecl.type = proc_type; result->ProcDecl.body = body; result->ProcDecl.tags = tags; result->ProcDecl.foreign_name = foreign_name; + result->ProcDecl.link_name = link_name; return result; } @@ -1165,10 +1168,10 @@ b32 is_foreign_name_valid(String name) { return true; } -void parse_proc_tags(AstFile *f, u64 *tags, String *foreign_name) { +void parse_proc_tags(AstFile *f, u64 *tags, String *foreign_name, String *link_name) { // TODO(bill): Add this to procedure literals too - - + GB_ASSERT(foreign_name != NULL); + GB_ASSERT(link_name != NULL); while (f->cursor[0].kind == Token_Hash) { AstNode *tag_expr = parse_tag_expr(f, NULL); @@ -1186,11 +1189,24 @@ void parse_proc_tags(AstFile *f, u64 *tags, String *foreign_name) { *foreign_name = f->cursor[0].string; // TODO(bill): Check if valid string if (!is_foreign_name_valid(*foreign_name)) { - syntax_error(ast_node_token(tag_expr), "Invalid alternative foreign procedure name"); + syntax_error(ast_node_token(tag_expr), "Invalid alternative foreign procedure name: `%.*s`", LIT(*foreign_name)); } next_token(f); } + } else if (are_strings_equal(tag_name, make_string("link_name"))) { + check_proc_add_tag(f, tag_expr, tags, ProcTag_link_name, tag_name); + if (f->cursor[0].kind == Token_String) { + *link_name = f->cursor[0].string; + // TODO(bill): Check if valid string + if (!is_foreign_name_valid(*link_name)) { + syntax_error(ast_node_token(tag_expr), "Invalid alternative link procedure name `%.*s`", LIT(*link_name)); + } + + next_token(f); + } else { + expect_token(f, Token_String); + } } ELSE_IF_ADD_TAG(bounds_check) ELSE_IF_ADD_TAG(no_bounds_check) @@ -1208,6 +1224,10 @@ void parse_proc_tags(AstFile *f, u64 *tags, String *foreign_name) { #undef ELSE_IF_ADD_TAG } + if ((*tags & ProcTag_foreign) && (*tags & ProcTag_link_name)) { + syntax_error(f->cursor[0], "You cannot apply both #foreign and #link_name to a procedure"); + } + if ((*tags & ProcTag_inline) && (*tags & ProcTag_no_inline)) { syntax_error(f->cursor[0], "You cannot apply both #inline and #no_inline to a procedure"); } @@ -1219,6 +1239,10 @@ void parse_proc_tags(AstFile *f, u64 *tags, String *foreign_name) { if (((*tags & ProcTag_bounds_check) || (*tags & ProcTag_no_bounds_check)) && (*tags & ProcTag_foreign)) { syntax_error(f->cursor[0], "You cannot apply both #bounds_check or #no_bounds_check to a procedure without a body"); } + + if ((*tags & ProcTag_stdcall) && (*tags & ProcTag_fastcall)) { + syntax_error(f->cursor[0], "You cannot apply one calling convention to a procedure"); + } } AstNode *parse_operand(AstFile *f, b32 lhs) { @@ -1292,10 +1316,14 @@ AstNode *parse_operand(AstFile *f, b32 lhs) { u64 tags = 0; String foreign_name = {}; - parse_proc_tags(f, &tags, &foreign_name); + String link_name = {}; + parse_proc_tags(f, &tags, &foreign_name, &link_name); if (tags & ProcTag_foreign) { syntax_error(f->cursor[0], "#foreign cannot be applied to procedure literals"); } + if (tags & ProcTag_link_name) { + syntax_error(f->cursor[0], "#link_name cannot be applied to procedure literals"); + } if (f->cursor[0].kind != Token_OpenBrace) { return type; @@ -2082,8 +2110,9 @@ AstNode *parse_proc_decl(AstFile *f, Token proc_token, AstNode *name) { AstNode *body = NULL; u64 tags = 0; String foreign_name = {}; + String link_name = {}; - parse_proc_tags(f, &tags, &foreign_name); + parse_proc_tags(f, &tags, &foreign_name, &link_name); AstNode *curr_proc = f->curr_proc; f->curr_proc = proc_type; @@ -2096,7 +2125,7 @@ AstNode *parse_proc_decl(AstFile *f, Token proc_token, AstNode *name) { body = parse_body(f); } - return make_proc_decl(f, name, proc_type, body, tags, foreign_name); + return make_proc_decl(f, name, proc_type, body, tags, foreign_name, link_name); } AstNode *parse_decl(AstFile *f, AstNodeArray names) { @@ -2794,7 +2823,7 @@ b32 try_add_foreign_system_library_path(Parser *p, String import_file) { } gb_global Rune illegal_import_runes[] = { - '"', '\'', '`', ' ', + '"', '\'', '`', ' ', '\t', '\r', '\n', '\v', '\f', '\\', // NOTE(bill): Disallow windows style filepaths '!', '$', '%', '^', '&', '*', '(', ')', '=', '+', '[', ']', '{', '}', @@ -2862,10 +2891,12 @@ void parse_file(Parser *p, AstFile *f) { if (!is_import_path_valid(file_str)) { if (id->is_load) { - syntax_error(ast_node_token(node), "Invalid #load path"); + syntax_error(ast_node_token(node), "Invalid #load path: `%.*s`", LIT(file_str)); } else { - syntax_error(ast_node_token(node), "Invalid #import path"); + syntax_error(ast_node_token(node), "Invalid #import path: `%.*s`", LIT(file_str)); } + // NOTE(bill): It's a naughty name + f->decls[i] = make_bad_decl(f, id->token, id->token); continue; } @@ -2888,6 +2919,8 @@ void parse_file(Parser *p, AstFile *f) { if (!is_import_path_valid(file_str)) { syntax_error(ast_node_token(node), "Invalid `foreign_system_library` path"); + // NOTE(bill): It's a naughty name + f->decls[i] = make_bad_decl(f, id->token, id->token); continue; }