diff --git a/code/demo.odin b/code/demo.odin index 305638d52..5241e29ce 100644 --- a/code/demo.odin +++ b/code/demo.odin @@ -7,17 +7,18 @@ #import "os.odin"; #import "strconv.odin"; #import "sync.odin"; +#import win32 "sys/windows.odin"; main :: proc() { - a: i8 = -1; - fmt.println(a, cast(u64)a, cast(i64)a); - b: i64 = -1; - fmt.println(b, cast(u64)b, cast(i64)b); + a := 1; + b := 2; + c := a + b; + + if c > 0 { + c = 0; + } when false { - s := new_slice(int, 0, 10); - append(s, 1, 2, 6, 3, 6, 5, 5, 5, 5, 1, 2); - fmt.println(s); /* Version 0.1.1 diff --git a/core/math.odin b/core/math.odin index f0b53950f..dc5b7ba76 100644 --- a/core/math.odin +++ b/core/math.odin @@ -27,14 +27,14 @@ Mat4 :: [4]Vec4; sqrt :: proc(x: f32) -> f32 #foreign __llvm_core "llvm.sqrt.f32"; sqrt :: proc(x: f64) -> f64 #foreign __llvm_core "llvm.sqrt.f64"; -sin :: proc(x: f32) -> f32 #foreign __llvm_core "llvm.sin.f32"; -sin :: proc(x: f64) -> f64 #foreign __llvm_core "llvm.sin.f64"; +sin :: proc(x: f32) -> f32 #foreign __llvm_core "llvm.sin.f32"; +sin :: proc(x: f64) -> f64 #foreign __llvm_core "llvm.sin.f64"; -cos :: proc(x: f32) -> f32 #foreign __llvm_core "llvm.cos.f32"; -cos :: proc(x: f64) -> f64 #foreign __llvm_core "llvm.cos.f64"; +cos :: proc(x: f32) -> f32 #foreign __llvm_core "llvm.cos.f32"; +cos :: proc(x: f64) -> f64 #foreign __llvm_core "llvm.cos.f64"; -tan :: proc(x: f32) -> f32 #inline { return sin(x)/cos(x); } -tan :: proc(x: f64) -> f64 #inline { return sin(x)/cos(x); } +tan :: proc(x: f32) -> f32 #inline { return sin(x)/cos(x); } +tan :: proc(x: f64) -> f64 #inline { return sin(x)/cos(x); } lerp :: proc(a, b, t: f32) -> f32 { return a*(1-t) + b*t; } lerp :: proc(a, b, t: f64) -> f64 { return a*(1-t) + b*t; } @@ -53,36 +53,42 @@ fmuladd :: proc(a, b, c: f64) -> f64 #foreign __llvm_core "llvm.fmuladd.f64"; copy_sign :: proc(x, y: f32) -> f32 { ix := transmute(u32)x; iy := transmute(u32)y; - ix &= 0x7fffffff; - ix |= iy & 0x80000000; + ix &= 0x7fff_ffff; + ix |= iy & 0x8000_0000; return transmute(f32)ix; } -round :: proc(x: f32) -> f32 { - if x >= 0 { - return floor(x + 0.5); - } - return ceil(x - 0.5); -} -floor :: proc(x: f32) -> f32 { - if x >= 0 { - return cast(f32)cast(int)x; - } - return cast(f32)cast(int)(x-0.5); -} -ceil :: proc(x: f32) -> f32 { - if x < 0 { - return cast(f32)cast(int)x; - } - return cast(f32)cast(int)(x+1); + +copy_sign :: proc(x, y: f64) -> f64 { + ix := transmute(u64)x; + iy := transmute(u64)y; + ix &= 0x7fff_ffff_ffff_ff; + ix |= iy & 0x8000_0000_0000_0000; + return transmute(f64)ix; } -remainder32 :: proc(x, y: f32) -> f32 { - return x - round(x/y) * y; -} +round :: proc(x: f32) -> f32 { return x >= 0 ? floor(x + 0.5) : ceil(x - 0.5); } +round :: proc(x: f64) -> f64 { return x >= 0 ? floor(x + 0.5) : ceil(x - 0.5); } -fmod32 :: proc(x, y: f32) -> f32 { +floor :: proc(x: f32) -> f32 { return x >= 0 ? cast(f32)cast(i64)x : cast(f32)cast(i64)(x-0.5); } // TODO: Get accurate versions +floor :: proc(x: f64) -> f64 { return x >= 0 ? cast(f64)cast(i64)x : cast(f64)cast(i64)(x-0.5); } // TODO: Get accurate versions + +ceil :: proc(x: f32) -> f32 { return x < 0 ? cast(f32)cast(i64)x : cast(f32)cast(i64)(x+1); } // TODO: Get accurate versions +ceil :: proc(x: f64) -> f64 { return x < 0 ? cast(f64)cast(i64)x : cast(f64)cast(i64)(x+1); } // TODO: Get accurate versions + +remainder :: proc(x, y: f32) -> f32 { return x - round(x/y) * y; } +remainder :: proc(x, y: f64) -> f64 { return x - round(x/y) * y; } + +mod :: proc(x, y: f32) -> f32 { y = abs(y); - result := remainder32(abs(x), y); + result := remainder(abs(x), y); + if sign(result) < 0 { + result += y; + } + return copy_sign(result, x); +} +mod :: proc(x, y: f64) -> f64 { + y = abs(y); + result := remainder(abs(x), y); if sign(result) < 0 { result += y; } @@ -95,7 +101,6 @@ to_degrees :: proc(radians: f32) -> f32 { return radians * 360 / TAU; } - dot :: proc(a, b: Vec2) -> f32 { c := a*b; return c.x + c.y; } dot :: proc(a, b: Vec3) -> f32 { c := a*b; return c.x + c.y + c.z; } dot :: proc(a, b: Vec4) -> f32 { c := a*b; return c.x + c.y + c.z + c.w; } diff --git a/core/os_windows.odin b/core/os_windows.odin index 8e380f0ba..d040797ce 100644 --- a/core/os_windows.odin +++ b/core/os_windows.odin @@ -1,4 +1,4 @@ -#import win32 "sys/windows.odin"; +#import w "sys/windows.odin"; #import "fmt.odin"; @@ -53,29 +53,28 @@ ERROR_FILE_IS_PIPE: Errno : 1<<29 + 0; open :: proc(path: string, mode: int, perm: u32) -> (Handle, Errno) { - using win32; if path.count == 0 { return INVALID_HANDLE, ERROR_FILE_NOT_FOUND; } access: u32; match mode & (O_RDONLY|O_WRONLY|O_RDWR) { - case O_RDONLY: access = FILE_GENERIC_READ; - case O_WRONLY: access = FILE_GENERIC_WRITE; - case O_RDWR: access = FILE_GENERIC_READ | FILE_GENERIC_WRITE; + case O_RDONLY: access = w.FILE_GENERIC_READ; + case O_WRONLY: access = w.FILE_GENERIC_WRITE; + case O_RDWR: access = w.FILE_GENERIC_READ | w.FILE_GENERIC_WRITE; } if mode&O_CREAT != 0 { - access |= FILE_GENERIC_WRITE; + access |= w.FILE_GENERIC_WRITE; } if mode&O_APPEND != 0 { - access &~= FILE_GENERIC_WRITE; - access |= FILE_APPEND_DATA; + access &~= w.FILE_GENERIC_WRITE; + access |= w.FILE_APPEND_DATA; } - share_mode := cast(u32)(FILE_SHARE_READ|FILE_SHARE_WRITE); - sa: ^SECURITY_ATTRIBUTES = nil; - sa_inherit := SECURITY_ATTRIBUTES{length = size_of(SECURITY_ATTRIBUTES), inherit_handle = 1}; + share_mode := cast(u32)(w.FILE_SHARE_READ|w.FILE_SHARE_WRITE); + sa: ^w.Security_Attributes = nil; + sa_inherit := w.Security_Attributes{length = size_of(w.Security_Attributes), inherit_handle = 1}; if mode&O_CLOEXEC == 0 { sa = ^sa_inherit; } @@ -83,37 +82,37 @@ open :: proc(path: string, mode: int, perm: u32) -> (Handle, Errno) { create_mode: u32; match { case mode&(O_CREAT|O_EXCL) == (O_CREAT | O_EXCL): - create_mode = CREATE_NEW; + create_mode = w.CREATE_NEW; case mode&(O_CREAT|O_TRUNC) == (O_CREAT | O_TRUNC): - create_mode = CREATE_ALWAYS; + create_mode = w.CREATE_ALWAYS; case mode&O_CREAT == O_CREAT: - create_mode = OPEN_ALWAYS; + create_mode = w.OPEN_ALWAYS; case mode&O_TRUNC == O_TRUNC: - create_mode = TRUNCATE_EXISTING; + create_mode = w.TRUNCATE_EXISTING; default: - create_mode = OPEN_EXISTING; + create_mode = w.OPEN_EXISTING; } buf: [300]byte; copy(buf[..], cast([]byte)path); - handle := cast(Handle)CreateFileA(^buf[0], access, share_mode, sa, create_mode, FILE_ATTRIBUTE_NORMAL, nil); + handle := cast(Handle)w.CreateFileA(^buf[0], access, share_mode, sa, create_mode, w.FILE_ATTRIBUTE_NORMAL, nil); if handle != INVALID_HANDLE { return handle, ERROR_NONE; } - err := GetLastError(); + err := w.GetLastError(); return INVALID_HANDLE, cast(Errno)err; } close :: proc(fd: Handle) { - win32.CloseHandle(cast(win32.HANDLE)fd); + w.CloseHandle(cast(w.Handle)fd); } write :: proc(fd: Handle, data: []byte) -> (int, Errno) { bytes_written: i32; - e := win32.WriteFile(cast(win32.HANDLE)fd, data.data, cast(i32)data.count, ^bytes_written, nil); - if e == win32.FALSE { - err := win32.GetLastError(); + e := w.WriteFile(cast(w.Handle)fd, data.data, cast(i32)data.count, ^bytes_written, nil); + if e == w.FALSE { + err := w.GetLastError(); return 0, cast(Errno)err; } return cast(int)bytes_written, ERROR_NONE; @@ -121,16 +120,16 @@ write :: proc(fd: Handle, data: []byte) -> (int, Errno) { read :: proc(fd: Handle, data: []byte) -> (int, Errno) { bytes_read: i32; - e := win32.ReadFile(cast(win32.HANDLE)fd, data.data, cast(u32)data.count, ^bytes_read, nil); - if e == win32.FALSE { - err := win32.GetLastError(); + e := w.ReadFile(cast(w.Handle)fd, data.data, cast(u32)data.count, ^bytes_read, nil); + if e == w.FALSE { + err := w.GetLastError(); return 0, cast(Errno)err; } return cast(int)bytes_read, ERROR_NONE; } seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) { - using win32; + using w; w: u32; match whence { case 0: w = FILE_BEGIN; @@ -139,11 +138,11 @@ seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) { } hi := cast(i32)(offset>>32); lo := cast(i32)(offset); - ft := GetFileType(cast(HANDLE)fd); + ft := GetFileType(cast(Handle)fd); if ft == FILE_TYPE_PIPE { return 0, ERROR_FILE_IS_PIPE; } - dw_ptr := SetFilePointer(cast(HANDLE)fd, lo, ^hi, w); + dw_ptr := SetFilePointer(cast(Handle)fd, lo, ^hi, w); if dw_ptr == INVALID_SET_FILE_POINTER { err := GetLastError(); return 0, cast(Errno)err; @@ -153,14 +152,14 @@ seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) { // NOTE(bill): Uses startup to initialize it -stdin := get_std_handle(win32.STD_INPUT_HANDLE); -stdout := get_std_handle(win32.STD_OUTPUT_HANDLE); -stderr := get_std_handle(win32.STD_ERROR_HANDLE); +stdin := get_std_handle(w.STD_INPUT_HANDLE); +stdout := get_std_handle(w.STD_OUTPUT_HANDLE); +stderr := get_std_handle(w.STD_ERROR_HANDLE); get_std_handle :: proc(h: int) -> Handle { - fd := win32.GetStdHandle(cast(i32)h); - win32.SetHandleInformation(fd, win32.HANDLE_FLAG_INHERIT, 0); + fd := w.GetStdHandle(cast(i32)h); + w.SetHandleInformation(fd, w.HANDLE_FLAG_INHERIT, 0); return cast(Handle)fd; } @@ -170,23 +169,23 @@ get_std_handle :: proc(h: int) -> Handle { last_write_time :: proc(fd: Handle) -> File_Time { - file_info: win32.BY_HANDLE_FILE_INFORMATION; - win32.GetFileInformationByHandle(cast(win32.HANDLE)fd, ^file_info); + file_info: w.By_Handle_File_Information; + w.GetFileInformationByHandle(cast(w.Handle)fd, ^file_info); lo := cast(File_Time)file_info.last_write_time.lo; hi := cast(File_Time)file_info.last_write_time.hi; return lo | hi << 32; } last_write_time_by_name :: proc(name: string) -> File_Time { - last_write_time: win32.FILETIME; - data: win32.FILE_ATTRIBUTE_DATA; + last_write_time: w.Filetime; + data: w.File_Attribute_Data; buf: [1024]byte; assert(buf.count > name.count); copy(buf[..], cast([]byte)name); - if win32.GetFileAttributesExA(^buf[0], win32.GetFileExInfoStandard, ^data) != 0 { + if w.GetFileAttributesExA(^buf[0], w.GetFileExInfoStandard, ^data) != 0 { last_write_time = data.last_write_time; } @@ -210,7 +209,7 @@ read_entire_file :: proc(name: string) -> ([]byte, bool) { defer close(fd); length: i64; - file_size_ok := win32.GetFileSizeEx(cast(win32.HANDLE)fd, ^length) != 0; + file_size_ok := w.GetFileSizeEx(cast(w.Handle)fd, ^length) != 0; if !file_size_ok { return nil, false; } @@ -233,7 +232,7 @@ read_entire_file :: proc(name: string) -> ([]byte, bool) { to_read = MAX; } - win32.ReadFile(cast(win32.HANDLE)fd, ^data[total_read], to_read, ^single_read_length, nil); + w.ReadFile(cast(w.Handle)fd, ^data[total_read], to_read, ^single_read_length, nil); if single_read_length <= 0 { free(data); return nil, false; @@ -249,7 +248,7 @@ read_entire_file :: proc(name: string) -> ([]byte, bool) { heap_alloc :: proc(size: int) -> rawptr { assert(size > 0); - return win32.HeapAlloc(win32.GetProcessHeap(), win32.HEAP_ZERO_MEMORY, size); + return w.HeapAlloc(w.GetProcessHeap(), w.HEAP_ZERO_MEMORY, size); } heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr { if new_size == 0 { @@ -259,24 +258,24 @@ heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr { if ptr == nil { return heap_alloc(new_size); } - return win32.HeapReAlloc(win32.GetProcessHeap(), win32.HEAP_ZERO_MEMORY, ptr, new_size); + return w.HeapReAlloc(w.GetProcessHeap(), w.HEAP_ZERO_MEMORY, ptr, new_size); } heap_free :: proc(ptr: rawptr) { if ptr == nil { return; } - win32.HeapFree(win32.GetProcessHeap(), 0, ptr); + w.HeapFree(w.GetProcessHeap(), 0, ptr); } exit :: proc(code: int) { - win32.ExitProcess(cast(u32)code); + w.ExitProcess(cast(u32)code); } current_thread_id :: proc() -> int { - return cast(int)win32.GetCurrentThreadId(); + return cast(int)w.GetCurrentThreadId(); } diff --git a/core/sync.odin b/core/sync.odin index a2296c3b6..72f784f6d 100644 --- a/core/sync.odin +++ b/core/sync.odin @@ -2,7 +2,7 @@ #import "atomic.odin"; Semaphore :: struct { - _handle: win32.HANDLE, + _handle: win32.Handle, } Mutex :: struct { diff --git a/core/sys/wgl.odin b/core/sys/wgl.odin index bf993ca58..9edbdda11 100644 --- a/core/sys/wgl.odin +++ b/core/sys/wgl.odin @@ -8,10 +8,10 @@ CONTEXT_PROFILE_MASK_ARB :: 0x9126; CONTEXT_FORWARD_COMPATIBLE_BIT_ARB :: 0x0002; CONTEXT_CORE_PROFILE_BIT_ARB :: 0x00000001; -HGLRC :: HANDLE; -COLORREF :: u32; +Hglrc :: Handle; +Color_Ref :: u32; -LAYERPLANEDESCRIPTOR :: struct #ordered { +Layer_Plane_Descriptor :: struct #ordered { size: u16, version: u16, flags: u32, @@ -35,38 +35,38 @@ LAYERPLANEDESCRIPTOR :: struct #ordered { aux_buffers: byte, layer_type: byte, reserved: byte, - transparent: COLORREF, + transparent: Color_Ref, } -POINTFLOAT :: struct #ordered { +Point_Float :: struct #ordered { x, y: f32, } -GLYPHMETRICSFLOAT :: struct #ordered { +Glyph_Metrics_Float :: struct #ordered { black_box_x: f32, black_box_y: f32, - glyph_origin: POINTFLOAT, + glyph_origin: Point_Float, cell_inc_x: f32, cell_inc_y: f32, } -CreateContextAttribsARBType :: #type proc(hdc: HDC, hshareContext: rawptr, attribList: ^i32) -> HGLRC; -ChoosePixelFormatARBType :: #type proc(hdc: HDC, attrib_i_list: ^i32, attrib_f_list: ^f32, max_formats: u32, formats: ^i32, num_formats : ^u32) -> BOOL #cc_c; +Create_Context_Attribs_ARB_Type :: #type proc(hdc: Hdc, hshareContext: rawptr, attribList: ^i32) -> Hglrc; +Choose_Pixel_Format_ARB_Type :: #type proc(hdc: Hdc, attrib_i_list: ^i32, attrib_f_list: ^f32, max_formats: u32, formats: ^i32, num_formats : ^u32) -> Bool #cc_c; -CreateContext :: proc(hdc: HDC) -> HGLRC #foreign opengl32 "wglCreateContext"; -MakeCurrent :: proc(hdc: HDC, hglrc: HGLRC) -> BOOL #foreign opengl32 "wglMakeCurrent"; -GetProcAddress :: proc(c_str: ^u8) -> PROC #foreign opengl32 "wglGetProcAddress"; -DeleteContext :: proc(hglrc: HGLRC) -> BOOL #foreign opengl32 "wglDeleteContext"; -CopyContext :: proc(src, dst: HGLRC, mask: u32) -> BOOL #foreign opengl32 "wglCopyContext"; -CreateLayerContext :: proc(hdc: HDC, layer_plane: i32) -> HGLRC #foreign opengl32 "wglCreateLayerContext"; -DescribeLayerPlane :: proc(hdc: HDC, pixel_format, layer_plane: i32, bytes: u32, pd: ^LAYERPLANEDESCRIPTOR) -> BOOL #foreign opengl32 "wglDescribeLayerPlane"; -GetCurrentContext :: proc() -> HGLRC #foreign opengl32 "wglGetCurrentContext"; -GetCurrentDC :: proc() -> HDC #foreign opengl32 "wglGetCurrentDC"; -GetLayerPaletteEntries :: proc(hdc: HDC, layer_plane, start, entries: i32, cr: ^COLORREF) -> i32 #foreign opengl32 "wglGetLayerPaletteEntries"; -RealizeLayerPalette :: proc(hdc: HDC, layer_plane: i32, realize: BOOL) -> BOOL #foreign opengl32 "wglRealizeLayerPalette"; -SetLayerPaletteEntries :: proc(hdc: HDC, layer_plane, start, entries: i32, cr: ^COLORREF) -> i32 #foreign opengl32 "wglSetLayerPaletteEntries"; -ShareLists :: proc(hglrc1, hglrc2: HGLRC) -> BOOL #foreign opengl32 "wglShareLists"; -SwapLayerBuffers :: proc(hdc: HDC, planes: u32) -> BOOL #foreign opengl32 "wglSwapLayerBuffers"; -UseFontBitmaps :: proc(hdc: HDC, first, count, list_base: u32) -> BOOL #foreign opengl32 "wglUseFontBitmaps"; -UseFontOutlines :: proc(hdc: HDC, first, count, list_base: u32, deviation, extrusion: f32, format: i32, gmf: ^GLYPHMETRICSFLOAT) -> BOOL #foreign opengl32 "wglUseFontOutlines"; +CreateContext :: proc(hdc: Hdc) -> Hglrc #foreign opengl32 "wglCreateContext"; +MakeCurrent :: proc(hdc: Hdc, hglrc: Hglrc) -> Bool #foreign opengl32 "wglMakeCurrent"; +GetProcAddress :: proc(c_str: ^u8) -> Proc #foreign opengl32 "wglGetProcAddress"; +DeleteContext :: proc(hglrc: Hglrc) -> Bool #foreign opengl32 "wglDeleteContext"; +CopyContext :: proc(src, dst: Hglrc, mask: u32) -> Bool #foreign opengl32 "wglCopyContext"; +CreateLayerContext :: proc(hdc: Hdc, layer_plane: i32) -> Hglrc #foreign opengl32 "wglCreateLayerContext"; +DescribeLayerPlane :: proc(hdc: Hdc, pixel_format, layer_plane: i32, bytes: u32, pd: ^Layer_Plane_Descriptor) -> Bool #foreign opengl32 "wglDescribeLayerPlane"; +GetCurrentContext :: proc() -> Hglrc #foreign opengl32 "wglGetCurrentContext"; +GetCurrentDC :: proc() -> Hdc #foreign opengl32 "wglGetCurrentDC"; +GetLayerPaletteEntries :: proc(hdc: Hdc, layer_plane, start, entries: i32, cr: ^Color_Ref) -> i32 #foreign opengl32 "wglGetLayerPaletteEntries"; +RealizeLayerPalette :: proc(hdc: Hdc, layer_plane: i32, realize: Bool) -> Bool #foreign opengl32 "wglRealizeLayerPalette"; +SetLayerPaletteEntries :: proc(hdc: Hdc, layer_plane, start, entries: i32, cr: ^Color_Ref) -> i32 #foreign opengl32 "wglSetLayerPaletteEntries"; +ShareLists :: proc(hglrc1, hglrc2: Hglrc) -> Bool #foreign opengl32 "wglShareLists"; +SwapLayerBuffers :: proc(hdc: Hdc, planes: u32) -> Bool #foreign opengl32 "wglSwapLayerBuffers"; +UseFontBitmaps :: proc(hdc: Hdc, first, count, list_base: u32) -> Bool #foreign opengl32 "wglUseFontBitmaps"; +UseFontOutlines :: proc(hdc: Hdc, first, count, list_base: u32, deviation, extrusion: f32, format: i32, gmf: ^Glyph_Metrics_Float) -> Bool #foreign opengl32 "wglUseFontOutlines"; diff --git a/core/sys/windows.odin b/core/sys/windows.odin index 708c9c84d..0a5edf003 100644 --- a/core/sys/windows.odin +++ b/core/sys/windows.odin @@ -3,28 +3,27 @@ #foreign_system_library "gdi32.lib" when ODIN_OS == "windows"; #foreign_system_library "winmm.lib" when ODIN_OS == "windows"; -HANDLE :: rawptr; -HWND :: HANDLE; -HDC :: HANDLE; -HINSTANCE :: HANDLE; -HICON :: HANDLE; -HCURSOR :: HANDLE; -HMENU :: HANDLE; -HBRUSH :: HANDLE; -HGDIOBJ :: HANDLE; -HMODULE :: HANDLE; -WPARAM :: uint; -LPARAM :: int; -LRESULT :: int; -ATOM :: i16; -BOOL :: i32; -WNDPROC :: #type proc(HWND, u32, WPARAM, LPARAM) -> LRESULT #cc_c; +Handle :: rawptr; +Hwnd :: Handle; +Hdc :: Handle; +Hinstance :: Handle; +Hicon :: Handle; +Hcursor :: Handle; +Hmenu :: Handle; +Hbrush :: Handle; +Hgdiobj :: Handle; +Hmodule :: Handle; +Wparam :: uint; +Lparam :: int; +Lresult :: int; +Bool :: i32; +Wnd_Proc :: #type proc(Hwnd, u32, Wparam, Lparam) -> Lresult #cc_c; -INVALID_HANDLE_VALUE :: cast(HANDLE)~cast(int)0; +INVALID_HANDLE :: cast(Handle)~cast(int)0; -FALSE: BOOL : 0; -TRUE: BOOL : 1; +FALSE: Bool : 0; +TRUE: Bool : 1; CS_VREDRAW :: 0x0001; CS_HREDRAW :: 0x0002; @@ -56,7 +55,7 @@ WM_CHAR :: 0x0102; PM_REMOVE :: 1; -COLOR_BACKGROUND :: cast(HBRUSH)(cast(int)1); +COLOR_BACKGROUND :: cast(Hbrush)(cast(int)1); BLACK_BRUSH :: 4; SM_CXSCREEN :: 0; @@ -65,53 +64,53 @@ SM_CYSCREEN :: 1; SW_SHOW :: 5; -POINT :: struct #ordered { +Point :: struct #ordered { x, y: i32, } -WNDCLASSEXA :: struct #ordered { +WndClassExA :: struct #ordered { size, style: u32, - wnd_proc: WNDPROC, + wnd_proc: Wnd_Proc, cls_extra, wnd_extra: i32, - instance: HINSTANCE, - icon: HICON, - cursor: HCURSOR, - background: HBRUSH, + instance: Hinstance, + icon: Hicon, + cursor: Hcursor, + background: Hbrush, menu_name, class_name: ^u8, - sm: HICON, + sm: Hicon, } -MSG :: struct #ordered { - hwnd: HWND, +Msg :: struct #ordered { + hwnd: Hwnd, message: u32, - wparam: WPARAM, - lparam: LPARAM, + wparam: Wparam, + lparam: Lparam, time: u32, - pt: POINT, + pt: Point, } -RECT :: struct #ordered { +Rect :: struct #ordered { left: i32, top: i32, right: i32, bottom: i32, } -FILETIME :: struct #ordered { +Filetime :: struct #ordered { lo, hi: u32, } -SYSTEMTIME :: struct #ordered { +Systemtime :: struct #ordered { year, month: u16, day_of_week, day: u16, hour, minute, second, millisecond: u16, } -BY_HANDLE_FILE_INFORMATION :: struct #ordered { +By_Handle_File_Information :: struct #ordered { file_attributes: u32, creation_time, last_access_time, - last_write_time: FILETIME, + last_write_time: Filetime, volume_serial_number, file_size_high, file_size_low, @@ -120,11 +119,11 @@ BY_HANDLE_FILE_INFORMATION :: struct #ordered { file_index_low: u32, } -FILE_ATTRIBUTE_DATA :: struct #ordered { +File_Attribute_Data :: struct #ordered { file_attributes: u32, creation_time, last_access_time, - last_write_time: FILETIME, + last_write_time: Filetime, file_size_high, file_size_low: u32, } @@ -136,13 +135,13 @@ GetFileExMaxInfoLevel: GET_FILEEX_INFO_LEVELS : 1; GetLastError :: proc() -> i32 #foreign kernel32; ExitProcess :: proc(exit_code: u32) #foreign kernel32; -GetDesktopWindow :: proc() -> HWND #foreign user32; -GetCursorPos :: proc(p: ^POINT) -> i32 #foreign user32; -ScreenToClient :: proc(h: HWND, p: ^POINT) -> i32 #foreign user32; -GetModuleHandleA :: proc(module_name: ^u8) -> HINSTANCE #foreign kernel32; -GetStockObject :: proc(fn_object: i32) -> HGDIOBJ #foreign gdi32; +GetDesktopWindow :: proc() -> Hwnd #foreign user32; +GetCursorPos :: proc(p: ^Point) -> i32 #foreign user32; +ScreenToClient :: proc(h: Hwnd, p: ^Point) -> i32 #foreign user32; +GetModuleHandleA :: proc(module_name: ^u8) -> Hinstance #foreign kernel32; +GetStockObject :: proc(fn_object: i32) -> Hgdiobj #foreign gdi32; PostQuitMessage :: proc(exit_code: i32) #foreign user32; -SetWindowTextA :: proc(hwnd: HWND, c_string: ^u8) -> BOOL #foreign user32; +SetWindowTextA :: proc(hwnd: Hwnd, c_string: ^u8) -> Bool #foreign user32; QueryPerformanceFrequency :: proc(result: ^i64) -> i32 #foreign kernel32; QueryPerformanceCounter :: proc(result: ^i64) -> i32 #foreign kernel32; @@ -152,28 +151,28 @@ Sleep :: proc(ms: i32) -> i32 #foreign kernel32; OutputDebugStringA :: proc(c_str: ^u8) #foreign kernel32; -RegisterClassExA :: proc(wc: ^WNDCLASSEXA) -> ATOM #foreign user32; +RegisterClassExA :: proc(wc: ^WndClassExA) -> i16 #foreign user32; CreateWindowExA :: proc(ex_style: u32, class_name, title: ^u8, style: u32, x, y, w, h: i32, - parent: HWND, menu: HMENU, instance: HINSTANCE, - param: rawptr) -> HWND #foreign user32; + parent: Hwnd, menu: Hmenu, instance: Hinstance, + param: rawptr) -> Hwnd #foreign user32; -ShowWindow :: proc(hwnd: HWND, cmd_show: i32) -> BOOL #foreign user32; -TranslateMessage :: proc(msg: ^MSG) -> BOOL #foreign user32; -DispatchMessageA :: proc(msg: ^MSG) -> LRESULT #foreign user32; -UpdateWindow :: proc(hwnd: HWND) -> BOOL #foreign user32; -PeekMessageA :: proc(msg: ^MSG, hwnd: HWND, - msg_filter_min, msg_filter_max, remove_msg: u32) -> BOOL #foreign user32; +ShowWindow :: proc(hwnd: Hwnd, cmd_show: i32) -> Bool #foreign user32; +TranslateMessage :: proc(msg: ^Msg) -> Bool #foreign user32; +DispatchMessageA :: proc(msg: ^Msg) -> Lresult #foreign user32; +UpdateWindow :: proc(hwnd: Hwnd) -> Bool #foreign user32; +PeekMessageA :: proc(msg: ^Msg, hwnd: Hwnd, + msg_filter_min, msg_filter_max, remove_msg: u32) -> Bool #foreign user32; -DefWindowProcA :: proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT #foreign user32; +DefWindowProcA :: proc(hwnd: Hwnd, msg: u32, wparam: Wparam, lparam: Lparam) -> Lresult #foreign user32; -AdjustWindowRect :: proc(rect: ^RECT, style: u32, menu: BOOL) -> BOOL #foreign user32; -GetActiveWindow :: proc() -> HWND #foreign user32; +AdjustWindowRect :: proc(rect: ^Rect, style: u32, menu: Bool) -> Bool #foreign user32; +GetActiveWindow :: proc() -> Hwnd #foreign user32; -DestroyWindow :: proc(wnd: HWND) -> BOOL #foreign user32; -DescribePixelFormat :: proc(dc: HDC, pixel_format: i32, bytes : u32, pfd: ^PIXELFORMATDESCRIPTOR) -> i32 #foreign user32; +DestroyWindow :: proc(wnd: Hwnd) -> Bool #foreign user32; +DescribePixelFormat :: proc(dc: Hdc, pixel_format: i32, bytes : u32, pfd: ^PIXELFORMATDESCRIPTOR) -> i32 #foreign user32; GetQueryPerformanceFrequency :: proc() -> i64 { @@ -187,29 +186,29 @@ GetSystemMetrics :: proc(index: i32) -> i32 #foreign kernel32; GetCurrentThreadId :: proc() -> u32 #foreign kernel32; timeGetTime :: proc() -> u32 #foreign winmm; -GetSystemTimeAsFileTime :: proc(system_time_as_file_time: ^FILETIME) #foreign kernel32; -FileTimeToLocalFileTime :: proc(file_time: ^FILETIME, local_file_time: ^FILETIME) -> BOOL #foreign kernel32; -FileTimeToSystemTime :: proc(file_time: ^FILETIME, system_time: ^SYSTEMTIME) -> BOOL #foreign kernel32; -SystemTimeToFileTime :: proc(system_time: ^SYSTEMTIME, file_time: ^FILETIME) -> BOOL #foreign kernel32; +GetSystemTimeAsFileTime :: proc(system_time_as_file_time: ^Filetime) #foreign kernel32; +FileTimeToLocalFileTime :: proc(file_time: ^Filetime, local_file_time: ^Filetime) -> Bool #foreign kernel32; +FileTimeToSystemTime :: proc(file_time: ^Filetime, system_time: ^Systemtime) -> Bool #foreign kernel32; +SystemTimeToFileTime :: proc(system_time: ^Systemtime, file_time: ^Filetime) -> Bool #foreign kernel32; // File Stuff -CloseHandle :: proc(h: HANDLE) -> i32 #foreign kernel32; -GetStdHandle :: proc(h: i32) -> HANDLE #foreign kernel32; +CloseHandle :: proc(h: Handle) -> i32 #foreign kernel32; +GetStdHandle :: proc(h: i32) -> Handle #foreign kernel32; CreateFileA :: proc(filename: ^u8, desired_access, share_mode: u32, security: rawptr, - creation, flags_and_attribs: u32, template_file: HANDLE) -> HANDLE #foreign kernel32; -ReadFile :: proc(h: HANDLE, buf: rawptr, to_read: u32, bytes_read: ^i32, overlapped: rawptr) -> BOOL #foreign kernel32; -WriteFile :: proc(h: HANDLE, buf: rawptr, len: i32, written_result: ^i32, overlapped: rawptr) -> BOOL #foreign kernel32; + creation, flags_and_attribs: u32, template_file: Handle) -> Handle #foreign kernel32; +ReadFile :: proc(h: Handle, buf: rawptr, to_read: u32, bytes_read: ^i32, overlapped: rawptr) -> Bool #foreign kernel32; +WriteFile :: proc(h: Handle, buf: rawptr, len: i32, written_result: ^i32, overlapped: rawptr) -> Bool #foreign kernel32; -GetFileSizeEx :: proc(file_handle: HANDLE, file_size: ^i64) -> BOOL #foreign kernel32; -GetFileAttributesExA :: proc(filename: ^u8, info_level_id: GET_FILEEX_INFO_LEVELS, file_info: rawptr) -> BOOL #foreign kernel32; -GetFileInformationByHandle :: proc(file_handle: HANDLE, file_info: ^BY_HANDLE_FILE_INFORMATION) -> BOOL #foreign kernel32; +GetFileSizeEx :: proc(file_handle: Handle, file_size: ^i64) -> Bool #foreign kernel32; +GetFileAttributesExA :: proc(filename: ^u8, info_level_id: GET_FILEEX_INFO_LEVELS, file_info: rawptr) -> Bool #foreign kernel32; +GetFileInformationByHandle :: proc(file_handle: Handle, file_info: ^By_Handle_File_Information) -> Bool #foreign kernel32; -GetFileType :: proc(file_handle: HANDLE) -> u32 #foreign kernel32; -SetFilePointer :: proc(file_handle: HANDLE, distance_to_move: i32, distance_to_move_high: ^i32, move_method: u32) -> u32 #foreign kernel32; +GetFileType :: proc(file_handle: Handle) -> u32 #foreign kernel32; +SetFilePointer :: proc(file_handle: Handle, distance_to_move: i32, distance_to_move_high: ^i32, move_method: u32) -> u32 #foreign kernel32; -SetHandleInformation :: proc(obj: HANDLE, mask, flags: u32) -> BOOL #foreign kernel32; +SetHandleInformation :: proc(obj: Handle, mask, flags: u32) -> Bool #foreign kernel32; HANDLE_FLAG_INHERIT :: 1; HANDLE_FLAG_PROTECT_FROM_CLOSE :: 2; @@ -242,13 +241,13 @@ TRUNCATE_EXISTING :: 5; FILE_ATTRIBUTE_READONLY :: 0x00000001; FILE_ATTRIBUTE_HIDDEN :: 0x00000002; FILE_ATTRIBUTE_SYSTEM :: 0x00000004; -FILE_ATTRIBUTE_DIRECTORY :: 0x00000010; +FILE_ATTRIBUTE_DIRectORY :: 0x00000010; FILE_ATTRIBUTE_ARCHIVE :: 0x00000020; FILE_ATTRIBUTE_DEVICE :: 0x00000040; FILE_ATTRIBUTE_NORMAL :: 0x00000080; FILE_ATTRIBUTE_TEMPORARY :: 0x00000100; FILE_ATTRIBUTE_SPARSE_FILE :: 0x00000200; -FILE_ATTRIBUTE_REPARSE_POINT :: 0x00000400; +FILE_ATTRIBUTE_REPARSE_Point :: 0x00000400; FILE_ATTRIBUTE_COMPRESSED :: 0x00000800; FILE_ATTRIBUTE_OFFLINE :: 0x00001000; FILE_ATTRIBUTE_NOT_CONTENT_INDEXED :: 0x00002000; @@ -263,27 +262,27 @@ INVALID_SET_FILE_POINTER :: ~cast(u32)0; -HeapAlloc :: proc (h: HANDLE, flags: u32, bytes: int) -> rawptr #foreign kernel32; -HeapReAlloc :: proc (h: HANDLE, flags: u32, memory: rawptr, bytes: int) -> rawptr #foreign kernel32; -HeapFree :: proc (h: HANDLE, flags: u32, memory: rawptr) -> BOOL #foreign kernel32; -GetProcessHeap :: proc () -> HANDLE #foreign kernel32; +HeapAlloc :: proc (h: Handle, flags: u32, bytes: int) -> rawptr #foreign kernel32; +HeapReAlloc :: proc (h: Handle, flags: u32, memory: rawptr, bytes: int) -> rawptr #foreign kernel32; +HeapFree :: proc (h: Handle, flags: u32, memory: rawptr) -> Bool #foreign kernel32; +GetProcessHeap :: proc () -> Handle #foreign kernel32; HEAP_ZERO_MEMORY :: 0x00000008; // Synchronization -SECURITY_ATTRIBUTES :: struct #ordered { +Security_Attributes :: struct #ordered { length: u32, security_descriptor: rawptr, - inherit_handle: BOOL, + inherit_handle: Bool, } INFINITE :: 0xffffffff; -CreateSemaphoreA :: proc(attributes: ^SECURITY_ATTRIBUTES, initial_count, maximum_count: i32, name: ^byte) -> HANDLE #foreign kernel32; -ReleaseSemaphore :: proc(semaphore: HANDLE, release_count: i32, previous_count: ^i32) -> BOOL #foreign kernel32; -WaitForSingleObject :: proc(handle: HANDLE, milliseconds: u32) -> u32 #foreign kernel32; +CreateSemaphoreA :: proc(attributes: ^Security_Attributes, initial_count, maximum_count: i32, name: ^byte) -> Handle #foreign kernel32; +ReleaseSemaphore :: proc(semaphore: Handle, release_count: i32, previous_count: ^i32) -> Bool #foreign kernel32; +WaitForSingleObject :: proc(handle: Handle, milliseconds: u32) -> u32 #foreign kernel32; InterlockedCompareExchange :: proc(dst: ^i32, exchange, comparand: i32) -> i32 #foreign kernel32; @@ -307,11 +306,11 @@ ReadBarrier :: proc() #foreign kernel32; -HMONITOR :: HANDLE; +Hmonitor :: Handle; GWL_STYLE :: -16; -HWND_TOP :: cast(HWND)cast(uint)0; +Hwnd_TOP :: cast(Hwnd)cast(uint)0; MONITOR_DEFAULTTONULL :: 0x00000000; MONITOR_DEFAULTTOPRIMARY :: 0x00000001; @@ -324,39 +323,39 @@ SWP_NOSIZE :: 0x0001; SWP_NOMOVE :: 0x0002; -MONITORINFO :: struct #ordered { +Monitor_Info :: struct #ordered { size: u32, - monitor: RECT, - work: RECT, + monitor: Rect, + work: Rect, flags: u32, } -WINDOWPLACEMENT :: struct #ordered { +Window_Placement :: struct #ordered { length: u32, flags: u32, show_cmd: u32, - min_pos: POINT, - max_pos: POINT, - normal_pos: RECT, + min_pos: Point, + max_pos: Point, + normal_pos: Rect, } -GetMonitorInfoA :: proc(monitor: HMONITOR, mi: ^MONITORINFO) -> BOOL #foreign user32; -MonitorFromWindow :: proc(wnd: HWND, flags : u32) -> HMONITOR #foreign user32; +GetMonitorInfoA :: proc(monitor: Hmonitor, mi: ^Monitor_Info) -> Bool #foreign user32; +MonitorFromWindow :: proc(wnd: Hwnd, flags : u32) -> Hmonitor #foreign user32; -SetWindowPos :: proc(wnd: HWND, wndInsertAfter: HWND, x, y, width, height: i32, flags: u32) #foreign user32 "SetWindowPos"; +SetWindowPos :: proc(wnd: Hwnd, wndInsertAfter: Hwnd, x, y, width, height: i32, flags: u32) #foreign user32 "SetWindowPos"; -GetWindowPlacement :: proc(wnd: HWND, wndpl: ^WINDOWPLACEMENT) -> BOOL #foreign user32; -SetWindowPlacement :: proc(wnd: HWND, wndpl: ^WINDOWPLACEMENT) -> BOOL #foreign user32; +GetWindowPlacement :: proc(wnd: Hwnd, wndpl: ^Window_Placement) -> Bool #foreign user32; +SetWindowPlacement :: proc(wnd: Hwnd, wndpl: ^Window_Placement) -> Bool #foreign user32; -GetWindowLongPtrA :: proc(wnd: HWND, index: i32) -> i64 #foreign user32; -SetWindowLongPtrA :: proc(wnd: HWND, index: i32, new: i64) -> i64 #foreign user32; +GetWindowLongPtrA :: proc(wnd: Hwnd, index: i32) -> i64 #foreign user32; +SetWindowLongPtrA :: proc(wnd: Hwnd, index: i32, new: i64) -> i64 #foreign user32; -GetWindowText :: proc(wnd: HWND, str: ^byte, maxCount: i32) -> i32 #foreign user32; +GetWindowText :: proc(wnd: Hwnd, str: ^byte, maxCount: i32) -> i32 #foreign user32; -HIWORD :: proc(wParam: WPARAM) -> u16 { return cast(u16)((cast(u32)wParam >> 16) & 0xffff); } -HIWORD :: proc(lParam: LPARAM) -> u16 { return cast(u16)((cast(u32)lParam >> 16) & 0xffff); } -LOWORD :: proc(wParam: WPARAM) -> u16 { return cast(u16)wParam; } -LOWORD :: proc(lParam: LPARAM) -> u16 { return cast(u16)lParam; } +HIWORD :: proc(wParam: Wparam) -> u16 { return cast(u16)((cast(u32)wParam >> 16) & 0xffff); } +HIWORD :: proc(lParam: Lparam) -> u16 { return cast(u16)((cast(u32)lParam >> 16) & 0xffff); } +LOWORD :: proc(wParam: Wparam) -> u16 { return cast(u16)wParam; } +LOWORD :: proc(lParam: Lparam) -> u16 { return cast(u16)lParam; } @@ -367,7 +366,7 @@ LOWORD :: proc(lParam: LPARAM) -> u16 { return cast(u16)lParam; } -BITMAPINFOHEADER :: struct #ordered { +Bitmap_Info_Header :: struct #ordered { size: u32, width, height: i32, planes, bit_count: i16, @@ -378,33 +377,33 @@ BITMAPINFOHEADER :: struct #ordered { clr_used: u32, clr_important: u32, } -BITMAPINFO :: struct #ordered { - using header: BITMAPINFOHEADER, - colors: [1]RGBQUAD, +Bitmap_Info :: struct #ordered { + using header: Bitmap_Info_Header, + colors: [1]Rgb_Quad, } -RGBQUAD :: struct #ordered { blue, green, red, reserved: byte } +Rgb_Quad :: struct #ordered { blue, green, red, reserved: byte } BI_RGB :: 0; DIB_RGB_COLORS :: 0x00; SRCCOPY: u32 : 0x00cc0020; -StretchDIBits :: proc (hdc: HDC, +StretchDIBits :: proc (hdc: Hdc, x_dst, y_dst, width_dst, height_dst: i32, x_src, y_src, width_src, header_src: i32, - bits: rawptr, bits_info: ^BITMAPINFO, + bits: rawptr, bits_info: ^Bitmap_Info, usage: u32, rop: u32) -> i32 #foreign gdi32; -LoadLibraryA :: proc (c_str: ^u8) -> HMODULE #foreign kernel32; -FreeLibrary :: proc (h: HMODULE) #foreign kernel32; -GetProcAddress :: proc (h: HMODULE, c_str: ^u8) -> PROC #foreign kernel32; +LoadLibraryA :: proc (c_str: ^u8) -> Hmodule #foreign kernel32; +FreeLibrary :: proc (h: Hmodule) #foreign kernel32; +GetProcAddress :: proc (h: Hmodule, c_str: ^u8) -> Proc #foreign kernel32; -GetClientRect :: proc(hwnd: HWND, rect: ^RECT) -> BOOL #foreign user32; +GetClientRect :: proc(hwnd: Hwnd, rect: ^Rect) -> Bool #foreign user32; // Windows OpenGL PFD_TYPE_RGBA :: 0; @@ -461,14 +460,14 @@ PIXELFORMATDESCRIPTOR :: struct #ordered { damage_mask: u32, } -GetDC :: proc(h: HWND) -> HDC #foreign user32; -SetPixelFormat :: proc(hdc: HDC, pixel_format: i32, pfd: ^PIXELFORMATDESCRIPTOR) -> BOOL #foreign gdi32; -ChoosePixelFormat :: proc(hdc: HDC, pfd: ^PIXELFORMATDESCRIPTOR) -> i32 #foreign gdi32; -SwapBuffers :: proc(hdc: HDC) -> BOOL #foreign gdi32; -ReleaseDC :: proc(wnd: HWND, hdc: HDC) -> i32 #foreign user32; +GetDC :: proc(h: Hwnd) -> Hdc #foreign user32; +SetPixelFormat :: proc(hdc: Hdc, pixel_format: i32, pfd: ^PIXELFORMATDESCRIPTOR) -> Bool #foreign gdi32; +ChoosePixelFormat :: proc(hdc: Hdc, pfd: ^PIXELFORMATDESCRIPTOR) -> i32 #foreign gdi32; +SwapBuffers :: proc(hdc: Hdc) -> Bool #foreign gdi32; +ReleaseDC :: proc(wnd: Hwnd, hdc: Hdc) -> i32 #foreign user32; -PROC :: #type proc() #cc_c; +Proc :: #type proc() #cc_c; GetKeyState :: proc(v_key: i32) -> i16 #foreign user32; @@ -611,7 +610,7 @@ Key_Code :: enum i32 { RCONTROL = 0xA3, LMENU = 0xA4, RMENU = 0xA5, - PROCESSKEY = 0xE5, + ProcESSKEY = 0xE5, ATTN = 0xF6, CRSEL = 0xF7, EXSEL = 0xF8, diff --git a/src/check_decl.c b/src/check_decl.c index bc49e36c1..a89460123 100644 --- a/src/check_decl.c +++ b/src/check_decl.c @@ -408,6 +408,56 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count } +void check_alias_decl(Checker *c, Entity *e, AstNode *expr) { + GB_ASSERT(e->type == NULL); + GB_ASSERT(e->kind == Entity_Alias); + + if (e->flags & EntityFlag_Visited) { + e->type = t_invalid; + return; + } + e->flags |= EntityFlag_Visited; + e->type = t_invalid; + + expr = unparen_expr(expr); + + if (expr->kind == AstNode_Alias) { + error_node(expr, "#alias of an #alias is not allowed"); + return; + } + + if (expr->kind == AstNode_Ident) { + Operand o = {0}; + Entity *f = check_ident(c, &o, expr, NULL, NULL, true); + if (f != NULL) { + e->Alias.original = f; + e->type = f->type; + } + return; + } else if (expr->kind == AstNode_SelectorExpr) { + Operand o = {0}; + Entity *f = check_selector(c, &o, expr, NULL); + if (f != NULL) { + e->Alias.original = f; + e->type = f->type; + } + return; + } + + Operand o = {0}; + check_expr_or_type(c, &o, expr); + if (o.mode == Addressing_Invalid) { + return; + } + switch (o.mode) { + case Addressing_Type: + e->type = o.type; + break; + default: + error_node(expr, "#alias declarations only allow types"); + } +} + void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) { if (e->type != NULL) { return; @@ -443,6 +493,9 @@ void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) { case Entity_Procedure: check_proc_lit(c, e, d); break; + case Entity_Alias: + check_alias_decl(c, e, d->init_expr); + break; } c->context = prev; diff --git a/src/check_expr.c b/src/check_expr.c index 3f6e591c0..75105462b 100644 --- a/src/check_expr.c +++ b/src/check_expr.c @@ -1028,7 +1028,7 @@ void check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node) { } -void check_ident(Checker *c, Operand *o, AstNode *n, Type *named_type, Type *type_hint) { +Entity *check_ident(Checker *c, Operand *o, AstNode *n, Type *named_type, Type *type_hint, bool allow_import_name) { GB_ASSERT(n->kind == AstNode_Ident); o->mode = Addressing_Invalid; o->expr = n; @@ -1046,7 +1046,7 @@ void check_ident(Checker *c, Operand *o, AstNode *n, Type *named_type, Type *typ if (named_type != NULL) { set_base_type(named_type, t_invalid); } - return; + return NULL; } bool is_overloaded = false; @@ -1095,7 +1095,7 @@ void check_ident(Checker *c, Operand *o, AstNode *n, Type *named_type, Type *typ o->type = t_invalid; o->overload_count = overload_count; o->overload_entities = procs; - return; + return NULL; } gb_free(heap_allocator(), procs); } @@ -1106,20 +1106,26 @@ void check_ident(Checker *c, Operand *o, AstNode *n, Type *named_type, Type *typ if (e->type == NULL) { compiler_error("Compiler error: How did this happen? type: %s; identifier: %.*s\n", type_to_string(e->type), LIT(name)); - return; + return NULL; + } + + e->flags |= EntityFlag_Used; + + Entity *original_e = e; + while (e->kind == Entity_Alias && e->Alias.original != NULL) { + e = e->Alias.original; } Type *type = e->type; - switch (e->kind) { case Entity_Constant: if (type == t_invalid) { o->type = t_invalid; - return; + return e; } o->value = e->Constant.value; if (o->value.kind == ExactValue_Invalid) { - return; + return e; } o->mode = Addressing_Constant; break; @@ -1128,7 +1134,7 @@ void check_ident(Checker *c, Operand *o, AstNode *n, Type *named_type, Type *typ e->flags |= EntityFlag_Used; if (type == t_invalid) { o->type = t_invalid; - return; + return e; } o->mode = Addressing_Variable; if (e->Variable.is_immutable) { @@ -1151,22 +1157,25 @@ void check_ident(Checker *c, Operand *o, AstNode *n, Type *named_type, Type *typ break; case Entity_ImportName: - error_node(n, "Use of import `%.*s` not in selector", LIT(e->ImportName.name)); - return; + if (!allow_import_name) { + error_node(n, "Use of import `%.*s` not in selector", LIT(name)); + } + return e; case Entity_LibraryName: - error_node(n, "Use of library `%.*s` not in #foreign tag", LIT(e->LibraryName.name)); - return; + error_node(n, "Use of library `%.*s` not in #foreign tag", LIT(name)); + return e; case Entity_Nil: o->mode = Addressing_Value; break; default: - compiler_error("Compiler error: Unknown EntityKind"); + compiler_error("Unknown EntityKind"); break; } o->type = type; + return e; } i64 check_array_or_map_count(Checker *c, AstNode *e, bool is_map) { @@ -1342,7 +1351,7 @@ Type *check_type_extra(Checker *c, AstNode *e, Type *named_type) { switch (e->kind) { case_ast_node(i, Ident, e); Operand o = {0}; - check_ident(c, &o, e, named_type, NULL); + check_ident(c, &o, e, named_type, NULL, false); switch (o.mode) { case Addressing_Invalid: @@ -2679,6 +2688,11 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h add_entity_use(c, op_expr, e); expr_entity = e; + Entity *original_e = e; + while (e->kind == Entity_Alias && e->Alias.original != NULL) { + e = e->Alias.original; + } + if (e != NULL && e->kind == Entity_ImportName && selector->kind == AstNode_Ident) { // IMPORTANT NOTE(bill): This is very sloppy code but it's also very fragile // It pretty much needs to be in this order and this way @@ -4413,7 +4427,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint case_end; case_ast_node(i, Ident, node); - check_ident(c, o, node, NULL, type_hint); + check_ident(c, o, node, NULL, type_hint, false); case_end; case_ast_node(bl, BasicLit, node); @@ -5626,7 +5640,7 @@ gbString write_expr_to_string(gbString str, AstNode *node) { case_end; case_ast_node(ht, HelperType, node); - str = gb_string_appendc(str, "type "); + str = gb_string_appendc(str, "#type "); str = write_expr_to_string(str, ht->type); case_end; } diff --git a/src/checker.c b/src/checker.c index 2e2eceefc..881e86c8b 100644 --- a/src/checker.c +++ b/src/checker.c @@ -816,7 +816,7 @@ bool add_entity(Checker *c, Scope *scope, AstNode *identifier, Entity *entity) { return false; } error(entity->token, - "Redeclararation of `%.*s` in this scope through `using`\n" + "Redeclaration of `%.*s` in this scope through `using`\n" "\tat %.*s(%td:%td)", LIT(name), LIT(up->token.pos.file), up->token.pos.line, up->token.pos.column); @@ -827,7 +827,7 @@ bool add_entity(Checker *c, Scope *scope, AstNode *identifier, Entity *entity) { return false; } error(entity->token, - "Redeclararation of `%.*s` in this scope\n" + "Redeclaration of `%.*s` in this scope\n" "\tat %.*s(%td:%td)", LIT(name), LIT(pos.file), pos.line, pos.column); @@ -1467,7 +1467,12 @@ void check_collect_entities(Checker *c, AstNodeArray nodes, bool is_file_scope) // TODO(bill): What if vd->type != NULL??? How to handle this case? d->type_expr = init; d->init_expr = init; - } else if (init != NULL && up_init->kind == AstNode_ProcLit) { + } else if (up_init != NULL && up_init->kind == AstNode_Alias) { + error_node(up_init, "#alias declarations are not yet supported"); + continue; + // e = make_entity_alias(c->allocator, d->scope, name->Ident, NULL, NULL); + // d->init_expr = init->Alias.expr; + }else if (init != NULL && up_init->kind == AstNode_ProcLit) { e = make_entity_procedure(c->allocator, d->scope, name->Ident, NULL, up_init->ProcLit.tags); d->proc_lit = up_init; d->type_expr = vd->type; diff --git a/src/entity.c b/src/entity.c index 32d070953..446edfa54 100644 --- a/src/entity.c +++ b/src/entity.c @@ -13,6 +13,7 @@ typedef struct Type Type; ENTITY_KIND(Builtin) \ ENTITY_KIND(ImportName) \ ENTITY_KIND(LibraryName) \ + ENTITY_KIND(Alias) \ ENTITY_KIND(Nil) \ ENTITY_KIND(Count) @@ -95,6 +96,9 @@ struct Entity { String name; bool used; } LibraryName; + struct { + Entity *original; + } Alias; i32 Nil; }; }; @@ -218,6 +222,13 @@ Entity *make_entity_library_name(gbAllocator a, Scope *scope, Token token, Type return entity; } +Entity *make_entity_alias(gbAllocator a, Scope *scope, Token token, Type *type, + Entity *original) { + Entity *entity = alloc_entity(a, Entity_Alias, scope, token, type); + entity->Alias.original = original; + return entity; +} + Entity *make_entity_nil(gbAllocator a, String name, Type *type) { Token token = make_token_ident(name); Entity *entity = alloc_entity(a, Entity_Nil, NULL, token, type); diff --git a/src/gb/gb.h b/src/gb/gb.h index d30e5d129..9a665e050 100644 --- a/src/gb/gb.h +++ b/src/gb/gb.h @@ -806,6 +806,10 @@ GB_DEF void const *gb_memchr (void const *data, u8 byte_value, isize size); GB_DEF void const *gb_memrchr (void const *data, u8 byte_value, isize size); +#ifndef gb_memcopy_array +#define gb_memcopy_array(dst, src, count) gb_memcopy((dst), (src), gb_size_of(*(dst))*(count)) +#endif + // NOTE(bill): Very similar to doing `*cast(T *)(&u)` #ifndef GB_BIT_CAST #define GB_BIT_CAST(dest, source) do { \ diff --git a/src/ir.c b/src/ir.c index a5bb58111..44f24d5d6 100644 --- a/src/ir.c +++ b/src/ir.c @@ -2916,8 +2916,21 @@ irValue *ir_find_global_variable(irProcedure *proc, String name) { void ir_build_stmt_list(irProcedure *proc, AstNodeArray stmts); -irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv) { + +irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { expr = unparen_expr(expr); + + TypeAndValue *tv = map_tav_get(&proc->module->info->types, hash_pointer(expr)); + GB_ASSERT_NOT_NULL(tv); + + if (tv->value.kind != ExactValue_Invalid) { + return ir_add_module_constant(proc->module, tv->type, tv->value); + } + + if (tv->mode == Addressing_Variable) { + return ir_addr_load(proc, ir_build_addr(proc, expr)); + } + switch (expr->kind) { case_ast_node(bl, BasicLit, expr); TokenPos pos = bl->pos; @@ -3782,27 +3795,6 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv return NULL; } - -irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { - expr = unparen_expr(expr); - - TypeAndValue *tv = map_tav_get(&proc->module->info->types, hash_pointer(expr)); - GB_ASSERT_NOT_NULL(tv); - - if (tv->value.kind != ExactValue_Invalid) { - return ir_add_module_constant(proc->module, tv->type, tv->value); - } - - irValue *value = NULL; - if (tv->mode == Addressing_Variable) { - value = ir_addr_load(proc, ir_build_addr(proc, expr)); - } else { - value = ir_build_single_expr(proc, expr, tv); - } - - return value; -} - irValue *ir_get_using_variable(irProcedure *proc, Entity *e) { GB_ASSERT(e->kind == Entity_Variable && e->flags & EntityFlag_Anonymous); String name = e->token.string; @@ -5192,9 +5184,9 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) { if (fs->cond != NULL) { loop = ir_new_block(proc, node, "for.loop"); } - irBlock *cont = loop; + irBlock *post = loop; if (fs->post != NULL) { - cont = ir_new_block(proc, node, "for.post"); + post = ir_new_block(proc, node, "for.post"); } ir_emit_jump(proc, loop); ir_start_block(proc, loop); @@ -5204,7 +5196,7 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) { ir_start_block(proc, body); } - ir_push_target_list(proc, done, cont, NULL); + ir_push_target_list(proc, done, post, NULL); ir_open_scope(proc); ir_build_stmt(proc, fs->body); @@ -5212,10 +5204,10 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) { ir_pop_target_list(proc); - ir_emit_jump(proc, cont); + ir_emit_jump(proc, post); if (fs->post != NULL) { - ir_start_block(proc, cont); + ir_start_block(proc, post); ir_build_stmt(proc, fs->post); ir_emit_jump(proc, loop); } @@ -5646,7 +5638,7 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) { case_end; - case_ast_node(pa, PushContext, node); + case_ast_node(pc, PushContext, node); ir_emit_comment(proc, str_lit("PushContext")); ir_open_scope(proc); @@ -5656,9 +5648,9 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) { ir_add_defer_instr(proc, proc->scope_index, ir_instr_store(proc, context_ptr, ir_emit_load(proc, prev_context))); - ir_emit_store(proc, context_ptr, ir_build_expr(proc, pa->expr)); + ir_emit_store(proc, context_ptr, ir_build_expr(proc, pc->expr)); - ir_build_stmt(proc, pa->body); + ir_build_stmt(proc, pc->body); ir_close_scope(proc, irDeferExit_Default, NULL); case_end; diff --git a/src/parser.c b/src/parser.c index 160b72ef3..2905489d6 100644 --- a/src/parser.c +++ b/src/parser.c @@ -139,6 +139,10 @@ AstNodeArray make_ast_node_array(AstFile *f) { AstNodeArray elems; \ Token open, close; \ }) \ + AST_NODE_KIND(Alias, "alias", struct { \ + Token token; \ + AstNode *expr; \ + }) \ AST_NODE_KIND(_ExprBegin, "", i32) \ AST_NODE_KIND(BadExpr, "bad expression", struct { Token begin, end; }) \ AST_NODE_KIND(TagExpr, "tag expression", struct { Token token, name; AstNode *expr; }) \ @@ -445,6 +449,8 @@ Token ast_node_token(AstNode *node) { return ast_node_token(node->CompoundLit.type); } return node->CompoundLit.open; + case AstNode_Alias: return node->Alias.token; + case AstNode_TagExpr: return node->TagExpr.token; case AstNode_RunExpr: return node->RunExpr.token; case AstNode_BadExpr: return node->BadExpr.begin; @@ -771,6 +777,13 @@ AstNode *ast_compound_lit(AstFile *f, AstNode *type, AstNodeArray elems, Token o result->CompoundLit.close = close; return result; } +AstNode *ast_alias(AstFile *f, Token token, AstNode *expr) { + AstNode *result = make_ast_node(f, AstNode_Alias); + result->Alias.token = token; + result->Alias.expr = expr; + return result; +} + AstNode *ast_ternary_expr(AstFile *f, AstNode *cond, AstNode *x, AstNode *y) { AstNode *result = make_ast_node(f, AstNode_TernaryExpr); @@ -1762,6 +1775,7 @@ AstNode *parse_operand(AstFile *f, bool lhs) { } else if (str_eq(name.string, str_lit("line"))) { return ast_basic_directive(f, token, name.string); } else if (str_eq(name.string, str_lit("procedure"))) { return ast_basic_directive(f, token, name.string); } else if (str_eq(name.string, str_lit("type"))) { return ast_helper_type(f, token, parse_type(f)); + } else if (!lhs && str_eq(name.string, str_lit("alias"))) { return ast_alias(f, token, parse_expr(f, false)); } else { operand = ast_tag_expr(f, token, name, parse_expr(f, false)); } diff --git a/src/ssa.c b/src/ssa.c index 2448ffdd9..7bccf027d 100644 --- a/src/ssa.c +++ b/src/ssa.c @@ -1,12 +1,13 @@ -typedef enum ssaOp ssaOp; -typedef struct ssaModule ssaModule; -typedef struct ssaValue ssaValue; -typedef struct ssaBlock ssaBlock; -typedef struct ssaProc ssaProc; -typedef struct ssaEdge ssaEdge; -typedef struct ssaRegister ssaRegister; -typedef enum ssaBlockKind ssaBlockKind; -typedef enum ssaBranchPrediction ssaBranchPrediction; +typedef enum ssaOp ssaOp; +typedef struct ssaModule ssaModule; +typedef struct ssaValue ssaValue; +typedef struct ssaBlock ssaBlock; +typedef struct ssaProc ssaProc; +typedef struct ssaEdge ssaEdge; +typedef struct ssaRegister ssaRegister; +typedef struct ssaTargetList ssaTargetList; +typedef enum ssaBlockKind ssaBlockKind; +typedef enum ssaBranchPrediction ssaBranchPrediction; String ssa_mangle_name(ssaModule *m, String path, Entity *e); @@ -17,265 +18,280 @@ String ssa_mangle_name(ssaModule *m, String path, Entity *e); typedef Array(ssaValue *) ssaValueArray; + +#define SSA_OPS \ + SSA_OP(Invalid)\ +\ + SSA_OP(Unknown)\ +\ + SSA_OP(Comment) /* Does nothing */\ +\ + SSA_OP(SP) /* Stack Pointer */\ + SSA_OP(SB) /* Stack Base */\ + SSA_OP(Addr) /* Address of something - special rules for certain types when loading and storing (e.g. Maps) */\ +\ + SSA_OP(Local)\ + SSA_OP(Global)\ + SSA_OP(Proc)\ +\ + SSA_OP(Load)\ + SSA_OP(Store)\ + SSA_OP(Move)\ + SSA_OP(Zero) /* Zero initialize */\ +\ + SSA_OP(ArrayIndex) /* Index for a fixed array */\ + SSA_OP(PtrIndex) /* Index for a struct/tuple/etc */\ + SSA_OP(OffsetPtr)\ + SSA_OP(ValueIndex) /* Extract for a value from a register */\ +\ + SSA_OP(Phi)\ + SSA_OP(Copy)\ +\ + /* TODO(bill): calling conventions */\ + SSA_OP(CallOdin)\ + SSA_OP(CallC)\ + SSA_OP(CallStd)\ + SSA_OP(CallFast)\ +\ + SSA_OP(BoundsCheck)\ + SSA_OP(SliceBoundsCheck)\ +\ + /* Built in operations/procedures */\ + SSA_OP(Bswap16)\ + SSA_OP(Bswap32)\ + SSA_OP(Bswap64)\ +\ + SSA_OP(Assume)\ + SSA_OP(DebugTrap)\ + SSA_OP(Trap)\ + SSA_OP(ReadCycleCounter)\ +\ +\ + SSA_OP(ConstBool)\ + SSA_OP(ConstString)\ + SSA_OP(ConstSlice)\ + SSA_OP(ConstNil)\ + SSA_OP(Const8)\ + SSA_OP(Const16)\ + SSA_OP(Const32)\ + SSA_OP(Const64)\ + SSA_OP(Const32F)\ + SSA_OP(Const64F)\ +\ + /* These should be all the operations I could possibly need for the mean time */\ + SSA_OP(Add8)\ + SSA_OP(Add16)\ + SSA_OP(Add32)\ + SSA_OP(Add64)\ + SSA_OP(AddPtr)\ + SSA_OP(Add32F)\ + SSA_OP(Add64F)\ + SSA_OP(Sub8)\ + SSA_OP(Sub16)\ + SSA_OP(Sub32)\ + SSA_OP(Sub64)\ + SSA_OP(SubPtr)\ + SSA_OP(Sub32F)\ + SSA_OP(Sub64F)\ + SSA_OP(Mul8)\ + SSA_OP(Mul16)\ + SSA_OP(Mul32)\ + SSA_OP(Mul64)\ + SSA_OP(Mul32F)\ + SSA_OP(Mul64F)\ + SSA_OP(Div8)\ + SSA_OP(Div8U)\ + SSA_OP(Div16)\ + SSA_OP(Div16U)\ + SSA_OP(Div32)\ + SSA_OP(Div32U)\ + SSA_OP(Div64)\ + SSA_OP(Div64U)\ + SSA_OP(Div32F)\ + SSA_OP(Div64F)\ + SSA_OP(Mod8)\ + SSA_OP(Mod8U)\ + SSA_OP(Mod16)\ + SSA_OP(Mod16U)\ + SSA_OP(Mod32)\ + SSA_OP(Mod32U)\ + SSA_OP(Mod64)\ + SSA_OP(Mod64U)\ +\ + SSA_OP(And8)\ + SSA_OP(And16)\ + SSA_OP(And32)\ + SSA_OP(And64)\ + SSA_OP(Or8)\ + SSA_OP(Or16)\ + SSA_OP(Or32)\ + SSA_OP(Or64)\ + SSA_OP(Xor8)\ + SSA_OP(Xor16)\ + SSA_OP(Xor32)\ + SSA_OP(Xor64)\ + SSA_OP(AndNot8)\ + SSA_OP(AndNot16)\ + SSA_OP(AndNot32)\ + SSA_OP(AndNot64)\ +\ + SSA_OP(Lsh8x8)\ + SSA_OP(Lsh8x16)\ + SSA_OP(Lsh8x32)\ + SSA_OP(Lsh8x64)\ + SSA_OP(Lsh16x8)\ + SSA_OP(Lsh16x16)\ + SSA_OP(Lsh16x32)\ + SSA_OP(Lsh16x64)\ + SSA_OP(Lsh32x8)\ + SSA_OP(Lsh32x16)\ + SSA_OP(Lsh32x32)\ + SSA_OP(Lsh32x64)\ + SSA_OP(Lsh64x8)\ + SSA_OP(Lsh64x16)\ + SSA_OP(Lsh64x32)\ + SSA_OP(Lsh64x64)\ + SSA_OP(Rsh8x8)\ + SSA_OP(Rsh8x16)\ + SSA_OP(Rsh8x32)\ + SSA_OP(Rsh8x64)\ + SSA_OP(Rsh16x8)\ + SSA_OP(Rsh16x16)\ + SSA_OP(Rsh16x32)\ + SSA_OP(Rsh16x64)\ + SSA_OP(Rsh32x8)\ + SSA_OP(Rsh32x16)\ + SSA_OP(Rsh32x32)\ + SSA_OP(Rsh32x64)\ + SSA_OP(Rsh64x8)\ + SSA_OP(Rsh64x16)\ + SSA_OP(Rsh64x32)\ + SSA_OP(Rsh64x64)\ + SSA_OP(Rsh8Ux8)\ + SSA_OP(Rsh8Ux16)\ + SSA_OP(Rsh8Ux32)\ + SSA_OP(Rsh8Ux64)\ + SSA_OP(Rsh16Ux8)\ + SSA_OP(Rsh16Ux16)\ + SSA_OP(Rsh16Ux32)\ + SSA_OP(Rsh16Ux64)\ + SSA_OP(Rsh32Ux8)\ + SSA_OP(Rsh32Ux16)\ + SSA_OP(Rsh32Ux32)\ + SSA_OP(Rsh32Ux64)\ + SSA_OP(Rsh64Ux8)\ + SSA_OP(Rsh64Ux16)\ + SSA_OP(Rsh64Ux32)\ + SSA_OP(Rsh64Ux64)\ +\ + SSA_OP(Eq8)\ + SSA_OP(Eq16)\ + SSA_OP(Eq32)\ + SSA_OP(Eq64)\ + SSA_OP(EqPtr)\ + SSA_OP(Eq32F)\ + SSA_OP(Eq64F)\ + SSA_OP(Ne8)\ + SSA_OP(Ne16)\ + SSA_OP(Ne32)\ + SSA_OP(Ne64)\ + SSA_OP(NePtr)\ + SSA_OP(Ne32F)\ + SSA_OP(Ne64F)\ + SSA_OP(Lt8)\ + SSA_OP(Lt16)\ + SSA_OP(Lt32)\ + SSA_OP(Lt64)\ + SSA_OP(LtPtr)\ + SSA_OP(Lt32F)\ + SSA_OP(Lt64F)\ + SSA_OP(Gt8)\ + SSA_OP(Gt16)\ + SSA_OP(Gt32)\ + SSA_OP(Gt64)\ + SSA_OP(GtPtr)\ + SSA_OP(Gt32F)\ + SSA_OP(Gt64F)\ + SSA_OP(Le8)\ + SSA_OP(Le16)\ + SSA_OP(Le32)\ + SSA_OP(Le64)\ + SSA_OP(LePtr)\ + SSA_OP(Le32F)\ + SSA_OP(Le64F)\ + SSA_OP(Ge8)\ + SSA_OP(Ge16)\ + SSA_OP(Ge32)\ + SSA_OP(Ge64)\ + SSA_OP(GePtr)\ + SSA_OP(Ge32F)\ + SSA_OP(Ge64F)\ +\ + SSA_OP(NotB)\ + SSA_OP(EqB)\ + SSA_OP(NeB)\ +\ + SSA_OP(Neg8)\ + SSA_OP(Neg16)\ + SSA_OP(Neg32)\ + SSA_OP(Neg64)\ + SSA_OP(Neg32F)\ + SSA_OP(Neg64F)\ +\ + SSA_OP(Not8)\ + SSA_OP(Not16)\ + SSA_OP(Not32)\ + SSA_OP(Not64)\ +\ + SSA_OP(SignExt8to16)\ + SSA_OP(SignExt8to32)\ + SSA_OP(SignExt8to64)\ + SSA_OP(SignExt16to32)\ + SSA_OP(SignExt16to64)\ + SSA_OP(SignExt32to64)\ + SSA_OP(ZeroExt8to16)\ + SSA_OP(ZeroExt8to32)\ + SSA_OP(ZeroExt8to64)\ + SSA_OP(ZeroExt16to32)\ + SSA_OP(ZeroExt16to64)\ + SSA_OP(ZeroExt32to64)\ + SSA_OP(Trunc16to8)\ + SSA_OP(Trunc32to8)\ + SSA_OP(Trunc32to16)\ + SSA_OP(Trunc64to8)\ + SSA_OP(Trunc64to16)\ + SSA_OP(Trunc64to32)\ +\ + SSA_OP(Cvt32to32F)\ + SSA_OP(Cvt32to64F)\ + SSA_OP(Cvt64to32F)\ + SSA_OP(Cvt64to64F)\ + SSA_OP(Cvt32Fto32)\ + SSA_OP(Cvt32Fto64)\ + SSA_OP(Cvt64Fto32)\ + SSA_OP(Cvt64Fto64)\ + SSA_OP(Cvt32Fto64F)\ + SSA_OP(Cvt64Fto32F)\ + SSA_OP(Cvt32Uto32F)\ + SSA_OP(Cvt32Uto64F)\ + SSA_OP(Cvt32Fto32U)\ + SSA_OP(Cvt64Fto32U)\ + SSA_OP(Cvt64Uto32F)\ + SSA_OP(Cvt64Uto64F)\ + SSA_OP(Cvt32Fto64U)\ + SSA_OP(Cvt64Fto64U)\ + + enum ssaOp { - ssaOp_Invalid, +#define SSA_OP(k) GB_JOIN2(ssaOp_, k), + SSA_OPS +#undef SSA_OP +}; - ssaOp_Unknown, - - ssaOp_Comment, // Does nothing - - ssaOp_SP, // Stack Pointer - ssaOp_SB, // Stack Base - ssaOp_Addr, // Address of something - special rules for certain types when loading and storing (e.g. Maps) - - ssaOp_Local, - ssaOp_Global, - ssaOp_Proc, - - ssaOp_Load, - ssaOp_Store, - ssaOp_Move, - ssaOp_Zero, // Zero initialize - - ssaOp_ArrayIndex, // Index for a fixed array - ssaOp_PtrIndex, // Index for a struct/tuple/etc - ssaOp_OffsetPtr, - ssaOp_ValueIndex, // Extract for a value from a register - - ssaOp_Phi, - ssaOp_Copy, - - // TODO(bill): calling conventions - ssaOp_CallOdin, - ssaOp_CallC, - ssaOp_CallStd, - ssaOp_CallFast, - - ssaOp_BoundsCheck, - ssaOp_SliceBoundsCheck, - - // Built in operations/procedures - ssaOp_Bswap16, - ssaOp_Bswap32, - ssaOp_Bswap64, - - ssaOp_Assume, - ssaOp_DebugTrap, - ssaOp_Trap, - ssaOp_ReadCycleCounter, - - - ssaOp_ConstBool, - ssaOp_ConstString, - ssaOp_ConstSlice, - ssaOp_ConstNil, - ssaOp_Const8, - ssaOp_Const16, - ssaOp_Const32, - ssaOp_Const64, - ssaOp_Const32F, - ssaOp_Const64F, - - // These should be all the operations I could possibly need for the mean time - ssaOp_Add8, - ssaOp_Add16, - ssaOp_Add32, - ssaOp_Add64, - ssaOp_AddPtr, - ssaOp_Add32F, - ssaOp_Add64F, - ssaOp_Sub8, - ssaOp_Sub16, - ssaOp_Sub32, - ssaOp_Sub64, - ssaOp_SubPtr, - ssaOp_Sub32F, - ssaOp_Sub64F, - ssaOp_Mul8, - ssaOp_Mul16, - ssaOp_Mul32, - ssaOp_Mul64, - ssaOp_Mul32F, - ssaOp_Mul64F, - ssaOp_Div8, - ssaOp_Div8U, - ssaOp_Div16, - ssaOp_Div16U, - ssaOp_Div32, - ssaOp_Div32U, - ssaOp_Div64, - ssaOp_Div64U, - ssaOp_Div32F, - ssaOp_Div64F, - ssaOp_Mod8, - ssaOp_Mod8U, - ssaOp_Mod16, - ssaOp_Mod16U, - ssaOp_Mod32, - ssaOp_Mod32U, - ssaOp_Mod64, - ssaOp_Mod64U, - - ssaOp_And8, - ssaOp_And16, - ssaOp_And32, - ssaOp_And64, - ssaOp_Or8, - ssaOp_Or16, - ssaOp_Or32, - ssaOp_Or64, - ssaOp_Xor8, - ssaOp_Xor16, - ssaOp_Xor32, - ssaOp_Xor64, - - ssaOp_Lsh8x8, - ssaOp_Lsh8x16, - ssaOp_Lsh8x32, - ssaOp_Lsh8x64, - ssaOp_Lsh16x8, - ssaOp_Lsh16x16, - ssaOp_Lsh16x32, - ssaOp_Lsh16x64, - ssaOp_Lsh32x8, - ssaOp_Lsh32x16, - ssaOp_Lsh32x32, - ssaOp_Lsh32x64, - ssaOp_Lsh64x8, - ssaOp_Lsh64x16, - ssaOp_Lsh64x32, - ssaOp_Lsh64x64, - ssaOp_Rsh8x8, - ssaOp_Rsh8x16, - ssaOp_Rsh8x32, - ssaOp_Rsh8x64, - ssaOp_Rsh16x8, - ssaOp_Rsh16x16, - ssaOp_Rsh16x32, - ssaOp_Rsh16x64, - ssaOp_Rsh32x8, - ssaOp_Rsh32x16, - ssaOp_Rsh32x32, - ssaOp_Rsh32x64, - ssaOp_Rsh64x8, - ssaOp_Rsh64x16, - ssaOp_Rsh64x32, - ssaOp_Rsh64x64, - ssaOp_Rsh8Ux8, - ssaOp_Rsh8Ux16, - ssaOp_Rsh8Ux32, - ssaOp_Rsh8Ux64, - ssaOp_Rsh16Ux8, - ssaOp_Rsh16Ux16, - ssaOp_Rsh16Ux32, - ssaOp_Rsh16Ux64, - ssaOp_Rsh32Ux8, - ssaOp_Rsh32Ux16, - ssaOp_Rsh32Ux32, - ssaOp_Rsh32Ux64, - ssaOp_Rsh64Ux8, - ssaOp_Rsh64Ux16, - ssaOp_Rsh64Ux32, - ssaOp_Rsh64Ux64, - - ssaOp_Eq8, - ssaOp_Eq16, - ssaOp_Eq32, - ssaOp_Eq64, - ssaOp_EqPtr, - ssaOp_Eq32F, - ssaOp_Eq64F, - ssaOp_Ne8, - ssaOp_Ne16, - ssaOp_Ne32, - ssaOp_Ne64, - ssaOp_NePtr, - ssaOp_Ne32F, - ssaOp_Ne64F, - ssaOp_Lt8, - ssaOp_Lt16, - ssaOp_Lt32, - ssaOp_Lt64, - ssaOp_LtPtr, - ssaOp_Lt32F, - ssaOp_Lt64F, - ssaOp_Gt8, - ssaOp_Gt16, - ssaOp_Gt32, - ssaOp_Gt64, - ssaOp_GtPtr, - ssaOp_Gt32F, - ssaOp_Gt64F, - ssaOp_Le8, - ssaOp_Le16, - ssaOp_Le32, - ssaOp_Le64, - ssaOp_LePtr, - ssaOp_Le32F, - ssaOp_Le64F, - ssaOp_Ge8, - ssaOp_Ge16, - ssaOp_Ge32, - ssaOp_Ge64, - ssaOp_GePtr, - ssaOp_Ge32F, - ssaOp_Ge64F, - - ssaOp_NotB, - ssaOp_EqB, - ssaOp_NeB, - - ssaOp_Neg8, - ssaOp_Neg16, - ssaOp_Neg32, - ssaOp_Neg64, - ssaOp_Neg32F, - ssaOp_Neg64F, - - ssaOp_Not8, - ssaOp_Not16, - ssaOp_Not32, - ssaOp_Not64, - - ssaOp_SignExt8to16, - ssaOp_SignExt8to32, - ssaOp_SignExt8to64, - ssaOp_SignExt16to32, - ssaOp_SignExt16to64, - ssaOp_SignExt32to64, - ssaOp_ZeroExt8to16, - ssaOp_ZeroExt8to32, - ssaOp_ZeroExt8to64, - ssaOp_ZeroExt16to32, - ssaOp_ZeroExt16to64, - ssaOp_ZeroExt32to64, - ssaOp_Trunc16to8, - ssaOp_Trunc32to8, - ssaOp_Trunc32to16, - ssaOp_Trunc64to8, - ssaOp_Trunc64to16, - ssaOp_Trunc64to32, - - ssaOp_Cvt32to32F, - ssaOp_Cvt32to64F, - ssaOp_Cvt64to32F, - ssaOp_Cvt64to64F, - ssaOp_Cvt32Fto32, - ssaOp_Cvt32Fto64, - ssaOp_Cvt64Fto32, - ssaOp_Cvt64Fto64, - ssaOp_Cvt32Fto64F, - ssaOp_Cvt64Fto32F, - ssaOp_Cvt32Uto32F, - ssaOp_Cvt32Uto64F, - ssaOp_Cvt32Fto32U, - ssaOp_Cvt64Fto32U, - ssaOp_Cvt64Uto32F, - ssaOp_Cvt64Uto64F, - ssaOp_Cvt32Fto64U, - ssaOp_Cvt64Fto64U, - - ssaOp_Count, +String const ssa_op_strings[] = { +#define SSA_OP(k) {cast(u8 *)#k, gb_size_of(#k)-1}, + SSA_OPS +#undef SSA_OP }; #define SSA_MAX_ARGS 4 @@ -295,6 +311,8 @@ struct ssaValue { ssaValueArray var_args; // Only used in procedure calls as the SSA_MAX_ARGS may be too small ExactValue exact_value; // Used for constants + + String comment_string; }; enum ssaBlockKind { @@ -333,15 +351,29 @@ struct ssaBlock { i32 id; // Unique identifier but the pointer could be used too ssaBlockKind kind; ssaProc * proc; // Containing procedure + String name; // Optional // Likely branch direction ssaBranchPrediction likeliness; + // Determines how a block exits + // It depends on the type of block: + // - BlockIf will be a boolean value + // - BlockExit will be a memory control value + ssaValue *control; + ssaValueArray values; ssaEdgeArray preds; ssaEdgeArray succs; }; +struct ssaTargetList { + ssaTargetList *prev; + ssaBlock * break_; + ssaBlock * continue_; + ssaBlock * fallthrough_; +}; + struct ssaProc { ssaModule * module; // Parent module String name; // Mangled name @@ -350,8 +382,11 @@ struct ssaProc { Array(ssaBlock *) blocks; ssaBlock * entry; // Entry block + ssaBlock * exit; // Exit block ssaBlock * curr_block; + ssaTargetList * target_list; + i32 block_id; i32 value_id; MapSsaValue values; // Key: Entity * @@ -385,14 +420,28 @@ struct ssaModule { }; +void ssa_push_target_list(ssaProc *p, ssaBlock *break_, ssaBlock *continue_, ssaBlock *fallthrough_) { + ssaTargetList *tl = gb_alloc_item(p->module->allocator, ssaTargetList); + tl->prev = p->target_list; + tl->break_ = break_; + tl->continue_ = continue_; + tl->fallthrough_ = fallthrough_; + p->target_list = tl; +} + +void ssa_pop_target_list(ssaProc *p) { + p->target_list = p->target_list->prev; +} - -ssaBlock *ssa_new_block(ssaProc *p, ssaBlockKind kind) { +ssaBlock *ssa_new_block(ssaProc *p, ssaBlockKind kind, char *name) { ssaBlock *b = gb_alloc_item(p->module->allocator, ssaBlock); b->id = p->block_id++; b->kind = kind; b->proc = p; + if (name != NULL || name[0] != 0) { + b->name = make_string_c(name); + } array_init(&b->values, heap_allocator()); array_init(&b->preds, heap_allocator()); @@ -425,7 +474,11 @@ ssaBlock *ssa_end_block(ssaProc *p) { return b; } -void ssa_add_to_edge(ssaBlock *b, ssaBlock *c) { +void ssa_add_edge_to(ssaBlock *b, ssaBlock *c) { + if (b == NULL) { + return; + } + GB_ASSERT(c != NULL); isize i = b->succs.count; isize j = b->preds.count; ssaEdge s = {c, j}; @@ -434,6 +487,37 @@ void ssa_add_to_edge(ssaBlock *b, ssaBlock *c) { array_add(&c->preds, p); } +void ssa_set_control(ssaBlock *b, ssaValue *v) { + if (b->control != NULL) { + b->control->uses--; + } + b->control = v; + if (v != NULL) { + v->uses++; + } +} + +void ssa_emit_jump(ssaProc *p, ssaBlock *edge) { + ssa_add_edge_to(ssa_end_block(p), edge); +} + + +bool ssa_op_uses_var_args(ssaOp op) { + switch (op) { + case ssaOp_CallOdin: + case ssaOp_CallC: + case ssaOp_CallStd: + case ssaOp_CallFast: + return true; + + case ssaOp_Phi: + return true; + } + return false; +} + + + ssaValue *ssa_new_value(ssaProc *p, ssaOp op, Type *t, ssaBlock *b) { ssaValue *v = gb_alloc_item(p->module->allocator, ssaValue); @@ -504,17 +588,44 @@ ssaValue *ssa_const_val(ssaProc *p, ssaOp op, Type *t, ExactValue exact_value) { return ssa_new_value0v(p->curr_block, op, t, exact_value); } -ssaValue *ssa_const_bool (ssaProc *p, Type *t, bool c) { return ssa_const_val(p, ssaOp_ConstBool, t, exact_value_bool(c)); } -ssaValue *ssa_const_i8 (ssaProc *p, Type *t, i8 c) { return ssa_const_val(p, ssaOp_Const8, t, exact_value_integer(cast(i64)c)); } -ssaValue *ssa_const_i16 (ssaProc *p, Type *t, i16 c) { return ssa_const_val(p, ssaOp_Const16, t, exact_value_integer(cast(i64)c)); } -ssaValue *ssa_const_i32 (ssaProc *p, Type *t, i32 c) { return ssa_const_val(p, ssaOp_Const32, t, exact_value_integer(cast(i64)c)); } -ssaValue *ssa_const_i64 (ssaProc *p, Type *t, i64 c) { return ssa_const_val(p, ssaOp_Const64, t, exact_value_integer(cast(i64)c)); } -ssaValue *ssa_const_f32 (ssaProc *p, Type *t, f32 c) { return ssa_const_val(p, ssaOp_Const32F, t, exact_value_float(c)); } -ssaValue *ssa_const_f64 (ssaProc *p, Type *t, f64 c) { return ssa_const_val(p, ssaOp_Const64F, t, exact_value_float(c)); } -ssaValue *ssa_const_string (ssaProc *p, Type *t, String c) { return ssa_const_val(p, ssaOp_ConstString, t, exact_value_string(c)); } -ssaValue *ssa_const_empty_string(ssaProc *p, Type *t) { return ssa_const_val(p, ssaOp_ConstString, t, (ExactValue){0}); } -ssaValue *ssa_const_slice (ssaProc *p, Type *t) { return ssa_const_val(p, ssaOp_ConstSlice, t, (ExactValue){0}); } -ssaValue *ssa_const_nil (ssaProc *p, Type *t) { return ssa_const_val(p, ssaOp_ConstNil, t, (ExactValue){0}); } +ssaValue *ssa_const_bool (ssaProc *p, Type *t, bool c) { return ssa_const_val(p, ssaOp_ConstBool, t, exact_value_bool(c)); } +ssaValue *ssa_const_i8 (ssaProc *p, Type *t, i8 c) { return ssa_const_val(p, ssaOp_Const8, t, exact_value_integer(cast(i64)c)); } +ssaValue *ssa_const_i16 (ssaProc *p, Type *t, i16 c) { return ssa_const_val(p, ssaOp_Const16, t, exact_value_integer(cast(i64)c)); } +ssaValue *ssa_const_i32 (ssaProc *p, Type *t, i32 c) { return ssa_const_val(p, ssaOp_Const32, t, exact_value_integer(cast(i64)c)); } +ssaValue *ssa_const_i64 (ssaProc *p, Type *t, i64 c) { return ssa_const_val(p, ssaOp_Const64, t, exact_value_integer(cast(i64)c)); } +ssaValue *ssa_const_f32 (ssaProc *p, Type *t, f32 c) { return ssa_const_val(p, ssaOp_Const32F, t, exact_value_float(c)); } +ssaValue *ssa_const_f64 (ssaProc *p, Type *t, f64 c) { return ssa_const_val(p, ssaOp_Const64F, t, exact_value_float(c)); } +ssaValue *ssa_const_string (ssaProc *p, Type *t, String c) { return ssa_const_val(p, ssaOp_ConstString, t, exact_value_string(c)); } +ssaValue *ssa_const_empty_string(ssaProc *p, Type *t) { return ssa_const_val(p, ssaOp_ConstString, t, (ExactValue){0}); } +ssaValue *ssa_const_slice (ssaProc *p, Type *t, ExactValue v) { return ssa_const_val(p, ssaOp_ConstSlice, t, v); } +ssaValue *ssa_const_nil (ssaProc *p, Type *t) { return ssa_const_val(p, ssaOp_ConstNil, t, (ExactValue){0}); } + +ssaValue *ssa_const_int(ssaProc *p, Type *t, i64 c) { + switch (8*type_size_of(p->module->allocator, t)) { + case 8: return ssa_const_i8 (p, t, cast(i8)c); + case 16: return ssa_const_i16(p, t, cast(i16)c); + case 32: return ssa_const_i32(p, t, cast(i32)c); + case 64: return ssa_const_i64(p, t, cast(i64)c); + } + GB_PANIC("Unknown int size"); + return NULL; +} + +void ssa_reset_value_args(ssaValue *v) { + if (ssa_op_uses_var_args(v->op)) { + for_array(i, v->var_args) { + v->var_args.e[i]->uses--; + } + v->var_args.count = 0; + } else { + for (isize i = 0; i < v->arg_count; i++) { + v->args[i]->uses--; + } + v->arg_count = 0; + } +} + + bool ssa_is_blank_ident(AstNode *node) { if (node->kind == AstNode_Ident) { @@ -527,6 +638,7 @@ bool ssa_is_blank_ident(AstNode *node) { typedef enum ssaAddrKind { ssaAddr_Default, + ssaAddr_Map, } ssaAddrKind; typedef struct ssaAddr { @@ -543,6 +655,21 @@ ssaAddr ssa_addr(ssaValue *v) { return addr; } +Type *ssa_addr_type(ssaAddr addr) { + if (addr.addr == NULL) { + return NULL; + } + + if (addr.kind == ssaAddr_Map) { + GB_PANIC("TODO: ssa_addr_type"); + return NULL; + } + + Type *t = addr.addr->type; + GB_ASSERT(is_type_pointer(t)); + return type_deref(t); +} + ssaProc *ssa_new_proc(ssaModule *m, String name, Entity *entity, DeclInfo *decl_info) { @@ -559,27 +686,24 @@ ssaProc *ssa_new_proc(ssaModule *m, String name, Entity *entity, DeclInfo *decl_ } ssaAddr ssa_add_local(ssaProc *p, Entity *e, AstNode *expr) { - ssaAddr result = {0}; - Type *t = make_type_pointer(p->module->allocator, e->type); ssaValue *local = ssa_new_value0(p->entry, ssaOp_Local, t); map_ssa_value_set(&p->values, hash_pointer(e), local); map_ssa_value_set(&p->module->values, hash_pointer(e), local); + local->comment_string = e->token.string; ssaValue *addr = ssa_new_value1(p->curr_block, ssaOp_Addr, local->type, local); ssa_new_value1(p->curr_block, ssaOp_Zero, t, addr); - result.addr = addr; - return result; + return ssa_addr(addr); } ssaAddr ssa_add_local_for_ident(ssaProc *p, AstNode *name) { - ssaAddr result = {0}; - Entity **found = map_entity_get(&p->module->info->definitions, hash_pointer(name)); if (found) { Entity *e = *found; return ssa_add_local(p, e, name); } - return result; + + return ssa_addr(NULL); } ssaAddr ssa_add_local_generated(ssaProc *p, Type *t) { @@ -594,12 +718,9 @@ ssaAddr ssa_add_local_generated(ssaProc *p, Type *t) { } void ssa_emit_comment(ssaProc *p, String s) { - ssa_new_value0v(p->curr_block, ssaOp_Comment, NULL, exact_value_string(s)); + // ssa_new_value0v(p->curr_block, ssaOp_Comment, NULL, exact_value_string(s)); } - - - void ssa_build_stmt(ssaProc *p, AstNode *node); void ssa_build_stmt_list(ssaProc *p, AstNodeArray nodes); @@ -607,12 +728,312 @@ void ssa_addr_store(ssaProc *p, ssaAddr addr, ssaValue *value) { if (addr.addr == NULL) { return; } + if (addr.kind == ssaAddr_Map) { + GB_PANIC("TODO(bill): ssa_addr_store"); + return; + } + + ssa_new_value2(p->curr_block, ssaOp_Store, addr.addr->type, addr.addr, value); } -ssaAddr ssa_build_addr(ssaProc *p, AstNode *node) { +ssaValue *ssa_addr_load(ssaProc *p, ssaAddr addr) { + if (addr.addr == NULL) { + return NULL; + } + + if (addr.kind == ssaAddr_Map) { + GB_PANIC("here\n"); + return NULL; + } + + Type *t = addr.addr->type; + Type *bt = base_type(t); + if (bt->kind == Type_Proc) { + return addr.addr; + } + + return ssa_new_value1(p->curr_block, ssaOp_Load, type_deref(t), addr.addr); +} + +ssaValue *ssa_get_using_variable(ssaProc *p, Entity *e) { + GB_PANIC("TODO(bill): ssa_get_using_variable"); + return NULL; + // GB_ASSERT(e->kind == Entity_Variable && e->flags & EntityFlag_Anonymous); + // String name = e->token.string; + // Entity *parent = e->using_parent; + // Selection sel = lookup_field(proc->module->allocator, parent->type, name, false); + // GB_ASSERT(sel.entity != NULL); + // irValue **pv = map_ir_value_get(&proc->module->values, hash_pointer(parent)); + // irValue *v = NULL; + // if (pv != NULL) { + // v = *pv; + // } else { + // v = ir_build_addr(proc, e->using_expr).addr; + // } + // GB_ASSERT(v != NULL); + // return ir_emit_deep_field_gep(proc, parent->type, v, sel); +} + +ssaAddr ssa_build_addr_from_entity(ssaProc *p, Entity *e, AstNode *expr) { + GB_ASSERT(e != NULL); + + ssaValue *v = NULL; + ssaValue **found = map_ssa_value_get(&p->module->values, hash_pointer(e)); + if (found) { + v = *found; + } else if (e->kind == Entity_Variable && e->flags & EntityFlag_Anonymous) { + // NOTE(bill): Calculate the using variable every time + v = ssa_get_using_variable(p, e); + } + + if (v == NULL) { + GB_PANIC("Unknown value: %.*s, entity: %p %.*s\n", LIT(e->token.string), e, LIT(entity_strings[e->kind])); + } + + return ssa_addr(v); +} + +ssaAddr ssa_build_addr(ssaProc *p, AstNode *expr) { + switch (expr->kind) { + case_ast_node(i, Ident, expr); + if (ssa_is_blank_ident(expr)) { + ssaAddr val = {0}; + return val; + } + Entity *e = entity_of_ident(p->module->info, expr); + return ssa_build_addr_from_entity(p, e, expr); + case_end; + + case_ast_node(pe, ParenExpr, expr); + return ssa_build_addr(p, unparen_expr(expr)); + case_end; + } + + GB_PANIC("Cannot get entity's address"); return ssa_addr(NULL); } + +Type *ssa_proper_type(Type *t) { + t = default_type(base_type(base_enum_type(t))); + + if (t->kind == Type_Basic) { + switch (t->Basic.kind) { + case Basic_int: + if (build_context.word_size == 8) { + return t_i64; + } + return t_i32; + case Basic_uint: + if (build_context.word_size == 8) { + return t_u64; + } + return t_u32; + } + } + + return t; +} + +ssaOp ssa_determine_op(TokenKind op, Type *t) { + t = ssa_proper_type(t); + if (t->kind == Type_Basic) { + switch (t->Basic.kind) { + case Basic_bool: + switch (op) { + case Token_And: return ssaOp_And8; + case Token_Or: return ssaOp_Or8; + case Token_Xor: return ssaOp_Xor8; + case Token_AndNot: return ssaOp_AndNot8; + } + break; + case Basic_i8: + switch (op) { + case Token_Add: return ssaOp_Add8; + case Token_Sub: return ssaOp_Sub8; + case Token_Mul: return ssaOp_Mul8; + case Token_Quo: return ssaOp_Div8; + case Token_Mod: return ssaOp_Mod8; + case Token_And: return ssaOp_And8; + case Token_Or: return ssaOp_Or8; + case Token_Xor: return ssaOp_Xor8; + case Token_AndNot: return ssaOp_AndNot8; + case Token_Lt: return ssaOp_Lt8; + case Token_LtEq: return ssaOp_Le8; + case Token_Gt: return ssaOp_Gt8; + case Token_GtEq: return ssaOp_Ge8; + case Token_CmpEq: return ssaOp_Eq8; + case Token_NotEq: return ssaOp_Ne8; + } + break; + case Basic_u8: + switch (op) { + case Token_Add: return ssaOp_Add8; + case Token_Sub: return ssaOp_Sub8; + case Token_Mul: return ssaOp_Mul8; + case Token_Quo: return ssaOp_Div8U; + case Token_Mod: return ssaOp_Mod8U; + case Token_And: return ssaOp_And8; + case Token_Or: return ssaOp_Or8; + case Token_Xor: return ssaOp_Xor8; + case Token_AndNot: return ssaOp_AndNot8; + case Token_Lt: return ssaOp_Lt8; + case Token_LtEq: return ssaOp_Le8; + case Token_Gt: return ssaOp_Gt8; + case Token_GtEq: return ssaOp_Ge8; + case Token_CmpEq: return ssaOp_Eq8; + case Token_NotEq: return ssaOp_Ne8; + } + break; + case Basic_i16: + switch (op) { + case Token_Add: return ssaOp_Add16; + case Token_Sub: return ssaOp_Sub16; + case Token_Mul: return ssaOp_Mul16; + case Token_Quo: return ssaOp_Div16; + case Token_Mod: return ssaOp_Mod16; + case Token_And: return ssaOp_And16; + case Token_Or: return ssaOp_Or16; + case Token_Xor: return ssaOp_Xor16; + case Token_AndNot: return ssaOp_AndNot16; + case Token_Lt: return ssaOp_Lt16; + case Token_LtEq: return ssaOp_Le16; + case Token_Gt: return ssaOp_Gt16; + case Token_GtEq: return ssaOp_Ge16; + case Token_CmpEq: return ssaOp_Eq16; + case Token_NotEq: return ssaOp_Ne16; + } + break; + case Basic_u16: + switch (op) { + case Token_Add: return ssaOp_Add16; + case Token_Sub: return ssaOp_Sub16; + case Token_Mul: return ssaOp_Mul16; + case Token_Quo: return ssaOp_Div16U; + case Token_Mod: return ssaOp_Mod16U; + case Token_And: return ssaOp_And16; + case Token_Or: return ssaOp_Or16; + case Token_Xor: return ssaOp_Xor16; + case Token_AndNot: return ssaOp_AndNot16; + case Token_Lt: return ssaOp_Lt16; + case Token_LtEq: return ssaOp_Le16; + case Token_Gt: return ssaOp_Gt16; + case Token_GtEq: return ssaOp_Ge16; + case Token_CmpEq: return ssaOp_Eq16; + case Token_NotEq: return ssaOp_Ne16; + } + break; + case Basic_i32: + switch (op) { + case Token_Add: return ssaOp_Add32; + case Token_Sub: return ssaOp_Sub32; + case Token_Mul: return ssaOp_Mul32; + case Token_Quo: return ssaOp_Div32; + case Token_Mod: return ssaOp_Mod32; + case Token_And: return ssaOp_And32; + case Token_Or: return ssaOp_Or32; + case Token_Xor: return ssaOp_Xor32; + case Token_AndNot: return ssaOp_AndNot32; + case Token_Lt: return ssaOp_Lt32; + case Token_LtEq: return ssaOp_Le32; + case Token_Gt: return ssaOp_Gt32; + case Token_GtEq: return ssaOp_Ge32; + case Token_CmpEq: return ssaOp_Eq32; + case Token_NotEq: return ssaOp_Ne32; + } + break; + case Basic_u32: + switch (op) { + case Token_Add: return ssaOp_Add32; + case Token_Sub: return ssaOp_Sub32; + case Token_Mul: return ssaOp_Mul32; + case Token_Quo: return ssaOp_Div32U; + case Token_Mod: return ssaOp_Mod32U; + case Token_And: return ssaOp_And32; + case Token_Or: return ssaOp_Or32; + case Token_Xor: return ssaOp_Xor32; + case Token_AndNot: return ssaOp_AndNot32; + case Token_Lt: return ssaOp_Lt32; + case Token_LtEq: return ssaOp_Le32; + case Token_Gt: return ssaOp_Gt32; + case Token_GtEq: return ssaOp_Ge32; + case Token_CmpEq: return ssaOp_Eq32; + case Token_NotEq: return ssaOp_Ne32; + } + break; + case Basic_i64: + switch (op) { + case Token_Add: return ssaOp_Add64; + case Token_Sub: return ssaOp_Sub64; + case Token_Mul: return ssaOp_Mul64; + case Token_Quo: return ssaOp_Div64; + case Token_Mod: return ssaOp_Mod64; + case Token_And: return ssaOp_And64; + case Token_Or: return ssaOp_Or64; + case Token_Xor: return ssaOp_Xor64; + case Token_AndNot: return ssaOp_AndNot64; + case Token_Lt: return ssaOp_Lt64; + case Token_LtEq: return ssaOp_Le64; + case Token_Gt: return ssaOp_Gt64; + case Token_GtEq: return ssaOp_Ge64; + case Token_CmpEq: return ssaOp_Eq64; + case Token_NotEq: return ssaOp_Ne64; + } + break; + case Basic_u64: + switch (op) { + case Token_Add: return ssaOp_Add64; + case Token_Sub: return ssaOp_Sub64; + case Token_Mul: return ssaOp_Mul64; + case Token_Quo: return ssaOp_Div64U; + case Token_Mod: return ssaOp_Mod64U; + case Token_And: return ssaOp_And64; + case Token_Or: return ssaOp_Or64; + case Token_Xor: return ssaOp_Xor64; + case Token_AndNot: return ssaOp_AndNot64; + case Token_Lt: return ssaOp_Lt64; + case Token_LtEq: return ssaOp_Le64; + case Token_Gt: return ssaOp_Gt64; + case Token_GtEq: return ssaOp_Ge64; + case Token_CmpEq: return ssaOp_Eq64; + case Token_NotEq: return ssaOp_Ne64; + } + break; + case Basic_f32: + switch (op) { + case Token_Add: return ssaOp_Add32F; + case Token_Sub: return ssaOp_Sub32F; + case Token_Mul: return ssaOp_Mul32F; + case Token_Quo: return ssaOp_Div32F; + case Token_Lt: return ssaOp_Lt32F; + case Token_LtEq: return ssaOp_Le32F; + case Token_Gt: return ssaOp_Gt32F; + case Token_GtEq: return ssaOp_Ge32F; + case Token_CmpEq: return ssaOp_Eq32F; + case Token_NotEq: return ssaOp_Ne32F; + } + break; + case Basic_f64: + switch (op) { + case Token_Add: return ssaOp_Add64F; + case Token_Sub: return ssaOp_Sub64F; + case Token_Mul: return ssaOp_Mul64F; + case Token_Quo: return ssaOp_Div64F; + case Token_Lt: return ssaOp_Lt64F; + case Token_LtEq: return ssaOp_Le64F; + case Token_Gt: return ssaOp_Gt64F; + case Token_GtEq: return ssaOp_Ge64F; + case Token_CmpEq: return ssaOp_Eq64F; + case Token_NotEq: return ssaOp_Ne64F; + } + break; + } + } + + GB_PANIC("Invalid Op for type"); + return ssaOp_Invalid; +} + ssaValue *ssa_build_expr(ssaProc *p, AstNode *expr) { expr = unparen_expr(expr); @@ -620,15 +1041,53 @@ ssaValue *ssa_build_expr(ssaProc *p, AstNode *expr) { GB_ASSERT_NOT_NULL(tv); if (tv->value.kind != ExactValue_Invalid) { - return NULL; - // return llir_add_module_constant(p->module, tv->type, tv->value); + Type *t = base_type(base_enum_type(tv->type)); + if (is_type_boolean(t)) { + return ssa_const_bool(p, tv->type, tv->value.value_bool); + } else if (is_type_string(t)) { + GB_ASSERT(tv->value.kind == ExactValue_String); + return ssa_const_string(p, tv->type, tv->value.value_string); + } else if(is_type_slice(t)) { + return ssa_const_slice(p, tv->type, tv->value); + } else if (is_type_integer(t)) { + GB_ASSERT(tv->value.kind == ExactValue_Integer); + + i64 s = 8*type_size_of(p->module->allocator, t); + switch (s) { + case 8: return ssa_const_i8 (p, tv->type, tv->value.value_integer); + case 16: return ssa_const_i16(p, tv->type, tv->value.value_integer); + case 32: return ssa_const_i32(p, tv->type, tv->value.value_integer); + case 64: return ssa_const_i64(p, tv->type, tv->value.value_integer); + default: GB_PANIC("Unknown integer size"); + } + } else if (is_type_float(t)) { + GB_ASSERT(tv->value.kind == ExactValue_Float); + i64 s = 8*type_size_of(p->module->allocator, t); + switch (s) { + case 32: return ssa_const_f32(p, tv->type, tv->value.value_float); + case 64: return ssa_const_f64(p, tv->type, tv->value.value_float); + default: GB_PANIC("Unknown float size"); + } + } + // IMPORTANT TODO(bill): Do constant record/array literals correctly + return ssa_const_nil(p, tv->type); } + if (tv->mode == Addressing_Variable) { + return ssa_addr_load(p, ssa_build_addr(p, expr)); + } + + switch (expr->kind) { case_ast_node(bl, BasicLit, expr); GB_PANIC("Non-constant basic literal"); case_end; + case_ast_node(bd, BasicDirective, expr); + TokenPos pos = bd->token.pos; + GB_PANIC("Non-constant basic literal %.*s(%td:%td) - %.*s", LIT(pos.file), pos.line, pos.column, LIT(bd->name)); + case_end; + case_ast_node(i, Ident, expr); Entity *e = *map_entity_get(&p->module->info->uses, hash_pointer(expr)); if (e->kind == Entity_Builtin) { @@ -648,7 +1107,103 @@ ssaValue *ssa_build_expr(ssaProc *p, AstNode *expr) { if (v->op == ssaOp_Proc) { return v; } - return v; + + ssaAddr addr = ssa_build_addr(p, expr); + return ssa_addr_load(p, addr); + } + case_end; + + case_ast_node(ue, UnaryExpr, expr); + switch (ue->op.kind) { + case Token_Pointer: { + ssaValue *ptr = ssa_build_addr(p, ue->expr).addr; + return ssa_new_value1(p->curr_block, ssaOp_Copy, tv->type, ptr); + } break; + + case Token_Add: + return ssa_build_expr(p, ue->expr); + + case Token_Not: // Boolean not + return ssa_new_value1(p->curr_block, ssaOp_NotB, tv->type, ssa_build_expr(p, ue->expr)); + case Token_Xor: { // Bitwise not + ssaValue *x = ssa_build_expr(p, ue->expr); + isize bits = 8*type_size_of(p->module->allocator, x->type); + switch (bits) { + case 8: return ssa_new_value1(p->curr_block, ssaOp_Not8, tv->type, x); + case 16: return ssa_new_value1(p->curr_block, ssaOp_Not16, tv->type, x); + case 32: return ssa_new_value1(p->curr_block, ssaOp_Not32, tv->type, x); + case 64: return ssa_new_value1(p->curr_block, ssaOp_Not64, tv->type, x); + } + GB_PANIC("unknown integer size"); + } break; + + case Token_Sub: { // 0-x + ssaValue *x = ssa_build_expr(p, ue->expr); + isize bits = 8*type_size_of(p->module->allocator, x->type); + if (is_type_integer(x->type)) { + switch (bits) { + case 8: return ssa_new_value1(p->curr_block, ssaOp_Neg8, tv->type, x); + case 16: return ssa_new_value1(p->curr_block, ssaOp_Neg16, tv->type, x); + case 32: return ssa_new_value1(p->curr_block, ssaOp_Neg32, tv->type, x); + case 64: return ssa_new_value1(p->curr_block, ssaOp_Neg64, tv->type, x); + } + } else if (is_type_float(x->type)) { + switch (bits) { + case 32: return ssa_new_value1(p->curr_block, ssaOp_Neg32F, tv->type, x); + case 64: return ssa_new_value1(p->curr_block, ssaOp_Neg64F, tv->type, x); + } + } + GB_PANIC("unknown type for -x"); + } break; + } + case_end; + + case_ast_node(be, BinaryExpr, expr); + Type *type = default_type(tv->type); + + switch (be->op.kind) { + case Token_Add: + case Token_Sub: + case Token_Mul: + case Token_Quo: + case Token_Mod: + case Token_And: + case Token_Or: + case Token_Xor: + case Token_AndNot: { + ssaValue *x = ssa_build_expr(p, be->left); + ssaValue *y = ssa_build_expr(p, be->right); + GB_ASSERT(x != NULL && y != NULL); + return ssa_new_value2(p->curr_block, ssa_determine_op(be->op.kind, x->type), tv->type, x, y); + } + + case Token_Shl: + case Token_Shr: { + GB_PANIC("TODO: shifts"); + return NULL; + } + + case Token_CmpEq: + case Token_NotEq: + case Token_Lt: + case Token_LtEq: + case Token_Gt: + case Token_GtEq: { + ssaValue *x = ssa_build_expr(p, be->left); + ssaValue *y = ssa_build_expr(p, be->right); + GB_ASSERT(x != NULL && y != NULL); + return ssa_new_value2(p->curr_block, ssa_determine_op(be->op.kind, x->type), tv->type, x, y); + } break; + + case Token_CmpAnd: + case Token_CmpOr: + GB_PANIC("TODO: inline && and ||"); + return NULL; + // return ir_emit_logical_binary_expr(proc, expr); + + default: + GB_PANIC("Invalid binary expression"); + break; } case_end; } @@ -673,9 +1228,82 @@ ssaValue *ssa_emit_struct_ep(ssaProc *p, ssaValue *ptr, i32 index) { } +ssaValue *ssa_build_cond(ssaProc *p, AstNode *cond, ssaBlock *yes, ssaBlock *no) { + switch (cond->kind) { + case_ast_node(pe, ParenExpr, cond); + return ssa_build_cond(p, pe->expr, yes, no); + case_end; + + case_ast_node(ue, UnaryExpr, cond); + if (ue->op.kind == Token_Not) { + return ssa_build_cond(p, ue->expr, no, yes); + } + case_end; + + case_ast_node(be, BinaryExpr, cond); + if (be->op.kind == Token_CmpAnd) { + ssaBlock *block = ssa_new_block(p, ssaBlock_Plain, "cmd.and"); + ssa_build_cond(p, be->left, block, no); + ssa_start_block(p, block); + return ssa_build_cond(p, be->right, yes, no); + } else if (be->op.kind == Token_CmpOr) { + ssaBlock *block = ssa_new_block(p, ssaBlock_Plain, "cmp.or"); + ssa_build_cond(p, be->left, yes, block); + ssa_start_block(p, block); + return ssa_build_cond(p, be->right, yes, no); + } + case_end; + } + + ssaValue *c = ssa_build_expr(p, cond); + ssaBlock *b = ssa_end_block(p); + b->kind = ssaBlock_If; + ssa_set_control(b, c); + ssa_add_edge_to(b, yes); + ssa_add_edge_to(b, no); + return c; +} + +void ssa_build_when_stmt(ssaProc *p, AstNodeWhenStmt *ws) { + ssaValue *cond = ssa_build_expr(p, ws->cond); + GB_ASSERT(is_type_boolean(cond->type)); + + GB_ASSERT(cond->exact_value.kind == ExactValue_Bool); + if (cond->exact_value.value_bool) { + ssa_build_stmt_list(p, ws->body->BlockStmt.stmts); + } else if (ws->else_stmt) { + switch (ws->else_stmt->kind) { + case AstNode_BlockStmt: + ssa_build_stmt_list(p, ws->else_stmt->BlockStmt.stmts); + break; + case AstNode_WhenStmt: + ssa_build_when_stmt(p, &ws->else_stmt->WhenStmt); + break; + default: + GB_PANIC("Invalid `else` statement in `when` statement"); + break; + } + } +} + +void ssa_build_assign_op(ssaProc *p, ssaAddr lhs, ssaValue *value, TokenKind op) { + // ssaValue *old_value = ssa_addr_load(p, lhs); + // Type *type = old_value->type; + + // ssaValue *change = value; + // if (is_type_pointer(type) && is_type_integer(value->type)) { + // change = ssa_emit_conv(p, value, default_type(value->type)); + // } else { + // change = ssa_emit_conv(p, value, type); + // } + // ssaValue *new_value = ssa_emit_arith(p, op, old_value, change, type); + // ssa_addr_store(p, lhs, new_value); +} + + void ssa_build_stmt(ssaProc *p, AstNode *node) { if (p->curr_block == NULL) { - ssaBlock *dead_block = ssa_new_block(p, ssaBlock_Plain); + ssaBlock *dead_block = ssa_new_block(p, ssaBlock_Plain, ""); ssa_start_block(p, dead_block); } @@ -694,6 +1322,20 @@ void ssa_build_stmt(ssaProc *p, AstNode *node) { } case_end; + case_ast_node(ws, WhenStmt, node); + ssa_build_when_stmt(p, ws); + case_end; + + case_ast_node(s, IncDecStmt, node); + TokenKind op = Token_Add; + if (s->op.kind == Token_Dec) { + op = Token_Sub; + } + ssaAddr addr = ssa_build_addr(p, s->expr); + Type *t = ssa_addr_type(addr); + ssa_build_assign_op(p, addr, ssa_const_int(p, t, 1), op); + case_end; + case_ast_node(vd, ValueDecl, node); if (vd->is_var) { ssaModule *m = p->module; @@ -829,9 +1471,336 @@ void ssa_build_stmt(ssaProc *p, AstNode *node) { // NOTE(bill): No need to use return value ssa_build_expr(p, es->expr); case_end; + + case_ast_node(ds, DeferStmt, node); + GB_PANIC("TODO: DeferStmt"); + case_end; + + case_ast_node(rs, ReturnStmt, node); + GB_PANIC("TODO: ReturnStmt"); + case_end; + + case_ast_node(is, IfStmt, node); + ssa_emit_comment(p, str_lit("IfStmt")); + if (is->init != NULL) { + ssaBlock *init = ssa_new_block(p, ssaBlock_Plain, "if.init"); + ssa_emit_jump(p, init); + ssa_start_block(p, init); + ssa_build_stmt(p, is->init); + } + ssaBlock *then = ssa_new_block(p, ssaBlock_Plain, "if.then"); + ssaBlock *done = ssa_new_block(p, ssaBlock_Plain, "if.done"); + ssaBlock *else_ = done; + if (is->else_stmt != NULL) { + else_ = ssa_new_block(p, ssaBlock_Plain, "if.else"); + } + ssaBlock *b = NULL; + + ssa_build_cond(p, is->cond, then, else_); + ssa_start_block(p, then); + + // ssa_open_scope(p); + ssa_build_stmt(p, is->body); + // ssa_close_scope(p, ssaDeferExit_Default, NULL); + + ssa_emit_jump(p, done); + + if (is->else_stmt != NULL) { + ssa_start_block(p, else_); + + // ssa_open_scope(p); + ssa_build_stmt(p, is->else_stmt); + // ssa_close_scope(p, ssaDeferExit_Default, NULL); + + ssa_emit_jump(p, done); + } + + ssa_start_block(p, done); + case_end; + + + case_ast_node(fs, ForStmt, node); + ssa_emit_comment(p, str_lit("ForStmt")); + if (fs->init != NULL) { + ssaBlock *init = ssa_new_block(p, ssaBlock_Plain, "for.init"); + ssa_emit_jump(p, init); + ssa_start_block(p, init); + ssa_build_stmt(p, fs->init); + } + + ssaBlock *body = ssa_new_block(p, ssaBlock_Plain, "for.body"); + ssaBlock *done = ssa_new_block(p, ssaBlock_Plain, "for.done"); + ssaBlock *loop = body; + if (fs->cond != NULL) { + loop = ssa_new_block(p, ssaBlock_Plain, "for.loop"); + } + ssaBlock *post = loop; + if (fs->post != NULL) { + post = ssa_new_block(p, ssaBlock_Plain, "for.post"); + } + + ssa_emit_jump(p, loop); + ssa_start_block(p, loop); + + if (loop != body) { + ssa_build_cond(p, fs->cond, body, done); + ssa_start_block(p, body); + } + + ssa_push_target_list(p, done, post, NULL); + // ssa_open_scope(p); + ssa_build_stmt(p, fs->body); + // ssa_close_scope(p, ssaDeferExit_Default, NULL); + ssa_pop_target_list(p); + + ssa_emit_jump(p, post); + + if (fs->post != NULL) { + ssa_start_block(p, post); + ssa_build_stmt(p, fs->post); + ssa_emit_jump(p, post); + } + + ssa_start_block(p, done); + case_end; + + case_ast_node(rs, RangeStmt, node); + GB_PANIC("TODO: RangeStmt"); + case_end; + + case_ast_node(rs, MatchStmt, node); + GB_PANIC("TODO: MatchStmt"); + case_end; + + case_ast_node(rs, TypeMatchStmt, node); + GB_PANIC("TODO: TypeMatchStmt"); + case_end; + + case_ast_node(bs, BranchStmt, node); + ssaBlock *b = NULL; + switch (bs->token.kind) { + case Token_break: + for (ssaTargetList *t = p->target_list; t != NULL && b == NULL; t = t->prev) { + b = t->break_; + } + break; + case Token_continue: + for (ssaTargetList *t = p->target_list; t != NULL && b == NULL; t = t->prev) { + b = t->continue_; + } + break; + case Token_fallthrough: + for (ssaTargetList *t = p->target_list; t != NULL && b == NULL; t = t->prev) { + b = t->fallthrough_; + } + break; + } + if (b != NULL) { + // ssa_emit_defer_stmts(p, irDeferExit_Branch, b); + } + switch (bs->token.kind) { + case Token_break: ssa_emit_comment(p, str_lit("break")); break; + case Token_continue: ssa_emit_comment(p, str_lit("continue")); break; + case Token_fallthrough: ssa_emit_comment(p, str_lit("fallthrough")); break; + } + ssa_emit_jump(p, b); + case_end; + + case_ast_node(pa, PushAllocator, node); + GB_PANIC("TODO: PushAllocator"); + case_end; + case_ast_node(pc, PushContext, node); + GB_PANIC("TODO: PushContext"); + case_end; } } +void ssa_print_value(gbFile *f, ssaValue *v) { + if (v == NULL) { + gb_fprintf(f, "nil"); + } + gb_fprintf(f, "v%d", v->id); +} + +void ssa_print_exact_value(gbFile *f, ssaValue *v) { + Type *t = default_type(v->type); + ExactValue ev = v->exact_value; + switch (ev.kind) { + case ExactValue_Bool: + if (ev.value_bool == false) { + gb_fprintf(f, " [false]"); + } else { + gb_fprintf(f, " [true]"); + } + break; + case ExactValue_Integer: + if (is_type_unsigned(t)) { + gb_fprintf(f, " [%llu]", ev.value_integer); + } else { + gb_fprintf(f, " [%lld]", ev.value_integer); + } + break; + case ExactValue_Float: + if (is_type_f32(t)) { + f32 fp = cast(f32)ev.value_float; + u32 x = *cast(u32 *)&fp; + gb_fprintf(f, " [0x%x]", x); + } else if (is_type_f64(t)) { + f64 fp = cast(f64)ev.value_float; + u64 x = *cast(u64 *)&fp; + gb_fprintf(f, " [0x%llx]", x); + } else { + GB_PANIC("unhandled integer"); + } + break; + case ExactValue_String: + gb_fprintf(f, " [%.*s]", LIT(ev.value_string)); + break; + case ExactValue_Pointer: + gb_fprintf(f, " [0x%llx]", ev.value_pointer); + break; + } +} + + +void ssa_print_reg_value(gbFile *f, ssaValue *v) { + gb_fprintf(f, " "); + gb_fprintf(f, "v%d = %.*s", v->id, LIT(ssa_op_strings[v->op])); + + if (v->type != NULL) { + gbString type_str = type_to_string(default_type(v->type)); + gb_fprintf(f, " %s", type_str); + gb_string_free(type_str); + } + + ssa_print_exact_value(f, v); + + if (ssa_op_uses_var_args(v->op)) { + for_array(i, v->var_args) { + gb_fprintf(f, " "); + ssa_print_value(f, v->var_args.e[i]); + } + } else { + for (isize i = 0; i < v->arg_count; i++) { + gb_fprintf(f, " "); + ssa_print_value(f, v->args[i]); + } + } + + if (v->comment_string.len > 0) { + gb_fprintf(f, " ; %.*s", LIT(v->comment_string)); + } + + gb_fprintf(f, "\n"); + +} + +void ssa_print_proc(gbFile *f, ssaProc *p) { + gbString type_str = type_to_string(p->entity->type); + gb_fprintf(f, "%.*s %s\n", LIT(p->name), type_str); + gb_string_free(type_str); + + bool *printed = gb_alloc_array(heap_allocator(), bool, p->value_id+1); + + for_array(i, p->blocks) { + ssaBlock *b = p->blocks.e[i]; + gb_fprintf(f, " b%d:", b->id); + if (b->preds.count > 0) { + gb_fprintf(f, " <-"); + for_array(j, b->preds) { + ssaBlock *pred = b->preds.e[j].block; + gb_fprintf(f, " b%d", pred->id); + } + } + gb_fprintf(f, "\n"); + + isize n = 0; + for_array(j, b->values) { + ssaValue *v = b->values.e[j]; + if (v->op != ssaOp_Phi) { + continue; + } + ssa_print_reg_value(f, v); + printed[v->id] = true; + n++; + } + + while (n < b->values.count) { + isize m = 0; + for_array(j, b->values) { + ssaValue *v = b->values.e[j]; + if (printed[v->id]) { + continue; + } + bool skip = false; + if (ssa_op_uses_var_args(v->op)) { + for_array(k, v->var_args) { + ssaValue *w = v->var_args.e[k]; + if (w != NULL && w->block == b && !printed[w->id]) { + skip = true; + break; + } + } + } else { + for (isize k = 0; k < v->arg_count; k++) { + ssaValue *w = v->args[k]; + if (w != NULL && w->block == b && !printed[w->id]) { + skip = true; + break; + } + } + } + + if (skip) { + break; + } + + ssa_print_reg_value(f, v); + printed[v->id] = true; + n++; + } + if (m == n) { + gb_fprintf(f, "!!!!DepCycle!!!!\n"); + for_array(k, b->values) { + ssaValue *v = b->values.e[k]; + if (printed[v->id]) { + continue; + } + + ssa_print_reg_value(f, v); + printed[v->id] = true; + n++; + } + } + } + + if (b->kind == ssaBlock_Plain) { + GB_ASSERT(b->succs.count == 1); + ssaBlock *next = b->succs.e[0].block; + gb_fprintf(f, " "); + gb_fprintf(f, "jump b%d", next->id); + gb_fprintf(f, "\n"); + } else if (b->kind == ssaBlock_If) { + GB_ASSERT(b->succs.count == 2); + ssaBlock *yes = b->succs.e[0].block; + ssaBlock *no = b->succs.e[1].block; + gb_fprintf(f, " "); + gb_fprintf(f, "branch v%d, b%d, b%d", b->control->id, yes->id, no->id); + gb_fprintf(f, "\n"); + } else if (b->kind == ssaBlock_Exit) { + gb_fprintf(f, " "); + gb_fprintf(f, "exit"); + gb_fprintf(f, "\n"); + } else if (b->kind == ssaBlock_Ret) { + gb_fprintf(f, " "); + gb_fprintf(f, "ret"); + gb_fprintf(f, "\n"); + } + } + + gb_free(heap_allocator(), printed); +} + void ssa_build_proc(ssaModule *m, ssaProc *p) { p->module = m; @@ -846,13 +1815,19 @@ void ssa_build_proc(ssaModule *m, ssaProc *p) { if (pl->body == NULL) { return; } - p->entry = ssa_new_block(p, ssaBlock_Entry); - p->curr_block = ssa_new_block(p, ssaBlock_Plain); + p->entry = ssa_new_block(p, ssaBlock_Entry, "entry"); + ssa_start_block(p, p->entry); ssa_build_stmt(p, pl->body); + + p->exit = ssa_new_block(p, ssaBlock_Exit, "exit"); + ssa_emit_jump(p, p->exit); + + ssa_print_proc(gb_file_get_standard(gbFileStandard_Error), p); } + bool ssa_generate(Parser *parser, CheckerInfo *info) { if (global_error_collector.count != 0) { return false; @@ -956,8 +1931,6 @@ bool ssa_generate(Parser *parser, CheckerInfo *info) { } if (e == entry_point) { - gb_printf("%.*s\n", LIT(name)); - ssaProc *p = ssa_new_proc(&m, name, e, decl); ssa_build_proc(&m, p); }