Browse Source

ssa - alloca all variables at the very start

Ginger Bill 9 years ago
parent
commit
807256dea4
8 changed files with 237 additions and 104 deletions
  1. 11 9
      code/demo.odin
  2. 1 1
      code/runtime.odin
  3. 99 51
      code/win32.odin
  4. 8 6
      src/checker/stmt.cpp
  5. 39 9
      src/codegen/print_llvm.cpp
  6. 39 7
      src/codegen/ssa.cpp
  7. 6 5
      src/main.cpp
  8. 34 16
      src/parser.cpp

+ 11 - 9
code/demo.odin

@@ -1,14 +1,16 @@
-#import "fmt.odin" as fmt
-// #import "game.odin" as game
+#import "runtime.odin" as _
+#import "punity.odin" as punity
 
 
-test_proc :: proc() {
-	fmt.println("Hello?")
-}
 
 
 
 
 main :: proc() {
 main :: proc() {
-	x := 0
-	// fmt.println("% % % %", "Hellope", true, 6.28, {4}int{1, 2, 3, 4})
-	fmt.println("%(%)", #file, #line)
-	// game.run()
+	init :: proc() {
+
+	}
+
+	step :: proc() {
+
+	}
+
+	punity.run(init, step)
 }
 }

+ 1 - 1
code/runtime.odin

@@ -171,7 +171,7 @@ __string_ge :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) >
 
 
 
 
 __assert :: proc(msg: string) {
 __assert :: proc(msg: string) {
-	os.write(os.get_standard_file(os.File_Standard.ERROR), msg as []byte)
+	_ = os.write(os.get_standard_file(os.File_Standard.ERROR), msg as []byte)
 	__debug_trap()
 	__debug_trap()
 }
 }
 
 

+ 99 - 51
code/win32.odin

@@ -9,18 +9,19 @@ HICON     :: type HANDLE
 HCURSOR   :: type HANDLE
 HCURSOR   :: type HANDLE
 HMENU     :: type HANDLE
 HMENU     :: type HANDLE
 HBRUSH    :: type HANDLE
 HBRUSH    :: type HANDLE
+HGDIOBJ   :: type HANDLE
 WPARAM    :: type uint
 WPARAM    :: type uint
 LPARAM    :: type int
 LPARAM    :: type int
 LRESULT   :: type int
 LRESULT   :: type int
 ATOM      :: type i16
 ATOM      :: type i16
 BOOL      :: type i32
 BOOL      :: type i32
-POINT     :: type struct { x, y: i32 }
 WNDPROC   :: type proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT
 WNDPROC   :: type proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT
 
 
 INVALID_HANDLE_VALUE :: (-1 as int) as HANDLE
 INVALID_HANDLE_VALUE :: (-1 as int) as HANDLE
 
 
-CS_VREDRAW    :: 1
-CS_HREDRAW    :: 2
+CS_VREDRAW    :: 0x0001
+CS_HREDRAW    :: 0x0002
+CS_OWNDC      :: 0x0020
 CW_USEDEFAULT :: 0x80000000
 CW_USEDEFAULT :: 0x80000000
 
 
 WS_OVERLAPPED       :: 0
 WS_OVERLAPPED       :: 0
@@ -32,13 +33,25 @@ WS_CAPTION          :: 0x00C00000
 WS_VISIBLE          :: 0x10000000
 WS_VISIBLE          :: 0x10000000
 WS_OVERLAPPEDWINDOW :: WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX
 WS_OVERLAPPEDWINDOW :: WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX
 
 
-WM_DESTROY :: 0x02
-WM_CLOSE   :: 0x10
-WM_QUIT    :: 0x12
+WM_DESTROY :: 0x0002
+WM_CLOSE   :: 0x0010
+WM_QUIT    :: 0x0012
+WM_KEYDOWN :: 0x0100
+WM_KEYUP   :: 0x0101
 
 
 PM_REMOVE :: 1
 PM_REMOVE :: 1
 
 
 COLOR_BACKGROUND :: 1 as HBRUSH
 COLOR_BACKGROUND :: 1 as HBRUSH
+BLACK_BRUSH :: 4
+
+SM_CXSCREEN :: 0
+SM_CYSCREEN :: 1
+
+SW_SHOW :: 5
+
+POINT :: struct #ordered {
+	x, y: i32
+}
 
 
 
 
 WNDCLASSEXA :: struct #ordered {
 WNDCLASSEXA :: struct #ordered {
@@ -62,45 +75,49 @@ MSG :: struct #ordered {
 	pt:      POINT
 	pt:      POINT
 }
 }
 
 
+RECT :: struct #ordered {
+	left:   i32
+	top:    i32
+	right:  i32
+	bottom: i32
+}
 
 
 
 
-GetLastError     :: proc() -> i32                   #foreign
-ExitProcess      :: proc(exit_code: u32)            #foreign
-GetDesktopWindow :: proc() -> HWND                  #foreign
-GetCursorPos     :: proc(p: ^POINT) -> i32          #foreign
-ScreenToClient   :: proc(h: HWND, p: ^POINT) -> i32 #foreign
-
-GetModuleHandleA :: proc(module_name: ^u8) -> HINSTANCE #foreign
+GetLastError     :: proc() -> i32                       #foreign #dll_import
+ExitProcess      :: proc(exit_code: u32)                #foreign #dll_import
+GetDesktopWindow :: proc() -> HWND                      #foreign #dll_import
+GetCursorPos     :: proc(p: ^POINT) -> i32              #foreign #dll_import
+ScreenToClient   :: proc(h: HWND, p: ^POINT) -> i32     #foreign #dll_import
+GetModuleHandleA :: proc(module_name: ^u8) -> HINSTANCE #foreign #dll_import
+GetStockObject   :: proc(fn_object: i32) -> HGDIOBJ     #foreign #dll_import
+PostQuitMessage  :: proc(exit_code: i32)                #foreign #dll_import
 
 
-QueryPerformanceFrequency :: proc(result: ^i64) -> i32 #foreign
-QueryPerformanceCounter   :: proc(result: ^i64) -> i32 #foreign
+QueryPerformanceFrequency :: proc(result: ^i64) -> i32 #foreign #dll_import
+QueryPerformanceCounter   :: proc(result: ^i64) -> i32 #foreign #dll_import
 
 
-sleep_ms :: proc(ms: i32) {
-	Sleep :: proc(ms: i32) -> i32 #foreign
-	Sleep(ms)
-}
+Sleep :: proc(ms: i32) -> i32 #foreign
 
 
-OutputDebugStringA :: proc(c_str: ^u8) #foreign
+OutputDebugStringA :: proc(c_str: ^u8) #foreign #dll_import
 
 
 
 
-RegisterClassExA :: proc(wc: ^WNDCLASSEXA) -> ATOM #foreign
+RegisterClassExA :: proc(wc: ^WNDCLASSEXA) -> ATOM #foreign #dll_import
 CreateWindowExA  :: proc(ex_style: u32,
 CreateWindowExA  :: proc(ex_style: u32,
                          class_name, title: ^u8,
                          class_name, title: ^u8,
                          style: u32,
                          style: u32,
-                         x, y: u32,
-                         w, h: i32,
+                         x, y, w, h: i32,
                          parent: HWND, menu: HMENU, instance: HINSTANCE,
                          parent: HWND, menu: HMENU, instance: HINSTANCE,
-                         param: rawptr) -> HWND #foreign
+                         param: rawptr) -> HWND #foreign #dll_import
 
 
-ShowWindow       :: proc(hwnd: HWND, cmd_show: i32) -> BOOL #foreign
-TranslateMessage :: proc(msg: ^MSG) -> BOOL                 #foreign
-DispatchMessageA :: proc(msg: ^MSG) -> LRESULT              #foreign
-UpdateWindow     :: proc(hwnd: HWND) -> BOOL                #foreign
+ShowWindow       :: proc(hwnd: HWND, cmd_show: i32) -> BOOL #foreign #dll_import
+TranslateMessage :: proc(msg: ^MSG) -> BOOL                 #foreign #dll_import
+DispatchMessageA :: proc(msg: ^MSG) -> LRESULT              #foreign #dll_import
+UpdateWindow     :: proc(hwnd: HWND) -> BOOL                #foreign #dll_import
 PeekMessageA     :: proc(msg: ^MSG, hwnd: HWND,
 PeekMessageA     :: proc(msg: ^MSG, hwnd: HWND,
-                         msg_filter_min, msg_filter_max, remove_msg: u32) -> BOOL #foreign
+                         msg_filter_min, msg_filter_max, remove_msg: u32) -> BOOL #foreign #dll_import
 
 
-DefWindowProcA   :: proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT #foreign
+DefWindowProcA   :: proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT #foreign #dll_import
 
 
+AdjustWindowRect :: proc(rect: ^RECT, style: u32, menu: BOOL) -> BOOL #foreign #dll_import
 
 
 
 
 GetQueryPerformanceFrequency :: proc() -> i64 {
 GetQueryPerformanceFrequency :: proc() -> i64 {
@@ -109,21 +126,21 @@ GetQueryPerformanceFrequency :: proc() -> i64 {
 	return r
 	return r
 }
 }
 
 
-GetCommandLineA :: proc() -> ^u8 #foreign
-
-GetCurrentThreadId :: proc() -> u32 #foreign
+GetCommandLineA :: proc() -> ^u8 #foreign #dll_import
+GetSystemMetrics :: proc(index: i32) -> i32 #foreign #dll_import
+GetCurrentThreadId :: proc() -> u32 #foreign #dll_import
 
 
 // File Stuff
 // File Stuff
 
 
-CloseHandle  :: proc(h: HANDLE) -> i32 #foreign
-GetStdHandle :: proc(h: i32) -> HANDLE #foreign
+CloseHandle  :: proc(h: HANDLE) -> i32 #foreign #dll_import
+GetStdHandle :: proc(h: i32) -> HANDLE #foreign #dll_import
 CreateFileA  :: proc(filename: ^u8, desired_access, share_mode: u32,
 CreateFileA  :: proc(filename: ^u8, desired_access, share_mode: u32,
                      security: rawptr,
                      security: rawptr,
-                     creation, flags_and_attribs: u32, template_file: HANDLE) -> HANDLE #foreign
-ReadFile     :: proc(h: HANDLE, buf: rawptr, to_read: u32, bytes_read: ^i32, overlapped: rawptr) -> BOOL #foreign
-WriteFile    :: proc(h: HANDLE, buf: rawptr, len: i32, written_result: ^i32, overlapped: rawptr) -> i32 #foreign
+                     creation, flags_and_attribs: u32, template_file: HANDLE) -> HANDLE #foreign #dll_import
+ReadFile     :: proc(h: HANDLE, buf: rawptr, to_read: u32, bytes_read: ^i32, overlapped: rawptr) -> BOOL #foreign #dll_import
+WriteFile    :: proc(h: HANDLE, buf: rawptr, len: i32, written_result: ^i32, overlapped: rawptr) -> i32 #foreign #dll_import
 
 
-GetFileSizeEx :: proc(file_handle: HANDLE, file_size: ^i64) -> BOOL #foreign
+GetFileSizeEx :: proc(file_handle: HANDLE, file_size: ^i64) -> BOOL #foreign #dll_import
 
 
 FILE_SHARE_READ      :: 0x00000001
 FILE_SHARE_READ      :: 0x00000001
 FILE_SHARE_WRITE     :: 0x00000002
 FILE_SHARE_WRITE     :: 0x00000002
@@ -144,17 +161,48 @@ OPEN_ALWAYS       :: 4
 TRUNCATE_EXISTING :: 5
 TRUNCATE_EXISTING :: 5
 
 
 
 
-HeapAlloc :: proc(h: HANDLE, flags: u32, bytes: int) -> rawptr #foreign
-HeapFree  :: proc(h: HANDLE, flags: u32, memory: rawptr) -> BOOL #foreign
-GetProcessHeap :: proc() -> HANDLE #foreign
+HeapAlloc :: proc(h: HANDLE, flags: u32, bytes: int) -> rawptr #foreign #dll_import
+HeapFree  :: proc(h: HANDLE, flags: u32, memory: rawptr) -> BOOL #foreign #dll_import
+GetProcessHeap :: proc() -> HANDLE #foreign #dll_import
+
 
 
 HEAP_ZERO_MEMORY :: 0x00000008
 HEAP_ZERO_MEMORY :: 0x00000008
 
 
 
 
 
 
+// GDI
 
 
+BITMAPINFO :: struct #ordered {
+	HEADER :: struct #ordered {
+		size:              u32
+		width, height:     i32
+		planes, bit_count: i16
+		compression:       u32
+		size_image:        u32
+		x_pels_per_meter:  i32
+		y_pels_per_meter:  i32
+		clr_used:          u32
+		clr_important:     u32
+	}
+	using header: HEADER
+	colors:       [1]RGBQUAD
+}
 
 
 
 
+RGBQUAD :: struct #ordered {
+	blue, green, red, reserved: byte
+}
+
+BI_RGB         :: 0
+DIB_RGB_COLORS :: 0x00
+SRCCOPY        : u32 : 0x00cc0020
+
+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,
+                      usage: u32,
+                      rop: u32) -> i32 #foreign #dll_import
 
 
 
 
 
 
@@ -222,24 +270,24 @@ PIXELFORMATDESCRIPTOR :: struct #ordered {
 }
 }
 
 
 GetDC             :: proc(h: HANDLE) -> HDC #foreign
 GetDC             :: proc(h: HANDLE) -> HDC #foreign
-SetPixelFormat    :: proc(hdc: HDC, pixel_format: i32, pfd: ^PIXELFORMATDESCRIPTOR ) -> BOOL #foreign
-ChoosePixelFormat :: proc(hdc: HDC, pfd: ^PIXELFORMATDESCRIPTOR) -> i32 #foreign
-SwapBuffers       :: proc(hdc: HDC) -> BOOL #foreign
-
+SetPixelFormat    :: proc(hdc: HDC, pixel_format: i32, pfd: ^PIXELFORMATDESCRIPTOR ) -> BOOL #foreign #dll_import
+ChoosePixelFormat :: proc(hdc: HDC, pfd: ^PIXELFORMATDESCRIPTOR) -> i32 #foreign #dll_import
+SwapBuffers       :: proc(hdc: HDC) -> BOOL #foreign #dll_import
+ReleaseDC         :: proc(wnd: HWND, hdc: HDC) -> i32 #foreign #dll_import
 
 
 WGL_CONTEXT_MAJOR_VERSION_ARB             :: 0x2091
 WGL_CONTEXT_MAJOR_VERSION_ARB             :: 0x2091
 WGL_CONTEXT_MINOR_VERSION_ARB             :: 0x2092
 WGL_CONTEXT_MINOR_VERSION_ARB             :: 0x2092
 WGL_CONTEXT_PROFILE_MASK_ARB              :: 0x9126
 WGL_CONTEXT_PROFILE_MASK_ARB              :: 0x9126
 WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB :: 0x0002
 WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB :: 0x0002
 
 
-wglCreateContext  :: proc(hdc: HDC) -> HGLRC #foreign
-wglMakeCurrent    :: proc(hdc: HDC, hglrc: HGLRC) -> BOOL #foreign
-wglGetProcAddress :: proc(c_str: ^u8) -> PROC #foreign
-wglDeleteContext  :: proc(hglrc: HGLRC) -> BOOL #foreign
+wglCreateContext  :: proc(hdc: HDC) -> HGLRC #foreign #dll_import
+wglMakeCurrent    :: proc(hdc: HDC, hglrc: HGLRC) -> BOOL #foreign #dll_import
+wglGetProcAddress :: proc(c_str: ^u8) -> PROC #foreign #dll_import
+wglDeleteContext  :: proc(hglrc: HGLRC) -> BOOL #foreign #dll_import
 
 
 
 
 
 
-GetAsyncKeyState :: proc(v_key: i32) -> i16 #foreign
+GetAsyncKeyState :: proc(v_key: i32) -> i16 #foreign #dll_import
 
 
 is_key_down :: proc(key: Key_Code) -> bool {
 is_key_down :: proc(key: Key_Code) -> bool {
 	return GetAsyncKeyState(key as i32) < 0
 	return GetAsyncKeyState(key as i32) < 0

+ 8 - 6
src/checker/stmt.cpp

@@ -754,12 +754,14 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
 		case Addressing_Type:
 		case Addressing_Type:
 			error(&c->error_collector, ast_node_token(node), "Is not an expression");
 			error(&c->error_collector, ast_node_token(node), "Is not an expression");
 			break;
 			break;
-		default:
-			if (kind == Expr_Stmt) {
-				return;
-			}
-			error(&c->error_collector, ast_node_token(node), "Expression is not used");
-			break;
+		case Addressing_NoValue:
+			return;
+		default: {
+			gbString expr_str = expr_to_string(operand.expr);
+			defer (gb_string_free(expr_str));
+
+			error(&c->error_collector, ast_node_token(node), "Expression is not used: `%s`", expr_str);
+		} break;
 		}
 		}
 	case_end;
 	case_end;
 
 

+ 39 - 9
src/codegen/print_llvm.cpp

@@ -387,13 +387,22 @@ void ssa_print_instr(ssaFileBuffer *f, ssaModule *m, ssaValue *value) {
 		ssa_fprintf(f, "%%%d = alloca ", value->id);
 		ssa_fprintf(f, "%%%d = alloca ", value->id);
 		ssa_print_type(f, m->sizes, type);
 		ssa_print_type(f, m->sizes, type);
 		ssa_fprintf(f, ", align %lld\n", type_align_of(m->sizes, m->allocator, type));
 		ssa_fprintf(f, ", align %lld\n", type_align_of(m->sizes, m->allocator, type));
-		if (instr->Local.zero_initialized) {
-			ssa_fprintf(f, "\tstore ");
-			ssa_print_type(f, m->sizes, type);
-			ssa_fprintf(f, " zeroinitializer, ");
-			ssa_print_type(f, m->sizes, type);
-			ssa_fprintf(f, "* %%%d\n", value->id);
-		}
+		// if (instr->Local.zero_initialized) {
+		// 	ssa_fprintf(f, "\tstore ");
+		// 	ssa_print_type(f, m->sizes, type);
+		// 	ssa_fprintf(f, " zeroinitializer, ");
+		// 	ssa_print_type(f, m->sizes, type);
+		// 	ssa_fprintf(f, "* %%%d\n", value->id);
+		// }
+	} break;
+
+	case ssaInstr_ZeroInit: {
+		Type *type = type_deref(ssa_type(instr->ZeroInit.address));
+		ssa_fprintf(f, "\tstore ");
+		ssa_print_type(f, m->sizes, type);
+		ssa_fprintf(f, " zeroinitializer, ");
+		ssa_print_type(f, m->sizes, type);
+		ssa_fprintf(f, "* %%%d\n", instr->ZeroInit.address->id);
 	} break;
 	} break;
 
 
 	case ssaInstr_Store: {
 	case ssaInstr_Store: {
@@ -745,10 +754,23 @@ void ssa_print_instr(ssaFileBuffer *f, ssaModule *m, ssaValue *value) {
 void ssa_print_proc(ssaFileBuffer *f, ssaModule *m, ssaProcedure *proc) {
 void ssa_print_proc(ssaFileBuffer *f, ssaModule *m, ssaProcedure *proc) {
 	if (proc->body == NULL) {
 	if (proc->body == NULL) {
 		ssa_fprintf(f, "declare ");
 		ssa_fprintf(f, "declare ");
+		if (proc->tags & ProcTag_dll_import) {
+			ssa_fprintf(f, "dllimport ");
+		}
+		if (proc->tags & ProcTag_dll_export) {
+			ssa_fprintf(f, "dllexport ");
+		}
 	} else {
 	} else {
 		ssa_fprintf(f, "\ndefine ");
 		ssa_fprintf(f, "\ndefine ");
 	}
 	}
 
 
+	if (proc->tags & ProcTag_stdcall) {
+		ssa_fprintf(f, "cc 64 ");
+	}
+	if (proc->tags & ProcTag_fastcall) {
+		ssa_fprintf(f, "cc 65 ");
+	}
+
 	auto *proc_type = &proc->type->Proc;
 	auto *proc_type = &proc->type->Proc;
 
 
 	if (proc_type->result_count == 0) {
 	if (proc_type->result_count == 0) {
@@ -773,7 +795,9 @@ void ssa_print_proc(ssaFileBuffer *f, ssaModule *m, ssaProcedure *proc) {
 				ssa_fprintf(f, ", ");
 				ssa_fprintf(f, ", ");
 			}
 			}
 			ssa_print_type(f, m->sizes, e->type);
 			ssa_print_type(f, m->sizes, e->type);
-			ssa_fprintf(f, " %%%.*s", LIT(e->token.string));
+			if (proc->body != NULL) {
+				ssa_fprintf(f, " %%%.*s", LIT(e->token.string));
+			}
 		}
 		}
 	}
 	}
 
 
@@ -787,14 +811,20 @@ void ssa_print_proc(ssaFileBuffer *f, ssaModule *m, ssaProcedure *proc) {
 			ssa_fprintf(f, "noinline ");
 			ssa_fprintf(f, "noinline ");
 		}
 		}
 
 
+		// if (proc->tags & ProcTag_stdcall) {
+		// 	ssa_fprintf(f, "\"cc\"=\"64\" ");
+		// }
+		// if (proc->tags & ProcTag_fastcall) {
+		// 	ssa_fprintf(f, "\"cc\"=\"65\" ");
+		// }
 
 
 		if (proc->tags & ProcTag_foreign) {
 		if (proc->tags & ProcTag_foreign) {
-			// TODO(bill): Set calling convention
 			ssa_fprintf(f, "; foreign\n");
 			ssa_fprintf(f, "; foreign\n");
 		}
 		}
 	}
 	}
 
 
 	if (proc->body != NULL) {
 	if (proc->body != NULL) {
+		// ssa_fprintf(f, "nounwind uwtable {\n");
 		ssa_fprintf(f, "{\n");
 		ssa_fprintf(f, "{\n");
 		gb_for_array(i, proc->blocks) {
 		gb_for_array(i, proc->blocks) {
 			ssaBlock *block = proc->blocks[i];
 			ssaBlock *block = proc->blocks[i];

+ 39 - 7
src/codegen/ssa.cpp

@@ -65,6 +65,8 @@ struct ssaProcedure {
 	isize               scope_index;
 	isize               scope_index;
 	gbArray(ssaDefer)   defer_stmts;
 	gbArray(ssaDefer)   defer_stmts;
 	gbArray(ssaBlock *) blocks;
 	gbArray(ssaBlock *) blocks;
+	ssaBlock *          decl_block;
+	ssaBlock *          entry_block;
 	ssaBlock *          curr_block;
 	ssaBlock *          curr_block;
 	ssaTargetList *     target_list;
 	ssaTargetList *     target_list;
 };
 };
@@ -78,6 +80,7 @@ struct ssaProcedure {
 	SSA_INSTR_KIND(Invalid), \
 	SSA_INSTR_KIND(Invalid), \
 	SSA_INSTR_KIND(Comment), \
 	SSA_INSTR_KIND(Comment), \
 	SSA_INSTR_KIND(Local), \
 	SSA_INSTR_KIND(Local), \
+	SSA_INSTR_KIND(ZeroInit), \
 	SSA_INSTR_KIND(Store), \
 	SSA_INSTR_KIND(Store), \
 	SSA_INSTR_KIND(Load), \
 	SSA_INSTR_KIND(Load), \
 	SSA_INSTR_KIND(GetElementPtr), \
 	SSA_INSTR_KIND(GetElementPtr), \
@@ -151,6 +154,9 @@ struct ssaInstr {
 			Type *  type;
 			Type *  type;
 			b32     zero_initialized;
 			b32     zero_initialized;
 		} Local;
 		} Local;
+		struct {
+			ssaValue *address;
+		} ZeroInit;
 		struct {
 		struct {
 			ssaValue *address;
 			ssaValue *address;
 			ssaValue *value;
 			ssaValue *value;
@@ -509,6 +515,13 @@ ssaValue *ssa_make_instr_store(ssaProcedure *p, ssaValue *address, ssaValue *val
 	return v;
 	return v;
 }
 }
 
 
+ssaValue *ssa_make_instr_zero_init(ssaProcedure *p, ssaValue *address) {
+	ssaValue *v = ssa_alloc_instr(p, ssaInstr_ZeroInit);
+	ssaInstr *i = &v->Instr;
+	i->ZeroInit.address = address;
+	return v;
+}
+
 ssaValue *ssa_make_instr_load(ssaProcedure *p, ssaValue *address) {
 ssaValue *ssa_make_instr_load(ssaProcedure *p, ssaValue *address) {
 	ssaValue *v = ssa_alloc_instr(p, ssaInstr_Load);
 	ssaValue *v = ssa_alloc_instr(p, ssaInstr_Load);
 	ssaInstr *i = &v->Instr;
 	ssaInstr *i = &v->Instr;
@@ -743,13 +756,26 @@ ssaValue *ssa_emit_select(ssaProcedure *p, ssaValue *cond, ssaValue *t, ssaValue
 	return ssa_emit(p, ssa_make_instr_select(p, cond, t, f));
 	return ssa_emit(p, ssa_make_instr_select(p, cond, t, f));
 }
 }
 
 
+ssaValue *ssa_emit_zero_init(ssaProcedure *p, ssaValue *address)  {
+	return ssa_emit(p, ssa_make_instr_zero_init(p, address));
+}
+
 ssaValue *ssa_emit_comment(ssaProcedure *p, String text) {
 ssaValue *ssa_emit_comment(ssaProcedure *p, String text) {
 	return ssa_emit(p, ssa_make_instr_comment(p, text));
 	return ssa_emit(p, ssa_make_instr_comment(p, text));
 }
 }
 
 
 
 
 ssaValue *ssa_add_local(ssaProcedure *proc, Entity *e, b32 zero_initialized = true) {
 ssaValue *ssa_add_local(ssaProcedure *proc, Entity *e, b32 zero_initialized = true) {
-	return ssa_emit(proc, ssa_make_instr_local(proc, e, zero_initialized));
+	ssaBlock *b = proc->decl_block; // all variables must be in the first block
+	ssaValue *instr = ssa_make_instr_local(proc, e, zero_initialized);
+	instr->Instr.parent = b;
+	gb_array_append(b->instrs, instr);
+
+	if (zero_initialized) {
+		ssa_emit_zero_init(proc, instr);
+	}
+
+	return instr;
 }
 }
 
 
 ssaValue *ssa_add_local_for_identifier(ssaProcedure *proc, AstNode *name, b32 zero_initialized) {
 ssaValue *ssa_add_local_for_identifier(ssaProcedure *proc, AstNode *name, b32 zero_initialized) {
@@ -769,11 +795,11 @@ ssaValue *ssa_add_local_generated(ssaProcedure *proc, Type *type) {
 	if (proc->curr_block) {
 	if (proc->curr_block) {
 		scope = proc->curr_block->scope;
 		scope = proc->curr_block->scope;
 	}
 	}
-	Entity *entity = make_entity_variable(proc->module->allocator,
-	                                      scope,
-	                                      empty_token,
-	                                      type);
-	return ssa_emit(proc, ssa_make_instr_local(proc, entity, true));
+	Entity *e = make_entity_variable(proc->module->allocator,
+	                                 scope,
+	                                 empty_token,
+	                                 type);
+	return ssa_add_local(proc, e, true);
 }
 }
 
 
 ssaValue *ssa_add_param(ssaProcedure *proc, Entity *e) {
 ssaValue *ssa_add_param(ssaProcedure *proc, Entity *e) {
@@ -944,7 +970,9 @@ ssaValue *ssa_lvalue_load(ssaProcedure *proc, ssaAddr lval) {
 void ssa_begin_procedure_body(ssaProcedure *proc) {
 void ssa_begin_procedure_body(ssaProcedure *proc) {
 	gb_array_init(proc->blocks, gb_heap_allocator());
 	gb_array_init(proc->blocks, gb_heap_allocator());
 	gb_array_init(proc->defer_stmts, gb_heap_allocator());
 	gb_array_init(proc->defer_stmts, gb_heap_allocator());
-	proc->curr_block = ssa_add_block(proc, proc->type_expr, make_string("entry"));
+	proc->decl_block  = ssa_add_block(proc, proc->type_expr, make_string("decls"));
+	proc->entry_block = ssa_add_block(proc, proc->type_expr, make_string("entry"));
+	proc->curr_block  = proc->entry_block;
 
 
 	if (proc->type->Proc.params != NULL) {
 	if (proc->type->Proc.params != NULL) {
 		auto *params = &proc->type->Proc.params->Tuple;
 		auto *params = &proc->type->Proc.params->Tuple;
@@ -960,6 +988,9 @@ void ssa_end_procedure_body(ssaProcedure *proc) {
 		ssa_emit_ret(proc, NULL);
 		ssa_emit_ret(proc, NULL);
 	}
 	}
 
 
+	proc->curr_block = proc->decl_block;
+	ssa_emit_jump(proc, proc->entry_block);
+
 
 
 // Number blocks and registers
 // Number blocks and registers
 	i32 reg_id = 0;
 	i32 reg_id = 0;
@@ -973,6 +1004,7 @@ void ssa_end_procedure_body(ssaProcedure *proc) {
 			// NOTE(bill): Ignore non-returning instructions
 			// NOTE(bill): Ignore non-returning instructions
 			switch (instr->kind) {
 			switch (instr->kind) {
 			case ssaInstr_Comment:
 			case ssaInstr_Comment:
+			case ssaInstr_ZeroInit:
 			case ssaInstr_Store:
 			case ssaInstr_Store:
 			case ssaInstr_Br:
 			case ssaInstr_Br:
 			case ssaInstr_Ret:
 			case ssaInstr_Ret:

+ 6 - 5
src/main.cpp

@@ -128,10 +128,10 @@ int main(int argc, char **argv) {
 	exit_code = win32_exec_command_line_app(
 	exit_code = win32_exec_command_line_app(
 		// "../misc/llvm-bin/opt %s -o %.*s.bc "
 		// "../misc/llvm-bin/opt %s -o %.*s.bc "
 		"opt %s -o %.*s.bc "
 		"opt %s -o %.*s.bc "
-		"-memcpyopt "
-		"-mem2reg "
-		"-die -dse "
-		"-dce "
+		// "-memcpyopt "
+		// "-mem2reg "
+		// "-die -dse "
+		// "-dce "
 		// "-S "
 		// "-S "
 		// "-debug-pass=Arguments "
 		// "-debug-pass=Arguments "
 		"",
 		"",
@@ -148,13 +148,14 @@ int main(int argc, char **argv) {
 	gb_for_array(i, parser.system_libraries) {
 	gb_for_array(i, parser.system_libraries) {
 		String lib = parser.system_libraries[i];
 		String lib = parser.system_libraries[i];
 		isize len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf),
 		isize len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf),
-		                        " -l%.*s.lib", LIT(lib));
+		                        " -l%.*s", LIT(lib));
 		lib_str = gb_string_appendc(lib_str, lib_str_buf);
 		lib_str = gb_string_appendc(lib_str, lib_str_buf);
 	}
 	}
 
 
 	exit_code = win32_exec_command_line_app(
 	exit_code = win32_exec_command_line_app(
 		"clang %.*s.bc -o %.*s.exe "
 		"clang %.*s.bc -o %.*s.exe "
 		"-O0 "
 		"-O0 "
+		// "-O2 "
 		"-Wno-override-module "
 		"-Wno-override-module "
 		"%s",
 		"%s",
 		cast(int)base_name_len, output_name,
 		cast(int)base_name_len, output_name,

+ 34 - 16
src/parser.cpp

@@ -65,12 +65,19 @@ enum DeclKind {
 	Declaration_Count,
 	Declaration_Count,
 };
 };
 
 
-enum ProcTag {
+enum ProcTag : u64 {
 	ProcTag_bounds_check    = GB_BIT(0),
 	ProcTag_bounds_check    = GB_BIT(0),
 	ProcTag_no_bounds_check = GB_BIT(1),
 	ProcTag_no_bounds_check = GB_BIT(1),
-	ProcTag_foreign         = GB_BIT(2),
-	ProcTag_inline          = GB_BIT(3),
-	ProcTag_no_inline       = GB_BIT(4),
+
+	ProcTag_foreign         = GB_BIT(10),
+	ProcTag_inline          = GB_BIT(11),
+	ProcTag_no_inline       = GB_BIT(12),
+	ProcTag_dll_import      = GB_BIT(13),
+	ProcTag_dll_export      = GB_BIT(14),
+
+	ProcTag_stdcall         = GB_BIT(15),
+	ProcTag_fastcall        = GB_BIT(16),
+	// ProcTag_cdecl           = GB_BIT(17),
 };
 };
 
 
 enum VarDeclTag {
 enum VarDeclTag {
@@ -220,7 +227,7 @@ AST_NODE_KIND(_DeclBegin,      "", struct{}) \
 	AST_NODE_KIND(BadDecl,  "bad declaration", struct { Token begin, end; }) \
 	AST_NODE_KIND(BadDecl,  "bad declaration", struct { Token begin, end; }) \
 	AST_NODE_KIND(VarDecl,  "variable declaration", struct { \
 	AST_NODE_KIND(VarDecl,  "variable declaration", struct { \
 			DeclKind kind; \
 			DeclKind kind; \
-			u32      tags; \
+			u64      tags; \
 			b32      is_using; \
 			b32      is_using; \
 			AstNodeArray names; \
 			AstNodeArray names; \
 			AstNode *type; \
 			AstNode *type; \
@@ -1171,10 +1178,19 @@ b32 is_foreign_name_valid(String name) {
 
 
 void parse_proc_tags(AstFile *f, u64 *tags, String *foreign_name) {
 void parse_proc_tags(AstFile *f, u64 *tags, String *foreign_name) {
 	// TODO(bill): Add this to procedure literals too
 	// TODO(bill): Add this to procedure literals too
+
+
+
 	while (f->cursor[0].kind == Token_Hash) {
 	while (f->cursor[0].kind == Token_Hash) {
 		AstNode *tag_expr = parse_tag_expr(f, NULL);
 		AstNode *tag_expr = parse_tag_expr(f, NULL);
 		ast_node(te, TagExpr, tag_expr);
 		ast_node(te, TagExpr, tag_expr);
 		String tag_name = te->name.string;
 		String tag_name = te->name.string;
+
+		#define ELSE_IF_ADD_TAG(name) \
+		else if (are_strings_equal(tag_name, make_string(#name))) { \
+			check_proc_add_tag(f, tag_expr, tags, ProcTag_##name, tag_name); \
+		}
+
 		if (are_strings_equal(tag_name, make_string("foreign"))) {
 		if (are_strings_equal(tag_name, make_string("foreign"))) {
 			check_proc_add_tag(f, tag_expr, tags, ProcTag_foreign, tag_name);
 			check_proc_add_tag(f, tag_expr, tags, ProcTag_foreign, tag_name);
 			if (f->cursor[0].kind == Token_String) {
 			if (f->cursor[0].kind == Token_String) {
@@ -1186,19 +1202,21 @@ void parse_proc_tags(AstFile *f, u64 *tags, String *foreign_name) {
 
 
 				next_token(f);
 				next_token(f);
 			}
 			}
-		} else if (are_strings_equal(tag_name, make_string("bounds_check"))) {
-			check_proc_add_tag(f, tag_expr, tags, ProcTag_bounds_check, tag_name);
-		} else if (are_strings_equal(tag_name, make_string("no_bounds_check"))) {
-			check_proc_add_tag(f, tag_expr, tags, ProcTag_no_bounds_check, tag_name);
-		} else if (are_strings_equal(tag_name, make_string("inline"))) {
-			check_proc_add_tag(f, tag_expr, tags, ProcTag_inline, tag_name);
-		} else if (are_strings_equal(tag_name, make_string("no_inline"))) {
-			check_proc_add_tag(f, tag_expr, tags, ProcTag_no_inline, tag_name);
-		// } else if (are_strings_equal(tag_name, make_string("no_context"))) {
-			// check_proc_add_tag(f, tag_expr, tags, ProcTag_no_context, tag_name);
-		} else {
+		}
+		ELSE_IF_ADD_TAG(bounds_check)
+		ELSE_IF_ADD_TAG(no_bounds_check)
+		ELSE_IF_ADD_TAG(inline)
+		ELSE_IF_ADD_TAG(no_inline)
+		ELSE_IF_ADD_TAG(dll_import)
+		ELSE_IF_ADD_TAG(dll_export)
+		ELSE_IF_ADD_TAG(stdcall)
+		ELSE_IF_ADD_TAG(fastcall)
+		// ELSE_IF_ADD_TAG(cdecl)
+		else {
 			ast_file_err(f, ast_node_token(tag_expr), "Unknown procedure tag");
 			ast_file_err(f, ast_node_token(tag_expr), "Unknown procedure tag");
 		}
 		}
+
+		#undef ELSE_IF_ADD_TAG
 	}
 	}
 
 
 	if ((*tags & ProcTag_inline) && (*tags & ProcTag_no_inline)) {
 	if ((*tags & ProcTag_inline) && (*tags & ProcTag_no_inline)) {