From d714bece47ea058e482389452cd428dad9c28fd0 Mon Sep 17 00:00:00 2001 From: Ginger Bill Date: Thu, 22 Dec 2016 23:06:31 +0000 Subject: [PATCH] Handle calling conventions correctly --- code/demo.odin | 21 ++--- core/_preload.odin | 16 ++-- core/fmt.odin | 4 +- core/math.odin | 8 +- core/mem.odin | 8 +- core/opengl.odin | 100 +++++++++++----------- core/opengl_constants.odin | 4 +- core/os_windows.odin | 16 ++-- core/sync.odin | 8 +- core/sys/windows.odin | 46 +++++----- core/utf8.odin | 12 +-- src/checker/checker.c | 4 +- src/checker/decl.c | 2 +- src/checker/expr.c | 14 ++-- src/checker/types.c | 24 +++++- src/main.c | 2 +- src/parser.c | 167 +++++++++++++++++++++++++------------ src/ssa.c | 14 ++-- src/ssa_print.c | 23 +++-- 19 files changed, 290 insertions(+), 203 deletions(-) diff --git a/code/demo.odin b/code/demo.odin index f93c1575b..897a5a878 100644 --- a/code/demo.odin +++ b/code/demo.odin @@ -1,4 +1,4 @@ -import ( +import { "atomic.odin"; "fmt.odin"; "hash.odin"; @@ -8,17 +8,12 @@ import ( "os.odin"; "sync.odin"; "utf8.odin"; -) - -proc main() { - var x = proc() -> int { - proc print_here() { - fmt.println("Here"); - } - - print_here(); - return 1; - }; - fmt.println(x()); + win32 "sys/windows.odin"; +} + +proc main() { + var x = ~(0 as u32); + var y = x << 32; + fmt.println(y); } diff --git a/core/_preload.odin b/core/_preload.odin index 89803334c..eae72ede1 100644 --- a/core/_preload.odin +++ b/core/_preload.odin @@ -1,10 +1,10 @@ #shared_global_scope; -import ( +import { "os.odin"; "fmt.odin"; "mem.odin"; -) +} // IMPORTANT NOTE(bill): `type_info` & `type_info_val` cannot be used within a // #shared_global_scope due to the internals of the compiler. @@ -14,7 +14,7 @@ import ( // IMPORTANT NOTE(bill): Do not change the order of any of this data // The compiler relies upon this _exact_ order -type ( +type { Type_Info_Member struct #ordered { name string; // can be empty if tuple type_info ^Type_Info; @@ -74,7 +74,7 @@ type ( Union Type_Info_Record; Raw_Union Type_Info_Record; } -) +} proc type_info_base(info ^Type_Info) -> ^Type_Info { if info == nil { @@ -113,13 +113,13 @@ proc fmuladd64(a, b, c f64) -> f64 #foreign "llvm.fmuladd.f64" type Allocator_Mode u8; -const ( +const { ALLOCATOR_ALLOC Allocator_Mode = iota; ALLOCATOR_FREE; ALLOCATOR_FREE_ALL; ALLOCATOR_RESIZE; -); -type ( +} +type { Allocator_Proc proc(allocator_data rawptr, mode Allocator_Mode, size, alignment int, old_memory rawptr, old_size int, flags u64) -> rawptr; @@ -136,7 +136,7 @@ type ( user_data rawptr; user_index int; } -); +} #thread_local var __context Context; diff --git a/core/fmt.odin b/core/fmt.odin index 5119a7195..5bcc7344a 100644 --- a/core/fmt.odin +++ b/core/fmt.odin @@ -1,8 +1,8 @@ -import ( +import { "os.odin"; "mem.odin"; "utf8.odin"; -) +} const PRINT_BUF_SIZE = 1<<12; diff --git a/core/math.odin b/core/math.odin index 288af0d31..0c2081a5f 100644 --- a/core/math.odin +++ b/core/math.odin @@ -1,4 +1,4 @@ -const ( +const { TAU = 6.28318530717958647692528676655900576; PI = 3.14159265358979323846264338327950288; ONE_OVER_TAU = 0.636619772367581343075535053490057448; @@ -16,9 +16,9 @@ const ( τ = TAU; π = PI; -) +} -type ( +type { Vec2 [vector 2]f32; Vec3 [vector 3]f32; Vec4 [vector 4]f32; @@ -26,7 +26,7 @@ type ( Mat2 [2]Vec2; Mat3 [3]Vec3; Mat4 [4]Vec4; -) +} proc sqrt32(x f32) -> f32 #foreign "llvm.sqrt.f32" proc sqrt64(x f64) -> f64 #foreign "llvm.sqrt.f64" diff --git a/core/mem.odin b/core/mem.odin index 2b5963c76..f504df84e 100644 --- a/core/mem.odin +++ b/core/mem.odin @@ -1,7 +1,7 @@ -import ( +import { "fmt.odin"; "os.odin"; -) +} proc set(data rawptr, value i32, len int) -> rawptr #link_name "__mem_set" { proc llvm_memset_64bit(dst rawptr, val byte, len int, align i32, is_volatile bool) #foreign "llvm.memset.p0i8.i64" @@ -116,7 +116,7 @@ proc allocation_header(data rawptr) -> ^Allocation_Header { // Custom allocators -type ( +type { Arena struct { backing Allocator; memory []byte; @@ -127,7 +127,7 @@ type ( arena ^Arena; original_count int; } -) +} diff --git a/core/opengl.odin b/core/opengl.odin index b5dbd46a3..9947cdf97 100644 --- a/core/opengl.odin +++ b/core/opengl.odin @@ -32,7 +32,7 @@ proc GetIntegerv(name i32, v ^i32) #foreign "glGetIntegerv" var _libgl = win32.LoadLibraryA(("opengl32.dll\x00" as string).data); -proc GetProcAddress(name string) -> proc() { +proc GetProcAddress(name string) -> proc() #cc_c { assert(name[name.count-1] == 0); var res = win32.wglGetProcAddress(name.data); if res == nil { @@ -41,68 +41,68 @@ proc GetProcAddress(name string) -> proc() { return res; } -var ( - GenBuffers proc(count i32, buffers ^u32); - GenVertexArrays proc(count i32, buffers ^u32); - GenSamplers proc(count i32, buffers ^u32); - BindBuffer proc(target i32, buffer u32); - BindVertexArray proc(buffer u32); - BindSampler proc(position i32, sampler u32); - BufferData proc(target i32, size int, data rawptr, usage i32); - BufferSubData proc(target i32, offset, size int, data rawptr); +var { + GenBuffers proc(count i32, buffers ^u32) #cc_c; + GenVertexArrays proc(count i32, buffers ^u32) #cc_c; + GenSamplers proc(count i32, buffers ^u32) #cc_c; + BindBuffer proc(target i32, buffer u32) #cc_c; + BindVertexArray proc(buffer u32) #cc_c; + BindSampler proc(position i32, sampler u32) #cc_c; + BufferData proc(target i32, size int, data rawptr, usage i32) #cc_c; + BufferSubData proc(target i32, offset, size int, data rawptr) #cc_c; - DrawArrays proc(mode, first i32, count u32); - DrawElements proc(mode i32, count u32, type_ i32, indices rawptr); + DrawArrays proc(mode, first i32, count u32) #cc_c; + DrawElements proc(mode i32, count u32, type_ i32, indices rawptr) #cc_c; - MapBuffer proc(target, access i32) -> rawptr; - UnmapBuffer proc(target i32); + MapBuffer proc(target, access i32) -> rawptr #cc_c; + UnmapBuffer proc(target i32) #cc_c; - VertexAttribPointer proc(index u32, size, type_ i32, normalized i32, stride u32, pointer rawptr); - EnableVertexAttribArray proc(index u32); + VertexAttribPointer proc(index u32, size, type_ i32, normalized i32, stride u32, pointer rawptr) #cc_c; + EnableVertexAttribArray proc(index u32) #cc_c; - CreateShader proc(shader_type i32) -> u32; - ShaderSource proc(shader u32, count u32, str ^^byte, length ^i32); - CompileShader proc(shader u32); - CreateProgram proc() -> u32; - AttachShader proc(program, shader u32); - DetachShader proc(program, shader u32); - DeleteShader proc(shader u32); - LinkProgram proc(program u32); - UseProgram proc(program u32); - DeleteProgram proc(program u32); + CreateShader proc(shader_type i32) -> u32 #cc_c; + ShaderSource proc(shader u32, count u32, str ^^byte, length ^i32) #cc_c; + CompileShader proc(shader u32) #cc_c; + CreateProgram proc() -> u32 #cc_c; + AttachShader proc(program, shader u32) #cc_c; + DetachShader proc(program, shader u32) #cc_c; + DeleteShader proc(shader u32) #cc_c; + LinkProgram proc(program u32) #cc_c; + UseProgram proc(program u32) #cc_c; + DeleteProgram proc(program u32) #cc_c; - GetShaderiv proc(shader u32, pname i32, params ^i32); - GetProgramiv proc(program u32, pname i32, params ^i32); - GetShaderInfoLog proc(shader u32, max_length u32, length ^u32, info_long ^byte); - GetProgramInfoLog proc(program u32, max_length u32, length ^u32, info_long ^byte); + GetShaderiv proc(shader u32, pname i32, params ^i32) #cc_c; + GetProgramiv proc(program u32, pname i32, params ^i32) #cc_c; + GetShaderInfoLog proc(shader u32, max_length u32, length ^u32, info_long ^byte) #cc_c; + GetProgramInfoLog proc(program u32, max_length u32, length ^u32, info_long ^byte) #cc_c; - ActiveTexture proc(texture i32); - GenerateMipmap proc(target i32); + ActiveTexture proc(texture i32) #cc_c; + GenerateMipmap proc(target i32) #cc_c; - SamplerParameteri proc(sampler u32, pname i32, param i32); - SamplerParameterf proc(sampler u32, pname i32, param f32); - SamplerParameteriv proc(sampler u32, pname i32, params ^i32); - SamplerParameterfv proc(sampler u32, pname i32, params ^f32); - SamplerParameterIiv proc(sampler u32, pname i32, params ^i32); - SamplerParameterIuiv proc(sampler u32, pname i32, params ^u32); + SamplerParameteri proc(sampler u32, pname i32, param i32) #cc_c; + SamplerParameterf proc(sampler u32, pname i32, param f32) #cc_c; + SamplerParameteriv proc(sampler u32, pname i32, params ^i32) #cc_c; + SamplerParameterfv proc(sampler u32, pname i32, params ^f32) #cc_c; + SamplerParameterIiv proc(sampler u32, pname i32, params ^i32) #cc_c; + SamplerParameterIuiv proc(sampler u32, pname i32, params ^u32) #cc_c; - Uniform1i proc(loc i32, v0 i32); - Uniform2i proc(loc i32, v0, v1 i32); - Uniform3i proc(loc i32, v0, v1, v2 i32); - Uniform4i proc(loc i32, v0, v1, v2, v3 i32); - Uniform1f proc(loc i32, v0 f32); - Uniform2f proc(loc i32, v0, v1 f32); - Uniform3f proc(loc i32, v0, v1, v2 f32); - Uniform4f proc(loc i32, v0, v1, v2, v3 f32); - UniformMatrix4fv proc(loc i32, count u32, transpose i32, value ^f32); + Uniform1i proc(loc i32, v0 i32) #cc_c; + Uniform2i proc(loc i32, v0, v1 i32) #cc_c; + Uniform3i proc(loc i32, v0, v1, v2 i32) #cc_c; + Uniform4i proc(loc i32, v0, v1, v2, v3 i32) #cc_c; + Uniform1f proc(loc i32, v0 f32) #cc_c; + Uniform2f proc(loc i32, v0, v1 f32) #cc_c; + Uniform3f proc(loc i32, v0, v1, v2 f32) #cc_c; + Uniform4f proc(loc i32, v0, v1, v2, v3 f32) #cc_c; + UniformMatrix4fv proc(loc i32, count u32, transpose i32, value ^f32) #cc_c; - GetUniformLocation proc(program u32, name ^byte) -> i32; -); + GetUniformLocation proc(program u32, name ^byte) -> i32 #cc_c; +} proc init() { - proc set_proc_address(p rawptr, name string) #inline { (p as ^proc())^ = GetProcAddress(name); } + proc set_proc_address(p rawptr, name string) #inline { (p as ^(proc() #cc_c))^ = GetProcAddress(name); } set_proc_address(^GenBuffers, "glGenBuffers\x00"); set_proc_address(^GenVertexArrays, "glGenVertexArrays\x00"); diff --git a/core/opengl_constants.odin b/core/opengl_constants.odin index 8c9a02f68..4f3037037 100644 --- a/core/opengl_constants.odin +++ b/core/opengl_constants.odin @@ -1,4 +1,4 @@ -const ( +const { FALSE = 0; TRUE = 1; @@ -1382,4 +1382,4 @@ const ( DEBUG_SEVERITY_HIGH_ARB = 0x9146; DEBUG_SEVERITY_MEDIUM_ARB = 0x9147; DEBUG_SEVERITY_LOW_ARB = 0x9148; -); +} diff --git a/core/os_windows.odin b/core/os_windows.odin index 777273e8f..b0c0d3e9d 100644 --- a/core/os_windows.odin +++ b/core/os_windows.odin @@ -1,9 +1,9 @@ -import ( +import { win32 "sys/windows.odin"; "fmt.odin"; -) +} -type ( +type { File_Time u64; File_Handle raw_union { @@ -15,7 +15,7 @@ type ( handle File_Handle; last_write_time File_Time; } -) +} proc open(name string) -> (File, bool) { using win32; @@ -87,15 +87,15 @@ proc last_write_time_by_name(name string) -> File_Time { -const ( +const { FILE_STANDARD_INPUT = iota; FILE_STANDARD_OUTPUT; FILE_STANDARD_ERROR; FILE_STANDARD_COUNT; -) +} // NOTE(bill): Uses startup to initialize it -var ( +var { __std_files = [FILE_STANDARD_COUNT]File{ {handle = win32.GetStdHandle(win32.STD_INPUT_HANDLE) transmute File_Handle }, {handle = win32.GetStdHandle(win32.STD_OUTPUT_HANDLE) transmute File_Handle }, @@ -105,7 +105,7 @@ var ( stdin = ^__std_files[FILE_STANDARD_INPUT]; stdout = ^__std_files[FILE_STANDARD_OUTPUT]; stderr = ^__std_files[FILE_STANDARD_ERROR]; -) +} proc read_entire_file(name string) -> ([]byte, bool) { diff --git a/core/sync.odin b/core/sync.odin index 3d484af41..79aeacfc8 100644 --- a/core/sync.odin +++ b/core/sync.odin @@ -1,9 +1,9 @@ -import ( +import { win32 "sys/windows.odin" when ODIN_OS == "windows"; "atomic.odin"; -) +} -type ( +type { Semaphore struct { handle win32.HANDLE; } @@ -14,7 +14,7 @@ type ( owner i32; recursion i32; } -) +} proc current_thread_id() -> i32 { return win32.GetCurrentThreadId() as i32; diff --git a/core/sys/windows.odin b/core/sys/windows.odin index d70c11be1..90f8bd424 100644 --- a/core/sys/windows.odin +++ b/core/sys/windows.odin @@ -1,7 +1,7 @@ #foreign_system_library "user32" when ODIN_OS == "windows"; #foreign_system_library "gdi32" when ODIN_OS == "windows"; -type ( +type { HANDLE rawptr; HWND HANDLE; HDC HANDLE; @@ -18,9 +18,9 @@ type ( ATOM i16; BOOL i32; WNDPROC proc(hwnd HWND, msg u32, wparam WPARAM, lparam LPARAM) -> LRESULT; -) +} -const ( +const { INVALID_HANDLE_VALUE = (-1 as int) as HANDLE; CS_VREDRAW = 0x0001; @@ -52,9 +52,9 @@ const ( SM_CYSCREEN = 1; SW_SHOW = 5; -) +} -type ( +type { POINT struct #ordered { x, y i32; } @@ -114,11 +114,11 @@ type ( } GET_FILEEX_INFO_LEVELS i32; -) -const ( +} +const { GetFileExInfoStandard = 0 as GET_FILEEX_INFO_LEVELS; GetFileExMaxInfoLevel = 1 as GET_FILEEX_INFO_LEVELS; -) +} proc GetLastError () -> i32 #foreign #dll_import proc ExitProcess (exit_code u32) #foreign #dll_import @@ -183,7 +183,7 @@ proc GetFileSizeEx (file_handle HANDLE, file_size ^i64) -> BOOL #for proc GetFileAttributesExA (filename ^u8, info_level_id GET_FILEEX_INFO_LEVELS, file_info rawptr) -> BOOL #foreign #dll_import proc GetFileInformationByHandle(file_handle HANDLE, file_info ^BY_HANDLE_FILE_INFORMATION) -> BOOL #foreign #dll_import -const ( +const { FILE_SHARE_READ = 0x00000001; FILE_SHARE_WRITE = 0x00000002; FILE_SHARE_DELETE = 0x00000004; @@ -201,7 +201,7 @@ const ( OPEN_EXISTING = 3; OPEN_ALWAYS = 4; TRUNCATE_EXISTING = 5; -) +} @@ -248,7 +248,7 @@ proc ReadBarrier () #foreign // GDI -type ( +type { BITMAPINFOHEADER struct #ordered { size u32; width, height i32; @@ -269,13 +269,13 @@ type ( RGBQUAD struct #ordered { blue, green, red, reserved byte; } -) +} -const ( +const { BI_RGB = 0; DIB_RGB_COLORS = 0x00; SRCCOPY = 0x00cc0020 as u32; -) +} proc StretchDIBits(hdc HDC, x_dst, y_dst, width_dst, height_dst i32, @@ -295,7 +295,7 @@ proc GetClientRect(hwnd HWND, rect ^RECT) -> BOOL #foreign // Windows OpenGL -const ( +const { PFD_TYPE_RGBA = 0; PFD_TYPE_COLORINDEX = 1; PFD_MAIN_PLANE = 0; @@ -317,11 +317,11 @@ const ( PFD_DEPTH_DONTCARE = 0x20000000; PFD_DOUBLEBUFFER_DONTCARE = 0x40000000; PFD_STEREO_DONTCARE = 0x80000000; -) +} -type ( +type { HGLRC HANDLE; - PROC proc(); + PROC proc() #cc_c; wglCreateContextAttribsARBType proc(hdc HDC, hshareContext rawptr, attribList ^i32) -> HGLRC; @@ -355,7 +355,7 @@ type ( visible_mask, damage_mask u32; } -) +} proc GetDC (h HANDLE) -> HDC #foreign proc SetPixelFormat (hdc HDC, pixel_format i32, pfd ^PIXELFORMATDESCRIPTOR ) -> BOOL #foreign #dll_import @@ -363,13 +363,13 @@ proc ChoosePixelFormat(hdc HDC, pfd ^PIXELFORMATDESCRIPTOR) -> i32 #foreign #dll proc SwapBuffers (hdc HDC) -> BOOL #foreign #dll_import proc ReleaseDC (wnd HWND, hdc HDC) -> i32 #foreign #dll_import -const ( +const { WGL_CONTEXT_MAJOR_VERSION_ARB = 0x2091; WGL_CONTEXT_MINOR_VERSION_ARB = 0x2092; WGL_CONTEXT_PROFILE_MASK_ARB = 0x9126; WGL_CONTEXT_CORE_PROFILE_BIT_ARB = 0x0001; WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB = 0x0002; -) +} proc wglCreateContext (hdc HDC) -> HGLRC #foreign #dll_import proc wglMakeCurrent (hdc HDC, hglrc HGLRC) -> BOOL #foreign #dll_import @@ -383,7 +383,7 @@ proc GetAsyncKeyState(v_key i32) -> i16 #foreign #dll_import proc is_key_down(key i32) -> bool #inline { return GetAsyncKeyState(key) < 0; } -const ( +const { KEY_LBUTTON = 0x01; KEY_RBUTTON = 0x02; KEY_CANCEL = 0x03; @@ -535,5 +535,5 @@ const ( KEY_NONAME = 0xFC; KEY_PA1 = 0xFD; KEY_OEM_CLEAR = 0xFE; -) +} diff --git a/core/utf8.odin b/core/utf8.odin index 42913eba5..4b2dd9ac7 100644 --- a/core/utf8.odin +++ b/core/utf8.odin @@ -1,4 +1,4 @@ -const ( +const { RUNE_ERROR = '\ufffd'; RUNE_SELF = 0x80; RUNE_BOM = 0xfeff; @@ -8,13 +8,13 @@ const ( SURROGATE_MIN = 0xd800; SURROGATE_MAX = 0xdfff; -) +} type Accept_Range struct { lo, hi u8; } -var ( +var { accept_ranges = [5]Accept_Range{ {0x80, 0xbf}, {0xa0, 0xbf}, @@ -42,7 +42,7 @@ var ( 0x13, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x23, 0x03, 0x03, // 0xe0-0xef 0x34, 0x04, 0x04, 0x04, 0x44, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, // 0xf0-0xff }; -) +} proc encode_rune(r rune) -> ([4]byte, int) { var buf [4]byte; @@ -99,12 +99,12 @@ proc decode_rune(s string) -> (rune, int) { return RUNE_ERROR, 1; } - const ( + const { MASK_X = 0b00111111; MASK_2 = 0b00011111; MASK_3 = 0b00001111; MASK_4 = 0b00000111; - ) + } if size == 2 { return (b0&MASK_2) as rune <<6 | (b1&MASK_X) as rune, 2; diff --git a/src/checker/checker.c b/src/checker/checker.c index 8fc40b83d..2159eb95b 100644 --- a/src/checker/checker.c +++ b/src/checker/checker.c @@ -1142,8 +1142,8 @@ void check_global_collect_entities_from_file(Checker *c, Scope *parent_scope, As for_array(iota, gd->specs) { AstNode *spec = gd->specs.e[iota]; switch (spec->kind) { - case_ast_node(bd, BadDecl, decl); - case_end; + case AstNode_BadDecl: + break; case_ast_node(is, ImportSpec, spec); if (!parent_scope->is_file) { // NOTE(bill): _Should_ be caught by the parser diff --git a/src/checker/decl.c b/src/checker/decl.c index be735f3d4..cc2c48f78 100644 --- a/src/checker/decl.c +++ b/src/checker/decl.c @@ -308,7 +308,7 @@ bool are_signatures_similar_enough(Type *a_, Type *b_) { 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); + Type *proc_type = make_type_proc(c->allocator, e->scope, NULL, 0, NULL, 0, false, ProcCC_Odin); e->type = proc_type; ast_node(pd, ProcDecl, d->proc_decl); diff --git a/src/checker/expr.c b/src/checker/expr.c index 79a8e8623..299dd55c9 100644 --- a/src/checker/expr.c +++ b/src/checker/expr.c @@ -821,13 +821,13 @@ void check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node) { if (params) param_count = params ->Tuple.variable_count; if (results) result_count = results->Tuple.variable_count; - type->Proc.scope = c->context.scope; - type->Proc.params = params; - type->Proc.param_count = param_count; - type->Proc.results = results; - type->Proc.result_count = result_count; - type->Proc.variadic = variadic; - // type->Proc.implicit_context = implicit_context; + type->Proc.scope = c->context.scope; + type->Proc.params = params; + type->Proc.param_count = param_count; + type->Proc.results = results; + type->Proc.result_count = result_count; + type->Proc.variadic = variadic; + type->Proc.calling_convention = pt->calling_convention; } diff --git a/src/checker/types.c b/src/checker/types.c index c3f3d2383..c3fff7e01 100644 --- a/src/checker/types.c +++ b/src/checker/types.c @@ -110,6 +110,7 @@ typedef struct TypeRecord { i32 param_count; \ i32 result_count; \ bool variadic; \ + ProcCallingConvention calling_convention; \ }) typedef enum TypeKind { @@ -382,7 +383,7 @@ Type *make_type_tuple(gbAllocator a) { return t; } -Type *make_type_proc(gbAllocator a, Scope *scope, Type *params, isize param_count, Type *results, isize result_count, bool variadic) { +Type *make_type_proc(gbAllocator a, Scope *scope, Type *params, isize param_count, Type *results, isize result_count, bool variadic, ProcCallingConvention calling_convention) { Type *t = alloc_type(a, Type_Proc); if (variadic) { @@ -403,6 +404,7 @@ Type *make_type_proc(gbAllocator a, Scope *scope, Type *params, isize param_coun t->Proc.results = results; t->Proc.result_count = result_count; t->Proc.variadic = variadic; + t->Proc.calling_convention = calling_convention; return t; } @@ -655,8 +657,9 @@ bool is_type_comparable(Type *t) { } bool are_types_identical(Type *x, Type *y) { - if (x == y) + if (x == y) { return true; + } if ((x == NULL && y != NULL) || (x != NULL && y == NULL)) { @@ -747,7 +750,8 @@ bool are_types_identical(Type *x, Type *y) { case Type_Proc: if (y->kind == Type_Proc) { - return are_types_identical(x->Proc.params, y->Proc.params) && + return x->Proc.calling_convention == y->Proc.calling_convention && + are_types_identical(x->Proc.params, y->Proc.params) && are_types_identical(x->Proc.results, y->Proc.results); } break; @@ -1547,6 +1551,20 @@ gbString write_type_to_string(gbString str, Type *type) { str = gb_string_appendc(str, " -> "); str = write_type_to_string(str, type->Proc.results); } + switch (type->Proc.calling_convention) { + case ProcCC_Odin: + // str = gb_string_appendc(str, " #cc_odin"); + break; + case ProcCC_C: + str = gb_string_appendc(str, " #cc_c"); + break; + case ProcCC_Std: + str = gb_string_appendc(str, " #cc_std"); + break; + case ProcCC_Fast: + str = gb_string_appendc(str, " #cc_fast"); + break; + } break; } diff --git a/src/main.c b/src/main.c index 1ca921ebe..d1571cbd4 100644 --- a/src/main.c +++ b/src/main.c @@ -242,7 +242,7 @@ int main(int argc, char **argv) { exit_code = win32_exec_command_line_app("msvc-link", true, "link %.*s.obj -OUT:%.*s.%s %s " "/defaultlib:libcmt " - "/nologo /incremental:no /opt:ref /subsystem:CONSOLE " + "/nologo /incremental:no /opt:ref /subsystem:WINDOWS " " %.*s " " %s " "", diff --git a/src/parser.c b/src/parser.c index 5ccc0df8a..b620e911b 100644 --- a/src/parser.c +++ b/src/parser.c @@ -72,12 +72,17 @@ typedef enum ProcTag { ProcTag_no_inline = GB_BIT(14), ProcTag_dll_import = GB_BIT(15), // ProcTag_dll_export = GB_BIT(16), - - ProcTag_stdcall = GB_BIT(20), - ProcTag_fastcall = GB_BIT(21), - // ProcTag_cdecl = GB_BIT(22), } ProcTag; +typedef enum ProcCallingConvention { + ProcCC_Odin = 0, + ProcCC_C, + ProcCC_Std, + ProcCC_Fast, + + ProcCC_Invalid, +} ProcCallingConvention; + typedef enum VarDeclTag { VarDeclTag_thread_local = GB_BIT(0), } VarDeclTag; @@ -286,6 +291,7 @@ AST_NODE_KIND(_TypeBegin, "", i32) \ AstNodeArray params; \ AstNodeArray results; \ u64 tags; \ + ProcCallingConvention calling_convention; \ }) \ AST_NODE_KIND(PointerType, "pointer type", struct { \ Token token; \ @@ -911,12 +917,13 @@ AstNode *make_field(AstFile *f, AstNodeArray names, AstNode *type, bool is_using return result; } -AstNode *make_proc_type(AstFile *f, Token token, AstNodeArray params, AstNodeArray results, u64 tags) { +AstNode *make_proc_type(AstFile *f, Token token, AstNodeArray params, AstNodeArray results, u64 tags, ProcCallingConvention calling_convention) { AstNode *result = make_node(f, AstNode_ProcType); result->ProcType.token = token; result->ProcType.params = params; result->ProcType.results = results; result->ProcType.tags = tags; + result->ProcType.calling_convention = calling_convention; return result; } @@ -1157,6 +1164,8 @@ void fix_advance_to_next_stmt(AstFile *f) { case Token_const: case Token_type: case Token_proc: + case Token_import: + case Token_include: case Token_if: case Token_when: @@ -1220,7 +1229,7 @@ void expect_semicolon(AstFile *f, AstNode *s) { case AstNode_ProcDecl: return; case AstNode_GenericDecl: - if (s->GenericDecl.close.kind == Token_CloseParen) { + if (s->GenericDecl.close.kind == Token_CloseBrace) { return; } else if (s->GenericDecl.token.kind == Token_type) { if (f->prev_token.kind == Token_CloseBrace) { @@ -1246,10 +1255,15 @@ void expect_semicolon(AstFile *f, AstNode *s) { AstNode * parse_expr(AstFile *f, bool lhs); -AstNode * parse_proc_type(AstFile *f); +AstNode * parse_proc_type(AstFile *f, String *foreign_name_, String *link_name_); AstNodeArray parse_stmt_list(AstFile *f); AstNode * parse_stmt(AstFile *f); AstNode * parse_body(AstFile *f); +AstNode * parse_proc_decl(AstFile *f); +void parse_proc_signature(AstFile *f, AstNodeArray *params, AstNodeArray *results); + + + AstNode *parse_identifier(AstFile *f) { Token token = f->curr_token; @@ -1270,8 +1284,12 @@ AstNode *parse_tag_expr(AstFile *f, AstNode *expression) { AstNode *unparen_expr(AstNode *node) { for (;;) { - if (node->kind != AstNode_ParenExpr) + if (node == NULL) { + return NULL; + } + if (node->kind != AstNode_ParenExpr) { return node; + } node = node->ParenExpr.expr; } } @@ -1380,10 +1398,13 @@ bool is_foreign_name_valid(String name) { return true; } -void parse_proc_tags(AstFile *f, u64 *tags, String *foreign_name, String *link_name) { +void parse_proc_tags(AstFile *f, u64 *tags, String *foreign_name, String *link_name, ProcCallingConvention *calling_convention) { // TODO(bill): Add this to procedure literals too - GB_ASSERT(foreign_name != NULL); + GB_ASSERT(tags != NULL); GB_ASSERT(link_name != NULL); + GB_ASSERT(link_name != NULL); + + ProcCallingConvention cc = ProcCC_Invalid; while (f->curr_token.kind == Token_Hash) { AstNode *tag_expr = parse_tag_expr(f, NULL); @@ -1427,16 +1448,49 @@ void parse_proc_tags(AstFile *f, u64 *tags, String *foreign_name, String *link_n ELSE_IF_ADD_TAG(no_inline) ELSE_IF_ADD_TAG(dll_import) // ELSE_IF_ADD_TAG(dll_export) - ELSE_IF_ADD_TAG(stdcall) - ELSE_IF_ADD_TAG(fastcall) - // ELSE_IF_ADD_TAG(cdecl) - else { + else if (str_eq(tag_name, str_lit("cc_odin"))) { + if (cc == ProcCC_Invalid) { + cc = ProcCC_Odin; + } else { + syntax_error_node(tag_expr, "Multiple calling conventions for procedure type"); + } + } else if (str_eq(tag_name, str_lit("cc_c"))) { + if (cc == ProcCC_Invalid) { + cc = ProcCC_C; + } else { + syntax_error_node(tag_expr, "Multiple calling conventions for procedure type"); + } + } else if (str_eq(tag_name, str_lit("cc_std"))) { + if (cc == ProcCC_Invalid) { + cc = ProcCC_Std; + } else { + syntax_error_node(tag_expr, "Multiple calling conventions for procedure type"); + } + } else if (str_eq(tag_name, str_lit("cc_fast"))) { + if (cc == ProcCC_Invalid) { + cc = ProcCC_Fast; + } else { + syntax_error_node(tag_expr, "Multiple calling conventions for procedure type"); + } + } else { syntax_error_node(tag_expr, "Unknown procedure tag"); } #undef ELSE_IF_ADD_TAG } + if (cc == ProcCC_Invalid) { + if ((*tags) & ProcTag_foreign) { + cc = ProcCC_C; + } else { + cc = ProcCC_Odin; + } + } + + if (calling_convention) { + *calling_convention = cc; + } + if ((*tags & ProcTag_foreign) && (*tags & ProcTag_export)) { syntax_error(f->curr_token, "You cannot apply both #foreign and #export to a procedure"); } @@ -1452,10 +1506,6 @@ void parse_proc_tags(AstFile *f, u64 *tags, String *foreign_name, String *link_n if (((*tags & ProcTag_bounds_check) || (*tags & ProcTag_no_bounds_check)) && (*tags & ProcTag_foreign)) { syntax_error(f->curr_token, "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->curr_token, "You cannot apply one calling convention to a procedure"); - } } AstNode *parse_operand(AstFile *f, bool lhs) { @@ -1545,32 +1595,28 @@ AstNode *parse_operand(AstFile *f, bool lhs) { // Parse Procedure Type or Literal case Token_proc: { - AstNode *curr_proc = f->curr_proc; - AstNode *type = parse_proc_type(f); - f->curr_proc = type; - - u64 tags = 0; String foreign_name = {0}; String link_name = {0}; - parse_proc_tags(f, &tags, &foreign_name, &link_name); - if (tags & ProcTag_foreign) { + AstNode *curr_proc = f->curr_proc; + AstNode *type = parse_proc_type(f, &foreign_name, &link_name); + f->curr_proc = type; + + if (type->ProcType.tags & ProcTag_foreign) { syntax_error(f->curr_token, "#foreign cannot be applied to procedure literals"); } - if (tags & ProcTag_export) { + if (type->ProcType.tags & ProcTag_export) { syntax_error(f->curr_token, "#export cannot be applied to procedure literals"); } if (f->curr_token.kind == Token_OpenBrace) { AstNode *body; - if ((tags & ProcTag_foreign) != 0) { + if ((type->ProcType.tags & ProcTag_foreign) != 0) { syntax_error(f->curr_token, "A procedure tagged as `#foreign` cannot have a body"); } body = parse_body(f); - type = make_proc_lit(f, type, body, tags, foreign_name, link_name); - } else if (type != NULL && type->kind == AstNode_ProcType) { - type->ProcType.tags = tags; + type = make_proc_lit(f, type, body, type->ProcType.tags, foreign_name, link_name); } f->curr_proc = curr_proc; @@ -1920,13 +1966,13 @@ AstNode *parse_generic_decl(AstFile *f, TokenKind keyword, ParserSpecProc spec_p Token token = expect_token(f, keyword); Token open = {0}, close = {0}; AstNodeArray specs = {0}; - if (f->curr_token.kind == Token_OpenParen) { - open = expect_token(f, Token_OpenParen); + if (f->curr_token.kind == Token_OpenBrace) { + open = expect_token(f, Token_OpenBrace); array_init(&specs, heap_allocator()); for (isize index = 0; - f->curr_token.kind != Token_CloseParen && + f->curr_token.kind != Token_CloseBrace && f->curr_token.kind != Token_EOF; index++) { AstNode *spec = spec_proc(f, keyword, index); @@ -1934,7 +1980,7 @@ AstNode *parse_generic_decl(AstFile *f, TokenKind keyword, ParserSpecProc spec_p expect_semicolon(f, spec); } - close = expect_token(f, Token_CloseParen); + close = expect_token(f, Token_CloseBrace); } else { array_init_reserve(&specs, heap_allocator(), 1); array_add(&specs, spec_proc(f, keyword, 0)); @@ -2042,8 +2088,6 @@ PARSE_SPEC_PROC(parse_include_spec) { return spec; } -AstNode *parse_proc_decl(AstFile *f); - AstNode *parse_decl(AstFile *f) { switch (f->curr_token.kind) { case Token_var: @@ -2055,6 +2099,7 @@ AstNode *parse_decl(AstFile *f) { return parse_generic_decl(f, f->curr_token.kind, parse_type_spec); case Token_proc: + // TODO(bill): Should I allow procedures to use the generic declaration syntax? return parse_proc_decl(f); case Token_import: @@ -2158,20 +2203,29 @@ AstNode *convert_stmt_to_expr(AstFile *f, AstNode *statement, String kind) { -void parse_proc_signature(AstFile *f, AstNodeArray *params, AstNodeArray *results); -AstNode *parse_proc_type(AstFile *f) { +AstNode *parse_proc_type(AstFile *f, String *foreign_name_, String *link_name_) { AstNodeArray params = {0}; AstNodeArray results = {0}; Token proc_token = expect_token(f, Token_proc); parse_proc_signature(f, ¶ms, &results); - return make_proc_type(f, proc_token, params, results, 0); + u64 tags = 0; + String foreign_name = {0}; + String link_name = {0}; + ProcCallingConvention cc = ProcCC_Odin; + + parse_proc_tags(f, &tags, &foreign_name, &link_name, &cc); + + if (foreign_name_) *foreign_name_ = foreign_name; + if (link_name_) *link_name_ = link_name; + + return make_proc_type(f, proc_token, params, results, tags, cc); } - -AstNodeArray parse_field_list(AstFile *f, isize *name_count_, bool allow_using, TokenKind separator, TokenKind follow) { +AstNodeArray parse_field_list(AstFile *f, isize *name_count_, bool allow_using, bool ellipsis_ok, + TokenKind separator, TokenKind follow) { AstNodeArray params = make_ast_node_array(f); isize name_count = 0; @@ -2203,7 +2257,7 @@ AstNodeArray parse_field_list(AstFile *f, isize *name_count_, bool allow_using, // expect_token_after(f, Token_Colon, "parameter list"); AstNode *type = NULL; - if (f->curr_token.kind == Token_Ellipsis) { + if (ellipsis_ok && f->curr_token.kind == Token_Ellipsis) { Token ellipsis = f->curr_token; next_token(f); type = parse_type_attempt(f); @@ -2245,7 +2299,7 @@ AstNodeArray parse_field_list(AstFile *f, isize *name_count_, bool allow_using, AstNodeArray parse_record_fields(AstFile *f, isize *field_count_, bool allow_using, String context) { - return parse_field_list(f, field_count_, allow_using, Token_Semicolon, Token_CloseBrace); + return parse_field_list(f, field_count_, allow_using, false, Token_Semicolon, Token_CloseBrace); } AstNode *parse_identifier_or_type(AstFile *f) { @@ -2358,8 +2412,14 @@ AstNode *parse_identifier_or_type(AstFile *f) { return make_raw_union_type(f, token, decls, decl_count); } - case Token_proc: - return parse_proc_type(f); + case Token_proc: { + Token token = f->curr_token; + AstNode *pt = parse_proc_type(f, NULL, NULL); + if (pt->ProcType.tags != 0) { + syntax_error(token, "A procedure type cannot have tags"); + } + return pt; + } case Token_OpenParen: { // NOTE(bill): Skip the paren expression @@ -2406,7 +2466,7 @@ void parse_proc_signature(AstFile *f, AstNodeArray *params, AstNodeArray *results) { expect_token(f, Token_OpenParen); - *params = parse_field_list(f, NULL, true, Token_Comma, Token_CloseParen); + *params = parse_field_list(f, NULL, true, true, Token_Comma, Token_CloseParen); expect_token_after(f, Token_CloseParen, "parameter list"); *results = parse_results(f); } @@ -2431,21 +2491,22 @@ AstNode *parse_proc_decl(AstFile *f) { return make_expr_stmt(f, parse_expr(f, true)); } - Token proc_token = expect_token(f, Token_proc); - AstNode *name = parse_identifier(f); - AstNodeArray params = {0}; AstNodeArray results = {0}; + + Token proc_token = expect_token(f, Token_proc); + AstNode *name = parse_identifier(f); parse_proc_signature(f, ¶ms, &results); - AstNode *proc_type = make_proc_type(f, proc_token, params, results, 0); - - AstNode *body = NULL; u64 tags = 0; String foreign_name = {0}; String link_name = {0}; + ProcCallingConvention cc = ProcCC_Odin; - parse_proc_tags(f, &tags, &foreign_name, &link_name); + parse_proc_tags(f, &tags, &foreign_name, &link_name, &cc); + + AstNode *proc_type = make_proc_type(f, proc_token, params, results, tags, cc); + AstNode *body = NULL; if (f->curr_token.kind == Token_OpenBrace) { if ((tags & ProcTag_foreign) != 0) { diff --git a/src/ssa.c b/src/ssa.c index f3e404571..f85dbaa2d 100644 --- a/src/ssa.c +++ b/src/ssa.c @@ -2607,7 +2607,7 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue } else if (e != NULL && e->kind == Entity_Variable) { return ssa_addr_load(proc, ssa_build_addr(proc, expr)); } - GB_PANIC("nil value for expression from identifier: %.*s", LIT(i->string)); + GB_PANIC("NULL value for expression from identifier: %.*s", LIT(i->string)); return NULL; case_end; @@ -5025,7 +5025,7 @@ void ssa_gen_tree(ssaGen *s) { Type *proc_type = make_type_proc(a, proc_scope, proc_params, 3, - proc_results, 1, false); + proc_results, 1, false, ProcCC_Std); AstNode *body = gb_alloc_item(a, AstNode); Entity *e = make_entity_procedure(a, NULL, make_token_ident(name), proc_type, 0); @@ -5035,7 +5035,7 @@ void ssa_gen_tree(ssaGen *s) { map_ssa_value_set(&m->members, hash_string(name), p); ssaProcedure *proc = &p->Proc; - proc->tags = ProcTag_no_inline | ProcTag_stdcall; // TODO(bill): is no_inline a good idea? + proc->tags = ProcTag_no_inline; // TODO(bill): is no_inline a good idea? e->Procedure.link_name = name; ssa_begin_procedure_body(proc); @@ -5084,17 +5084,19 @@ void ssa_gen_tree(ssaGen *s) { Type *proc_type = make_type_proc(a, proc_scope, proc_params, 4, - proc_results, 1, false); + proc_results, 1, false, ProcCC_Std); AstNode *body = gb_alloc_item(a, AstNode); Entity *e = make_entity_procedure(a, NULL, make_token_ident(name), proc_type, 0); ssaValue *p = ssa_make_value_procedure(a, m, e, proc_type, NULL, body, name); + m->entry_point_entity = e; + map_ssa_value_set(&m->values, hash_pointer(e), p); map_ssa_value_set(&m->members, hash_string(name), p); ssaProcedure *proc = &p->Proc; - proc->tags = ProcTag_no_inline | ProcTag_stdcall; // TODO(bill): is no_inline a good idea? + proc->tags = ProcTag_no_inline; // TODO(bill): is no_inline a good idea? e->Procedure.link_name = name; ssa_begin_procedure_body(proc); @@ -5108,7 +5110,7 @@ void ssa_gen_tree(ssaGen *s) { String name = str_lit(SSA_STARTUP_RUNTIME_PROC_NAME); Type *proc_type = make_type_proc(a, gb_alloc_item(a, Scope), NULL, 0, - NULL, 0, false); + NULL, 0, false, ProcCC_Odin); AstNode *body = gb_alloc_item(a, AstNode); Entity *e = make_entity_procedure(a, NULL, make_token_ident(name), proc_type, 0); ssaValue *p = ssa_make_value_procedure(a, m, e, proc_type, NULL, body, name); diff --git a/src/ssa_print.c b/src/ssa_print.c index c6f55893a..bbca6b9db 100644 --- a/src/ssa_print.c +++ b/src/ssa_print.c @@ -636,6 +636,16 @@ void ssa_print_value(ssaFileBuffer *f, ssaModule *m, ssaValue *value, Type *type } } +void ssa_print_calling_convention(ssaFileBuffer *f, ssaModule *m, ProcCallingConvention cc) { + switch (cc) { + case ProcCC_Odin: ssa_fprintf(f, ""); break; + case ProcCC_C: ssa_fprintf(f, "ccc "); break; + case ProcCC_Std: ssa_fprintf(f, "cc 64 "); break; + case ProcCC_Fast: ssa_fprintf(f, "cc 65 "); break; + default: GB_PANIC("unknown calling convention: %d", cc); + } +} + void ssa_print_instr(ssaFileBuffer *f, ssaModule *m, ssaValue *value) { GB_ASSERT(value->kind == ssaValue_Instr); ssaInstr *instr = &value->Instr; @@ -933,6 +943,7 @@ void ssa_print_instr(ssaFileBuffer *f, ssaModule *m, ssaValue *value) { if (gb_is_between(bo->op, Token__ComparisonBegin+1, Token__ComparisonEnd-1)) { if (is_type_string(elem_type)) { ssa_fprintf(f, "call "); + ssa_print_calling_convention(f, m, ProcCC_Odin); ssa_print_type(f, m, t_bool); char *runtime_proc = ""; switch (bo->op) { @@ -1033,11 +1044,14 @@ void ssa_print_instr(ssaFileBuffer *f, ssaModule *m, ssaValue *value) { case ssaInstr_Call: { ssaInstrCall *call = &instr->Call; + Type *proc_type = base_type(ssa_type(call->value)); + GB_ASSERT(is_type_proc(proc_type)); Type *result_type = call->type; if (result_type) { ssa_fprintf(f, "%%%d = ", value->index); } ssa_fprintf(f, "call "); + ssa_print_calling_convention(f, m, proc_type->Proc.calling_convention); if (result_type) { ssa_print_type(f, m, result_type); } else { @@ -1226,6 +1240,7 @@ void ssa_print_instr(ssaFileBuffer *f, ssaModule *m, ssaValue *value) { } } + void ssa_print_proc(ssaFileBuffer *f, ssaModule *m, ssaProcedure *proc) { if (proc->body == NULL) { ssa_fprintf(f, "declare "); @@ -1243,14 +1258,10 @@ void ssa_print_proc(ssaFileBuffer *f, ssaModule *m, ssaProcedure *proc) { } } - if (proc->tags & ProcTag_stdcall) { - ssa_fprintf(f, "cc 64 "); - } else if (proc->tags & ProcTag_fastcall) { - ssa_fprintf(f, "cc 65 "); - } - TypeProc *proc_type = &proc->type->Proc; + ssa_print_calling_convention(f, m, proc_type->calling_convention); + if (proc_type->result_count == 0) { ssa_fprintf(f, "void"); } else {