From 2d49a615630eb27d95c7cde67722f419a1977996 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 16 Aug 2016 18:53:02 +0100 Subject: [PATCH] defer statements --- build.bat | 2 +- examples/basic.odin | 7 +- examples/main.ll | 447 ++++++++----------------------------- examples/main.odin | 36 ++- examples/win32.odin | 8 + misc/shell.bat | 1 + src/checker/checker.cpp | 2 +- src/codegen/codegen.cpp | 1 + src/codegen/print_llvm.cpp | 7 +- src/codegen/ssa.cpp | 214 +++++++++++++----- src/gb/gb.h | 35 ++- src/parser.cpp | 1 + src/tokenizer.cpp | 31 +-- 13 files changed, 338 insertions(+), 454 deletions(-) diff --git a/build.bat b/build.bat index 87fe6c857..100b4bca6 100644 --- a/build.bat +++ b/build.bat @@ -45,7 +45,7 @@ pushd %build_dir% cl %compiler_settings% "..\src\main.cpp" ^ /link %linker_settings% -OUT:%exe_name% ^ - && call odin run ..\examples/main.odin + && odin run ..\examples/main.odin :do_not_compile_exe diff --git a/examples/basic.odin b/examples/basic.odin index 7d5a70f95..265d5cc83 100644 --- a/examples/basic.odin +++ b/examples/basic.odin @@ -121,10 +121,7 @@ print_uint_base :: proc(i, base : uint) { print_bool :: proc(b : bool) { - if b { - print_string("true"); - } else { - print_string("false"); - } + if b { print_string("true"); } + else { print_string("false"); } } diff --git a/examples/main.ll b/examples/main.ll index a1922d604..ed7f195a1 100644 --- a/examples/main.ll +++ b/examples/main.ll @@ -1,343 +1,119 @@ %.string = type {i8*, i64} ; Basic_string %.rawptr = type i8* ; Basic_rawptr -%HANDLE = type %.rawptr -%HWND = type %.rawptr -%HDC = type %.rawptr -%HINSTANCE = type %.rawptr -%HICON = type %.rawptr -%HCURSOR = type %.rawptr -%HMENU = type %.rawptr -%HBRUSH = type %.rawptr -%WPARAM = type i64 -%LPARAM = type i64 -%LRESULT = type i64 -%ATOM = type i16 -%POINT = type {i32, i32} -%BOOL = type i32 -%WNDPROC = type %LRESULT (%HWND, i32, %WPARAM, %LPARAM)* -%WNDCLASSEXA = type {i32, i32, %WNDPROC, i32, i32, %HINSTANCE, %HICON, %HCURSOR, %HBRUSH, i8*, i8*, %HICON} -%MSG = type {%HWND, i32, %WPARAM, %LPARAM, i32, %POINT} declare void @llvm.memmove.p0i8.p0i8.i64(i8*, i8*, i64, i32, i1) argmemonly nounwind -@constant = global i64 zeroinitializer -@win32_perf_count_freq = global i64 zeroinitializer -define i64 @win32_get_perf_count_freq() { -entry.-.0: - %0 = alloca i64, align 8 ; r - store i64 zeroinitializer, i64* %0 - %1 = getelementptr inbounds i64, i64* %0 - %2 = call i32 @QueryPerformanceFrequency(i64* %1) - %3 = load i64, i64* %0, align 8 - ret i64 %3 -} - -define double @time_now() { -entry.-.0: - %0 = load i64, i64* @win32_perf_count_freq, align 8 - %1 = icmp eq i64 %0, 0 - br i1 %1, label %if.then.-.1, label %if.done.-.2 - -if.then.-.1: - call void @llvm.debugtrap() - br label %if.done.-.2 - -if.done.-.2: - %2 = alloca i64, align 8 ; counter - store i64 zeroinitializer, i64* %2 - %3 = getelementptr inbounds i64, i64* %2 - %4 = call i32 @QueryPerformanceCounter(i64* %3) - %5 = alloca double, align 8 ; result - store double zeroinitializer, double* %5 - %6 = load i64, i64* @win32_perf_count_freq, align 8 - %7 = sitofp i64 %6 to double - %8 = load i64, i64* %2, align 8 - %9 = sitofp i64 %8 to double - %10 = fdiv double %9, %7 - store double %10, double* %5 - %11 = load double, double* %5, align 8 - ret double %11 -} - -define void @win32_print_last_error() { -entry.-.0: - %0 = alloca i64, align 8 ; err_code - store i64 zeroinitializer, i64* %0 - %1 = call i32 @GetLastError() - %2 = zext i32 %1 to i64 - store i64 %2, i64* %0 - %3 = load i64, i64* %0, align 8 - %4 = icmp ne i64 %3, 0 - br i1 %4, label %if.then.-.1, label %if.done.-.2 - -if.then.-.1: - %5 = getelementptr inbounds [14 x i8], [14 x i8]* @.str0, i64 0, i64 0 - %6 = alloca %.string, align 8 - store %.string zeroinitializer, %.string* %6 - %7 = getelementptr inbounds %.string, %.string* %6, i64 0, i32 0 - %8 = getelementptr inbounds %.string, %.string* %6, i64 0, i32 1 - store i8* %5, i8** %7 - store i64 14, i64* %8 - %9 = load %.string, %.string* %6, align 8 - call void @print_string(%.string %9) - %10 = load i64, i64* %0, align 8 - call void @print_int(i64 %10) - %11 = getelementptr inbounds [1 x i8], [1 x i8]* @.str1, i64 0, i64 0 - %12 = alloca %.string, align 8 - store %.string zeroinitializer, %.string* %12 - %13 = getelementptr inbounds %.string, %.string* %12, i64 0, i32 0 - %14 = getelementptr inbounds %.string, %.string* %12, i64 0, i32 1 - store i8* %11, i8** %13 - store i64 1, i64* %14 - %15 = load %.string, %.string* %12, align 8 - call void @print_string(%.string %15) - br label %if.done.-.2 - -if.done.-.2: - ret void -} - define void @main() { entry.-.0: call void @__$startup_runtime() - %0 = alloca %WNDCLASSEXA, align 8 ; wc - store %WNDCLASSEXA zeroinitializer, %WNDCLASSEXA* %0 - %1 = alloca %HINSTANCE, align 8 ; instance - store %HINSTANCE zeroinitializer, %HINSTANCE* %1 - %2 = call %HINSTANCE @GetModuleHandleA(i8* null) - store %HINSTANCE %2, %HINSTANCE* %1 - %3 = getelementptr inbounds i64, i64* @win32_perf_count_freq - %4 = call i32 @QueryPerformanceFrequency(i64* %3) - %5 = alloca i8*, align 8 ; class_name - store i8* zeroinitializer, i8** %5 - %6 = getelementptr inbounds [18 x i8], [18 x i8]* @.str2, i64 0, i64 0 - %7 = alloca %.string, align 8 - store %.string zeroinitializer, %.string* %7 - %8 = getelementptr inbounds %.string, %.string* %7, i64 0, i32 0 - %9 = getelementptr inbounds %.string, %.string* %7, i64 0, i32 1 - store i8* %6, i8** %8 - store i64 18, i64* %9 - %10 = load %.string, %.string* %7, align 8 - %11 = call i8* @main$to_c_string-0(%.string %10) - store i8* %11, i8** %5 - %12 = alloca i8*, align 8 ; title - store i8* zeroinitializer, i8** %12 - %13 = getelementptr inbounds [18 x i8], [18 x i8]* @.str3, i64 0, i64 0 - %14 = alloca %.string, align 8 - store %.string zeroinitializer, %.string* %14 - %15 = getelementptr inbounds %.string, %.string* %14, i64 0, i32 0 - %16 = getelementptr inbounds %.string, %.string* %14, i64 0, i32 1 - store i8* %13, i8** %15 - store i64 18, i64* %16 - %17 = load %.string, %.string* %14, align 8 - %18 = call i8* @main$to_c_string-0(%.string %17) - store i8* %18, i8** %12 - %19 = getelementptr inbounds %WNDCLASSEXA, %WNDCLASSEXA* %0, i64 0, i32 0 - store i32 80, i32* %19 - %20 = getelementptr inbounds %WNDCLASSEXA, %WNDCLASSEXA* %0, i64 0, i32 1 - store i32 3, i32* %20 - %21 = getelementptr inbounds %WNDCLASSEXA, %WNDCLASSEXA* %0, i64 0, i32 5 - %22 = load %HINSTANCE, %HINSTANCE* %1, align 8 - store %HINSTANCE %22, %HINSTANCE* %21 - %23 = getelementptr inbounds %WNDCLASSEXA, %WNDCLASSEXA* %0, i64 0, i32 10 - %24 = load i8*, i8** %5, align 8 - store i8* %24, i8** %23 - %25 = getelementptr inbounds %WNDCLASSEXA, %WNDCLASSEXA* %0, i64 0, i32 8 - %26 = inttoptr i64 1 to %.rawptr - store %HBRUSH %26, %HBRUSH* %25 - %27 = getelementptr inbounds %WNDCLASSEXA, %WNDCLASSEXA* %0, i64 0, i32 2 - store %WNDPROC @main$1, %WNDPROC* %27 - %28 = getelementptr inbounds %WNDCLASSEXA, %WNDCLASSEXA* %0 - %29 = call %ATOM @RegisterClassExA(%WNDCLASSEXA* %28) - %30 = icmp eq i16 %29, 0 - br i1 %30, label %if.then.-.1, label %if.done.-.2 + %0 = getelementptr inbounds [8 x i8], [8 x i8]* @.str0, i64 0, i64 0 + %1 = alloca %.string, align 8 + store %.string zeroinitializer, %.string* %1 + %2 = getelementptr inbounds %.string, %.string* %1, i64 0, i32 0 + %3 = getelementptr inbounds %.string, %.string* %1, i64 0, i32 1 + store i8* %0, i8** %2 + store i64 8, i64* %3 + %4 = load %.string, %.string* %1, align 8 + call void @print_string(%.string %4) + br label %for.init.-.1 -if.then.-.1: - ret void +for.init.-.1: + %5 = alloca i64, align 8 ; i + store i64 zeroinitializer, i64* %5 + store i64 0, i64* %5 + br label %for.loop.-.3 -if.done.-.2: - %31 = alloca %HWND, align 8 ; hwnd - store %HWND zeroinitializer, %HWND* %31 - %32 = load i8*, i8** %5, align 8 - %33 = load i8*, i8** %12, align 8 - %34 = load %HINSTANCE, %HINSTANCE* %1, align 8 - %35 = call %HWND @CreateWindowExA(i32 0, i8* %32, i8* %33, i32 281673728, i32 0, i32 0, i32 854, i32 480, %HWND null, %HMENU null, %HINSTANCE %34, %.rawptr null) - store %HWND %35, %HWND* %31 - %36 = load %HWND, %HWND* %31, align 8 - %37 = icmp eq %.rawptr %36, null - br i1 %37, label %if.then.-.3, label %if.done.-.4 +for.body.-.2: + %6 = load i64, i64* %5, align 8 + %7 = icmp sgt i64 %6, 2 + br i1 %7, label %if.then.-.5, label %if.done.-.9 -if.then.-.3: - call void @win32_print_last_error() - ret void +for.loop.-.3: + %8 = load i64, i64* %5, align 8 + %9 = icmp slt i64 %8, 4 + br i1 %9, label %for.body.-.2, label %for.done.-.13 -if.done.-.4: - %38 = alloca double, align 8 ; start_time - store double zeroinitializer, double* %38 - %39 = call double @time_now() - store double %39, double* %38 - %40 = alloca i1, align 1 ; running - store i1 zeroinitializer, i1* %40 - store i1 true, i1* %40 - %41 = alloca i64, align 8 ; tick_count - store i64 zeroinitializer, i64* %41 - store i64 0, i64* %41 - br label %for.loop.-.6 +for.post.-.4: + %10 = load i64, i64* %5, align 8 + %11 = add i64 %10, 1 + store i64 %11, i64* %5 + br label %for.loop.-.3 -for.body.-.5: - %42 = alloca double, align 8 ; curr_time - store double zeroinitializer, double* %42 - %43 = call double @time_now() - store double %43, double* %42 - %44 = alloca double, align 8 ; dt - store double zeroinitializer, double* %44 - %45 = load double, double* %38, align 8 - %46 = load double, double* %42, align 8 - %47 = fsub double %46, %45 - store double %47, double* %44 - %48 = load double, double* %44, align 8 - %49 = fcmp ogt double %48, 0x4000000000000000 - br i1 %49, label %if.then.-.7, label %if.done.-.8 +if.then.-.5: + br label %defer.-.6 -for.loop.-.6: - %50 = load i1, i1* %40, align 1 - br i1 %50, label %for.body.-.5, label %for.done.-.16 +defer.-.6: + %12 = getelementptr inbounds [6 x i8], [6 x i8]* @.str1, i64 0, i64 0 + %13 = alloca %.string, align 8 + store %.string zeroinitializer, %.string* %13 + %14 = getelementptr inbounds %.string, %.string* %13, i64 0, i32 0 + %15 = getelementptr inbounds %.string, %.string* %13, i64 0, i32 1 + store i8* %12, i8** %14 + store i64 6, i64* %15 + %16 = load %.string, %.string* %13, align 8 + call void @print_string(%.string %16) + br label %defer.-.7 -if.then.-.7: - store i1 false, i1* %40 - br label %if.done.-.8 +defer.-.7: + %17 = load i64, i64* %5, align 8 + call void @print_int(i64 %17) + call void @print_rune(i32 10) + br label %for.done.-.13 -if.done.-.8: - %51 = alloca %MSG, align 8 ; msg - store %MSG zeroinitializer, %MSG* %51 - br label %for.body.-.9 +defer.-.8: + %18 = getelementptr inbounds [6 x i8], [6 x i8]* @.str2, i64 0, i64 0 + %19 = alloca %.string, align 8 + store %.string zeroinitializer, %.string* %19 + %20 = getelementptr inbounds %.string, %.string* %19, i64 0, i32 0 + %21 = getelementptr inbounds %.string, %.string* %19, i64 0, i32 1 + store i8* %18, i8** %20 + store i64 6, i64* %21 + %22 = load %.string, %.string* %19, align 8 + call void @print_string(%.string %22) + br label %if.done.-.9 -for.body.-.9: - %52 = alloca i1, align 1 ; ok - store i1 zeroinitializer, i1* %52 - %53 = getelementptr inbounds %MSG, %MSG* %51 - %54 = call %BOOL @PeekMessageA(%MSG* %53, %HWND null, i32 0, i32 0, i32 1) - %55 = icmp ne i32 %54, 0 - store i1 %55, i1* %52 - %56 = load i1, i1* %52, align 1 - br i1 %56, label %if.done.-.11, label %if.then.-.10 +if.done.-.9: + %23 = load i64, i64* %5, align 8 + %24 = icmp eq i64 %23, 2 + br i1 %24, label %if.then.-.10, label %if.done.-.11 if.then.-.10: - br label %for.done.-.15 + br label %if.done.-.11 if.done.-.11: - %57 = getelementptr inbounds %MSG, %MSG* %51, i64 0, i32 1 - %58 = load i32, i32* %57, align 4 - %59 = icmp eq i32 %58, 18 - br i1 %59, label %if.then.-.12, label %if.else.-.13 + br label %defer.-.12 -if.then.-.12: - ret void - -if.else.-.13: - %60 = getelementptr inbounds %MSG, %MSG* %51 - %61 = call %BOOL @TranslateMessage(%MSG* %60) - %62 = getelementptr inbounds %MSG, %MSG* %51 - %63 = call %LRESULT @DispatchMessageA(%MSG* %62) - br label %if.done.-.14 - -if.done.-.14: - br label %for.body.-.9 - -for.done.-.15: - %64 = getelementptr inbounds [6 x i8], [6 x i8]* @.str4, i64 0, i64 0 - %65 = alloca %.string, align 8 - store %.string zeroinitializer, %.string* %65 - %66 = getelementptr inbounds %.string, %.string* %65, i64 0, i32 0 - %67 = getelementptr inbounds %.string, %.string* %65, i64 0, i32 1 - store i8* %64, i8** %66 - store i64 6, i64* %67 - %68 = load %.string, %.string* %65, align 8 - call void @print_string(%.string %68) - %69 = load i64, i64* %41, align 8 - call void @print_int(i64 %69) - %70 = load i64, i64* %41, align 8 - %71 = add i64 %70, 1 - store i64 %71, i64* %41 +defer.-.12: + %25 = load i64, i64* %5, align 8 + call void @print_int(i64 %25) call void @print_rune(i32 10) - call void @sleep_ms(i32 16) - br label %for.loop.-.6 + br label %for.post.-.4 -for.done.-.16: +for.done.-.13: + %26 = getelementptr inbounds [13 x i8], [13 x i8]* @.str3, i64 0, i64 0 + %27 = alloca %.string, align 8 + store %.string zeroinitializer, %.string* %27 + %28 = getelementptr inbounds %.string, %.string* %27, i64 0, i32 0 + %29 = getelementptr inbounds %.string, %.string* %27, i64 0, i32 1 + store i8* %26, i8** %28 + store i64 13, i64* %29 + %30 = load %.string, %.string* %27, align 8 + call void @print_string(%.string %30) + br label %defer.-.14 + +defer.-.14: + %31 = getelementptr inbounds [6 x i8], [6 x i8]* @.str4, i64 0, i64 0 + %32 = alloca %.string, align 8 + store %.string zeroinitializer, %.string* %32 + %33 = getelementptr inbounds %.string, %.string* %32, i64 0, i32 0 + %34 = getelementptr inbounds %.string, %.string* %32, i64 0, i32 1 + store i8* %31, i8** %33 + store i64 6, i64* %34 + %35 = load %.string, %.string* %32, align 8 + call void @print_string(%.string %35) ret void } -define i8* @main$to_c_string-0(%.string %s) { -entry.-.0: - %0 = alloca %.string, align 8 ; s - store %.string zeroinitializer, %.string* %0 - store %.string %s, %.string* %0 - %1 = alloca i8*, align 8 ; c_str - store i8* zeroinitializer, i8** %1 - %2 = getelementptr inbounds %.string, %.string* %0, i64 0, i32 1 - %3 = load i64, i64* %2, align 8 - %4 = add i64 %3, 1 - %5 = call %.rawptr @malloc(i64 %4) - %6 = bitcast %.rawptr %5 to i8* - store i8* %6, i8** %1 - %7 = load i8*, i8** %1, align 8 - %8 = getelementptr inbounds %.string, %.string* %0, i64 0, i32 0 - %9 = load i8*, i8** %8, align 8 - %10 = getelementptr i8, i8* %9, i64 0 - %11 = getelementptr inbounds i8, i8* %10 - %12 = getelementptr inbounds %.string, %.string* %0, i64 0, i32 1 - %13 = load i64, i64* %12, align 8 - %14 = call i32 @memcpy(%.rawptr %7, %.rawptr %11, i64 %13) - %15 = load i8*, i8** %1, align 8 - %16 = getelementptr inbounds %.string, %.string* %0, i64 0, i32 1 - %17 = load i64, i64* %16, align 8 - %18 = getelementptr i8, i8* %15, i64 %17 - store i8 0, i8* %18 - %19 = load i8*, i8** %1, align 8 - ret i8* %19 -} - -define %LRESULT @main$1(%HWND %hwnd, i32 %msg, %WPARAM %wparam, %LPARAM %lparam) noinline { -entry.-.0: - %0 = alloca %HWND, align 8 ; hwnd - store %HWND zeroinitializer, %HWND* %0 - store %HWND %hwnd, %HWND* %0 - %1 = alloca i32, align 4 ; msg - store i32 zeroinitializer, i32* %1 - store i32 %msg, i32* %1 - %2 = alloca %WPARAM, align 8 ; wparam - store %WPARAM zeroinitializer, %WPARAM* %2 - store %WPARAM %wparam, %WPARAM* %2 - %3 = alloca %LPARAM, align 8 ; lparam - store %LPARAM zeroinitializer, %LPARAM* %3 - store %LPARAM %lparam, %LPARAM* %3 - %4 = load i32, i32* %1, align 4 - %5 = icmp eq i32 %4, 2 - br i1 %5, label %if.then.-.1, label %cmp-or.-.3 - -if.then.-.1: - call void @ExitProcess(i32 0) - ret %LRESULT 0 - -cmp-or.-.2: - %6 = load i32, i32* %1, align 4 - %7 = icmp eq i32 %6, 18 - br i1 %7, label %if.then.-.1, label %if.done.-.4 - -cmp-or.-.3: - %8 = load i32, i32* %1, align 4 - %9 = icmp eq i32 %8, 16 - br i1 %9, label %if.then.-.1, label %cmp-or.-.2 - -if.done.-.4: - %10 = load %HWND, %HWND* %0, align 8 - %11 = load i32, i32* %1, align 4 - %12 = load %WPARAM, %WPARAM* %2, align 8 - %13 = load %LPARAM, %LPARAM* %3, align 8 - %14 = call %LRESULT @DefWindowProcA(%HWND %10, i32 %11, %WPARAM %12, %LPARAM %13) - ret i64 %14 -} - define void @print_string(%.string %s) { entry.-.0: %0 = alloca %.string, align 8 ; s @@ -973,36 +749,6 @@ if.done.-.3: ret void } -declare %HANDLE @GetStdHandle(i32 %h) ; foreign -declare i32 @CloseHandle(%HANDLE %h) ; foreign -declare i32 @WriteFileA(%HANDLE %h, %.rawptr %buf, i32 %len, i32* %written_result, %.rawptr %overlapped) ; foreign -declare i32 @GetLastError() ; foreign -declare void @ExitProcess(i32 %exit_code) ; foreign -declare %HWND @GetDesktopWindow() ; foreign -declare i32 @GetCursorPos(%POINT* %p) ; foreign -declare i32 @ScreenToClient(%HWND %h, %POINT* %p) ; foreign -declare %HINSTANCE @GetModuleHandleA(i8* %module_name) ; foreign -declare i32 @QueryPerformanceFrequency(i64* %result) ; foreign -declare i32 @QueryPerformanceCounter(i64* %result) ; foreign -define void @sleep_ms(i32 %ms) { -entry.-.0: - %0 = alloca i32, align 4 ; ms - store i32 zeroinitializer, i32* %0 - store i32 %ms, i32* %0 - %1 = load i32, i32* %0, align 4 - %2 = call i32 @Sleep(i32 %1) - ret void -} - -declare i32 @Sleep(i32 %ms) declare void @OutputDebugStringA(i8* %c_str) ; foreign -declare %ATOM @RegisterClassExA(%WNDCLASSEXA* %wc) ; foreign -declare %HWND @CreateWindowExA(i32 %ex_style, i8* %class_name, i8* %title, i32 %style, i32 %x, i32 %y, i32 %w, i32 %h, %HWND %parent, %HMENU %menu, %HINSTANCE %instance, %.rawptr %param) ; foreign -declare %BOOL @ShowWindow(%HWND %hwnd, i32 %cmd_show) ; foreign -declare %BOOL @UpdateWindow(%HWND %hwnd) ; foreign -declare %BOOL @PeekMessageA(%MSG* %msg, %HWND %hwnd, i32 %msg_filter_min, i32 %msg_filter_max, i32 %remove_msg) ; foreign -declare %BOOL @TranslateMessage(%MSG* %msg) ; foreign -declare %LRESULT @DispatchMessageA(%MSG* %msg) ; foreign -declare %LRESULT @DefWindowProcA(%HWND %hwnd, i32 %msg, %WPARAM %wparam, %LPARAM %lparam) ; foreign declare i32 @putchar(i32 %c) ; foreign declare %.rawptr @malloc(i64 %sz) ; foreign declare void @free(%.rawptr %ptr) ; foreign @@ -1249,20 +995,17 @@ entry.-.0: ret i1 %5 } -@.str0 = global [14 x i8] c"GetLastError\3A\20" -@.str1 = global [1 x i8] c"\0A" -@.str2 = global [18 x i8] c"Odin-Language-Demo" -@.str3 = global [18 x i8] c"Odin\20Language\20Demo" -@.str4 = global [6 x i8] c"Tick\3A\20" +@.str0 = global [8 x i8] c"Hellope\0A" +@.str1 = global [6 x i8] c"break\0A" +@.str2 = global [6 x i8] c"break\0A" +@.str3 = global [13 x i8] c"Never\20called\0A" +@.str4 = global [6 x i8] c"World\0A" @.str5 = global [64 x i8] c"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\40$" @.str6 = global [64 x i8] c"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\40$" @.str7 = global [4 x i8] c"true" @.str8 = global [5 x i8] c"false" -define void @__$startup_runtime() { +define void @__$startup_runtime() noinline { entry.-.0: - %0 = call i64 @win32_get_perf_count_freq() - store i64 1, i64* @constant - store i64 %0, i64* @win32_perf_count_freq ret void } diff --git a/examples/main.odin b/examples/main.odin index e9562d48c..fd1dca9ef 100644 --- a/examples/main.odin +++ b/examples/main.odin @@ -1,16 +1,34 @@ #load "basic.odin" -#load "win32.odin" -constant := 1; +main :: proc() { + print_string("Hellope\n"); + defer print_string("World\n"); -win32_perf_count_freq: i64 = win32_get_perf_count_freq(); -win32_get_perf_count_freq :: proc() -> i64 { - r: i64; - _ = QueryPerformanceFrequency(^r); - return r; + for i := 0; i < 4; i++ { + defer { + print_int(i); + print_rune('\n'); + } + + if i > 2 { + defer print_string("break\n"); + break; + } + if i == 2 { + // return; + } + } + + print_string("Never called\n"); } + +/* +#load "win32.odin" + +win32_perf_count_freq := GetQueryPerformanceFrequency(); + time_now :: proc() -> f64 { if win32_perf_count_freq == 0 { debug_trap(); @@ -22,7 +40,6 @@ time_now :: proc() -> f64 { return result; } - win32_print_last_error :: proc() { err_code := GetLastError() as int; if err_code != 0 { @@ -33,6 +50,7 @@ win32_print_last_error :: proc() { } main :: proc() { +/* wc: WNDCLASSEXA; instance := GetModuleHandleA(null); @@ -113,4 +131,6 @@ main :: proc() { sleep_ms(16); } +*/ } +*/ diff --git a/examples/win32.odin b/examples/win32.odin index 14d779f4d..c647d66dd 100644 --- a/examples/win32.odin +++ b/examples/win32.odin @@ -101,3 +101,11 @@ TranslateMessage :: proc(msg: ^MSG) -> BOOL #foreign DispatchMessageA :: proc(msg: ^MSG) -> LRESULT #foreign DefWindowProcA :: proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT #foreign + + + +GetQueryPerformanceFrequency :: proc() -> i64 { + r: i64; + _ = QueryPerformanceFrequency(^r); + return r; +} diff --git a/misc/shell.bat b/misc/shell.bat index 1296a50be..2253d0439 100644 --- a/misc/shell.bat +++ b/misc/shell.bat @@ -5,5 +5,6 @@ rem call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" set _NO_DEBUG_HEAP=1 set path=w:\Odin\misc;%path% +wmic cls diff --git a/src/checker/checker.cpp b/src/checker/checker.cpp index a27a54f87..225e94a95 100644 --- a/src/checker/checker.cpp +++ b/src/checker/checker.cpp @@ -594,7 +594,7 @@ void check_parsed_files(Checker *c) { isize entity_index = 0; Entity **entities = gb_alloc_array(c->allocator, Entity *, entity_count); DeclInfo *di = NULL; - if (vd->value_count == 1) { + if (vd->value_count > 0) { di = make_declaration_info(gb_heap_allocator(), c->global_scope); di->entities = entities; di->entity_count = entity_count; diff --git a/src/codegen/codegen.cpp b/src/codegen/codegen.cpp index 15afec217..34933b2a9 100644 --- a/src/codegen/codegen.cpp +++ b/src/codegen/codegen.cpp @@ -128,6 +128,7 @@ void ssa_gen_code(ssaGen *s) { map_set(&m->members, hash_string(name), p); ssaProcedure *proc = &p->proc; + proc->tags = ProcTag_no_inline; // TODO(bill): is no_inline a good idea? ssa_begin_procedure_body(proc); diff --git a/src/codegen/print_llvm.cpp b/src/codegen/print_llvm.cpp index 80bc320cb..36b9156de 100644 --- a/src/codegen/print_llvm.cpp +++ b/src/codegen/print_llvm.cpp @@ -274,6 +274,7 @@ void ssa_print_instr(gbFile *f, ssaModule *m, ssaValue *value) { ssaInstr *instr = &value->instr; ssa_fprintf(f, "\t"); + switch (instr->kind) { case ssaInstr_StartupRuntime: { ssa_fprintf(f, "call void @" SSA_STARTUP_RUNTIME_PROC_NAME "()\n"); @@ -354,7 +355,11 @@ void ssa_print_instr(gbFile *f, ssaModule *m, ssaValue *value) { ssa_fprintf(f, ", %d\n", instr->extract_value.index); } break; - case ssaInstr_Br: { + case ssaInstr_NoOp: {; + ssa_fprintf(f, "%%%d = add i32 0, 0\n", value->id); + } break; + + case ssaInstr_Br: {; ssa_fprintf(f, "br "); if (instr->br.cond != NULL) { ssa_print_type(f, m->sizes, t_bool); diff --git a/src/codegen/ssa.cpp b/src/codegen/ssa.cpp index f9393dcff..3e19e5932 100644 --- a/src/codegen/ssa.cpp +++ b/src/codegen/ssa.cpp @@ -23,6 +23,7 @@ struct ssaBlock { i32 id; AstNode *node; Scope *scope; + isize scope_index; String label; ssaProcedure *parent; @@ -37,6 +38,17 @@ struct ssaTargetList { ssaBlock * fallthrough_; }; +enum ssaDeferKind { + ssaDefer_Default, + ssaDefer_Return, + ssaDefer_Branch, +}; +struct ssaDefer { + AstNode *stmt; + isize scope_index; + ssaBlock *block; +}; + struct ssaProcedure { ssaProcedure *parent; gbArray(ssaProcedure *) children; @@ -48,6 +60,8 @@ struct ssaProcedure { AstNode * body; u64 tags; + isize scope_index; + gbArray(ssaDefer) defer_stmts; gbArray(ssaBlock *) blocks; ssaBlock * curr_block; ssaTargetList * target_list; @@ -71,6 +85,7 @@ struct ssaProcedure { SSA_INSTR_KIND(BinaryOp), \ SSA_INSTR_KIND(Call), \ SSA_INSTR_KIND(MemCopy), \ + SSA_INSTR_KIND(NoOp), \ SSA_INSTR_KIND(ExtractElement), \ SSA_INSTR_KIND(InsertElement), \ SSA_INSTR_KIND(ShuffleVector), \ @@ -121,7 +136,6 @@ struct ssaInstr { ssaBlock *parent; Type *type; - TokenPos pos; union { struct { @@ -637,6 +651,13 @@ ssaValue *ssa_make_instr_insert_element(ssaProcedure *p, ssaValue *vector, ssaVa return v; } +ssaValue *ssa_make_instr_no_op(ssaProcedure *p) { + ssaValue *v = ssa_alloc_instr(p->module->allocator, ssaInstr_NoOp); + if (p->curr_block) { + gb_array_append(p->curr_block->values, v); + } + return v; +} @@ -682,11 +703,16 @@ b32 ssa_is_blank_ident(AstNode *node) { ssaInstr *ssa_get_last_instr(ssaBlock *block) { - isize len = gb_array_count(block->instrs); - if (len > 0) { - ssaValue *v = block->instrs[len-1]; - GB_ASSERT(v->kind == ssaValue_Instr); - return &v->instr; + if (block != NULL) { + isize len = 0; + if (block->instrs != NULL) { + len = gb_array_count(block->instrs); + } + if (len > 0) { + ssaValue *v = block->instrs[len-1]; + GB_ASSERT(v->kind == ssaValue_Instr); + return &v->instr; + } } return NULL; @@ -762,36 +788,77 @@ Type *ssa_lvalue_type(ssaLvalue lval) { return NULL; } - -void ssa_build_stmt(ssaProcedure *proc, AstNode *s); - -void ssa_emit_defer_stmts(ssaProcedure *proc, ssaBlock *block) { - if (block == NULL) - return; - - // IMPORTANT TODO(bill): ssa defer - Place where needed!!! - -#if 0 - Scope *curr_scope = block->scope; - if (curr_scope == NULL) { - // GB_PANIC("No scope found for deferred statements"); - } - - for (Scope *s = curr_scope; s != NULL; s = s->parent) { - isize count = gb_array_count(s->deferred_stmts); - for (isize i = count-1; i >= 0; i--) { - ssa_build_stmt(proc, s->deferred_stmts[i]); +ssaBlock *ssa__make_block(ssaProcedure *proc, AstNode *node, String label) { + Scope *scope = NULL; + if (node != NULL) { + Scope **found = map_get(&proc->module->info->scopes, hash_pointer(node)); + if (found) { + scope = *found; + } else { + GB_PANIC("Block scope not found for %.*s", LIT(ast_node_strings[node->kind])); } } -#endif + + ssaValue *block = ssa_make_value_block(proc, node, scope, label); + return &block->block; } +ssaBlock *ssa_add_block(ssaProcedure *proc, AstNode *node, String label) { + ssaBlock *block = ssa__make_block(proc, node, label); + gb_array_append(proc->blocks, block); + return block; +} + +void ssa_build_stmt(ssaProcedure *proc, AstNode *s); +void ssa_emit_no_op(ssaProcedure *proc); +void ssa_emit_jump(ssaProcedure *proc, ssaBlock *block); + +void ssa_build_defer_stmt(ssaProcedure *proc, ssaDefer d) { + ssaBlock *b = ssa__make_block(proc, NULL, make_string("defer")); + // HACK(bill): The prev block may defer injection before it's terminator + ssaInstr *last_instr = ssa_get_last_instr(proc->curr_block); + if (last_instr == NULL || !ssa_is_instr_terminating(last_instr)) { + ssa_emit_jump(proc, b); + } + gb_array_append(proc->blocks, b); + proc->curr_block = b; + ssa_build_stmt(proc, d.stmt); +} + +void ssa_emit_defer_stmts(ssaProcedure *proc, ssaDeferKind kind, ssaBlock *block) { + isize count = gb_array_count(proc->defer_stmts); + isize i = count; + while (i --> 0) { + ssaDefer d = proc->defer_stmts[i]; + if (kind == ssaDefer_Return) { + ssa_build_defer_stmt(proc, d); + } else if (kind == ssaDefer_Default) { + if (proc->scope_index == d.scope_index) { + ssa_build_defer_stmt(proc, d); + gb_array_pop(proc->defer_stmts); + continue; + } else { + break; + } + } else if (kind == ssaDefer_Branch) { + GB_ASSERT(block != NULL); + isize lower_limit = block->scope_index+1; + if (lower_limit < d.scope_index) { + ssa_build_defer_stmt(proc, d); + } + } + } +} + + + + void ssa_emit_unreachable(ssaProcedure *proc) { ssa_emit(proc, ssa_make_instr_unreachable(proc)); } void ssa_emit_ret(ssaProcedure *proc, ssaValue *v) { - ssa_emit_defer_stmts(proc, proc->curr_block); + ssa_emit_defer_stmts(proc, ssaDefer_Return, NULL); ssa_emit(proc, ssa_make_instr_ret(proc, v)); } @@ -806,6 +873,11 @@ void ssa_emit_if(ssaProcedure *proc, ssaValue *cond, ssaBlock *true_block, ssaBl proc->curr_block = NULL; } +void ssa_emit_no_op(ssaProcedure *proc) { + ssa_emit(proc, ssa_make_instr_no_op(proc)); +} + + ssaValue *ssa_lvalue_store(ssaProcedure *proc, ssaLvalue lval, ssaValue *value) { if (lval.address != NULL) { @@ -838,30 +910,10 @@ ssaValue *ssa_lvalue_load(ssaProcedure *proc, ssaLvalue lval) { -ssaBlock *ssa__make_block(ssaProcedure *proc, AstNode *node, String label) { - Scope *scope = NULL; - if (node != NULL) { - Scope **found = map_get(&proc->module->info->scopes, hash_pointer(node)); - if (found) { - scope = *found; - } else { - GB_PANIC("Block scope not found for %.*s", LIT(ast_node_strings[node->kind])); - } - } - - ssaValue *block = ssa_make_value_block(proc, node, scope, label); - return &block->block; -} - -ssaBlock *ssa_add_block(ssaProcedure *proc, AstNode *node, String label) { - ssaBlock *block = ssa__make_block(proc, node, label); - gb_array_append(proc->blocks, block); - return block; -} - void ssa_begin_procedure_body(ssaProcedure *proc) { gb_array_init(proc->blocks, 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")); if (proc->type->proc.params != NULL) { @@ -878,6 +930,13 @@ void ssa_end_procedure_body(ssaProcedure *proc) { ssa_emit_ret(proc, NULL); } + +#if 0 + gb_for_array(i, proc->defer_stmts) { + gb_printf("defer %td - %p\n", proc->defer_stmts[i].scope_index, proc->defer_stmts[i].stmt); + } +#endif + // Number blocks and registers i32 reg_id = 0; gb_for_array(i, proc->blocks) { @@ -2214,11 +2273,18 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) { case_end; case_ast_node(bs, BlockStmt, node); + proc->scope_index++; ssa_build_stmt_list(proc, bs->list); + ssa_emit_defer_stmts(proc, ssaDefer_Default, NULL); + proc->scope_index--; case_end; - case_ast_node(bs, DeferStmt, node); - GB_PANIC("DeferStmt"); + case_ast_node(ds, DeferStmt, node); + isize scope_index = proc->scope_index; + if (ds->stmt->kind == AstNode_BlockStmt) + scope_index--; + ssaDefer d = {ds->stmt, scope_index, proc->curr_block}; + gb_array_append(proc->defer_stmts, d); case_end; case_ast_node(rs, ReturnStmt, node); @@ -2250,7 +2316,6 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) { } v = ssa_emit_load(proc, v); } - ssa_emit_ret(proc, v); case_end; @@ -2271,12 +2336,23 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) { ssa_build_cond(proc, is->cond, then, else_); proc->curr_block = then; + + proc->scope_index++; ssa_build_stmt(proc, is->body); + ssa_emit_defer_stmts(proc, ssaDefer_Default, NULL); + proc->scope_index--; + ssa_emit_jump(proc, done); if (is->else_stmt != NULL) { proc->curr_block = else_; + + proc->scope_index++; ssa_build_stmt(proc, is->else_stmt); + ssa_emit_defer_stmts(proc, ssaDefer_Default, NULL); + proc->scope_index--; + + ssa_emit_jump(proc, done); } gb_array_append(proc->blocks, done); @@ -2301,6 +2377,7 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) { ssaBlock *cont = loop; if (fs->post != NULL) { cont = ssa_add_block(proc, node, make_string("for.post")); + } ssa_emit_jump(proc, loop); proc->curr_block = loop; @@ -2310,7 +2387,12 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) { } ssa_push_target_list(proc, done, cont, NULL); + + proc->scope_index++; ssa_build_stmt(proc, fs->body); + ssa_emit_defer_stmts(proc, ssaDefer_Default, NULL); + proc->scope_index--; + ssa_pop_target_list(proc); ssa_emit_jump(proc, cont); @@ -2319,6 +2401,8 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) { ssa_build_stmt(proc, fs->post); ssa_emit_jump(proc, loop); } + + gb_array_append(proc->blocks, done); proc->curr_block = done; @@ -2327,16 +2411,24 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) { case_ast_node(bs, BranchStmt, node); ssaBlock *block = NULL; switch (bs->token.kind) { - #define BRANCH_GET_BLOCK(kind_) \ - case GB_JOIN2(Token_, kind_): { \ - for (ssaTargetList *t = proc->target_list; t != NULL && block == NULL; t = t->prev) { \ - block = GB_JOIN3(t->, kind_, _); \ - } \ - } break - BRANCH_GET_BLOCK(break); - BRANCH_GET_BLOCK(continue); - BRANCH_GET_BLOCK(fallthrough); - #undef BRANCH_GET_BLOCK + case Token_break: { + for (ssaTargetList *t = proc->target_list; t != NULL && block == NULL; t = t->prev) { + block = t->break_; + } + } break; + case Token_continue: { + for (ssaTargetList *t = proc->target_list; t != NULL && block == NULL; t = t->prev) { + block = t->continue_; + } + } break; + case Token_fallthrough: { + for (ssaTargetList *t = proc->target_list; t != NULL && block == NULL; t = t->prev) { + block = t->fallthrough_; + } + } break; + } + if (block != NULL && bs->token.kind != Token_fallthrough) { + ssa_emit_defer_stmts(proc, ssaDefer_Branch, block); } ssa_emit_jump(proc, block); ssa_emit_unreachable(proc); diff --git a/src/gb/gb.h b/src/gb/gb.h index 7a4824fbc..a75d6d97d 100644 --- a/src/gb/gb.h +++ b/src/gb/gb.h @@ -5917,21 +5917,36 @@ gb_inline isize gb_strnlen(char const *str, isize max_len) { } gb_inline isize gb_utf8_strlen(u8 const *str) { - isize result = 0; - for (; *str; str++) { - if ((*str & 0xc0) != 0x80) - result++; + isize count = 0; + for (; *str; count++) { + u8 c = *str; + isize inc = 0; + if (c < 0x80) inc = 1; + else if ((c & 0xe0) == 0xc0) inc = 2; + else if ((c & 0xf0) == 0xe0) inc = 3; + else if ((c & 0xf8) == 0xf0) inc = 4; + else return -1; + + str += inc; } - return result; + return count; } gb_inline isize gb_utf8_strnlen(u8 const *str, isize max_len) { - isize result = 0; - for (; *str && result < max_len; str++) { - if ((*str & 0xc0) != 0x80) - result++; + isize count = 0; + for (; *str && max_len > 0; count++) { + u8 c = *str; + isize inc = 0; + if (c < 0x80) inc = 1; + else if ((c & 0xe0) == 0xc0) inc = 2; + else if ((c & 0xf0) == 0xe0) inc = 3; + else if ((c & 0xf8) == 0xf0) inc = 4; + else return -1; + + str += inc; + max_len -= inc; } - return result; + return count; } diff --git a/src/parser.cpp b/src/parser.cpp index 5818875bb..cce4bc551 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1834,6 +1834,7 @@ AstNode *parse_if_stmt(AstFile *f) { } body = parse_block_stmt(f); + if (allow_token(f, Token_else)) { switch (f->cursor[0].kind) { case Token_if: diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 8d7848d53..4c6db0a76 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -263,10 +263,7 @@ void tokenizer_err_(Tokenizer *t, char *function, char *msg, ...) { if (column < 1) column = 1; -#if 0 - gb_printf_err("%s()\n", function); -#endif - gb_printf_err("%s(%td:%td) ", t->fullpath, t->line_count, column); + gb_printf_err("%.*s(%td:%td) Syntax error: ", LIT(t->fullpath), t->line_count, column); va_start(va, msg); gb_printf_err_va(msg, va); @@ -360,6 +357,9 @@ gb_inline void destroy_tokenizer(Tokenizer *t) { gb_free(gb_heap_allocator(), t->start); } if (t->allocated_strings != NULL) { + gb_for_array(i, t->allocated_strings) { + gb_free(gb_heap_allocator(), t->allocated_strings[i].text); + } gb_array_free(t->allocated_strings); } } @@ -618,7 +618,7 @@ Token tokenizer_get_token(Tokenizer *t) { token.string.len = t->curr - token.string.text; - // NOTE(bill): ALL identifiers are > 1 + // NOTE(bill): All keywords are > 1 if (token.string.len > 1) { if (are_strings_equal(token.string, token_strings[Token_as])) { token.kind = Token_as; @@ -706,18 +706,19 @@ Token tokenizer_get_token(Tokenizer *t) { } } - if (valid && len != 1) - tokenizer_err(t, "Illegal rune literal"); token.string.len = t->curr - token.string.text; - - i32 success = unquote_string(gb_heap_allocator(), &token.string); - if (success > 0) { - if (success == 2) { - gb_array_append(t->allocated_strings, token.string); - } - return token; + if (valid && len != 1) { + tokenizer_err(t, "Invalid rune literal %.*s", LIT(token.string)); } else { - tokenizer_err(t, "Invalid rune literal"); + i32 success = unquote_string(gb_heap_allocator(), &token.string); + if (success > 0) { + if (success == 2) { + gb_array_append(t->allocated_strings, token.string); + } + return token; + } else { + tokenizer_err(t, "Invalid rune literal %.*s", LIT(token.string)); + } } } break;