aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGinger Bill <bill@gingerbill.org>2017-03-12 16:42:51 +0000
committerGinger Bill <bill@gingerbill.org>2017-03-12 16:42:51 +0000
commitaaec8bf423a40f887d43d12403c2e40f187d424c (patch)
tree98958a8c7db53197a0176fcc7607bdcad0a4d8c3
parent0fcbda951aea462248304a7e16f5c4eb9da9939d (diff)
windows.odin TYPE_NAME to Type_Name; More SSA work and SSA printing for debugging
-rw-r--r--code/demo.odin15
-rw-r--r--core/math.odin67
-rw-r--r--core/os_windows.odin89
-rw-r--r--core/sync.odin2
-rw-r--r--core/sys/wgl.odin50
-rw-r--r--core/sys/windows.odin255
-rw-r--r--src/check_decl.c53
-rw-r--r--src/check_expr.c46
-rw-r--r--src/checker.c11
-rw-r--r--src/entity.c11
-rw-r--r--src/gb/gb.h4
-rw-r--r--src/ir.c52
-rw-r--r--src/parser.c14
-rw-r--r--src/ssa.c1573
14 files changed, 1656 insertions, 586 deletions
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);
-}
-remainder32 :: proc(x, y: f32) -> f32 {
- return x - round(x/y) * y;
+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;
}
-fmod32 :: proc(x, y: f32) -> f32 {
+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); }
+
+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 := 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 := remainder32(abs(x), 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;
-
-
-INVALID_HANDLE_VALUE :: cast(HANDLE)~cast(int)0;
-
-FALSE: BOOL : 0;
-TRUE: BOOL : 1;
+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 :: cast(Handle)~cast(int)0;
+
+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;
}
- Type *type = e->type;
+ 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,
-
- 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,
+#define SSA_OP(k) GB_JOIN2(ssaOp_, k),
+ SSA_OPS
+#undef SSA_OP
+};
+
+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);
+}
+
+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(ssaProc *p, AstNode *node) {
+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);
}