From bfda1016860942564abdbfe86cbb3487469c8ea5 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 10 Feb 2020 00:14:43 +0000 Subject: Get basic IR code generation working properly --- src/checker.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/checker.cpp') diff --git a/src/checker.cpp b/src/checker.cpp index 3f9d3ba71..bfd2d3149 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1625,6 +1625,7 @@ void add_dependency_to_set(Checker *c, Entity *entity) { if (decl == nullptr) { return; } + for_array(i, decl->type_info_deps.entries) { Type *type = decl->type_info_deps.entries[i].ptr; add_min_dep_type_info(c, type); @@ -1670,8 +1671,8 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) { str_lit("type_table"), str_lit("__type_info_of"), str_lit("default_temp_allocator"), - str_lit("default_temp_allocator_init"), - str_lit("default_temp_allocator_destroy"), + // str_lit("default_temp_allocator_init"), + // str_lit("default_temp_allocator_destroy"), str_lit("default_temp_allocator_proc"), str_lit("Type_Info"), -- cgit v1.2.3 From 2180f4a475287546b9230745343ca3e0847525c6 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 23 Feb 2020 10:04:25 +0000 Subject: Basic work on obj generation --- LLVM-C.dll | Bin 0 -> 51116544 bytes build.bat | 7 +- core/mem/mem.odin | 6 +- core/runtime/internal.odin | 16 +-- core/runtime/procs_windows_amd64.odin | 18 +-- examples/llvm-demo/demo.odin | 80 ++++++------ src/checker.cpp | 2 + src/llvm_backend.cpp | 227 +++++++++++++++++++++++++++++----- src/llvm_backend.hpp | 11 ++ src/parser.hpp | 4 +- 10 files changed, 283 insertions(+), 88 deletions(-) create mode 100644 LLVM-C.dll (limited to 'src/checker.cpp') diff --git a/LLVM-C.dll b/LLVM-C.dll new file mode 100644 index 000000000..598db4d91 Binary files /dev/null and b/LLVM-C.dll differ diff --git a/build.bat b/build.bat index 58799c454..715171d7c 100644 --- a/build.bat +++ b/build.bat @@ -50,8 +50,13 @@ del *.ilk > NUL 2> NUL cl %compiler_settings% "src\main.cpp" ^ /link %linker_settings% -OUT:%exe_name% ^ && odin build examples/llvm-demo/demo.odin -llvm-api +if %errorlevel% neq 0 ( + goto end_of_build +) - rem && link -nologo llvm_demo.obj kernel32.lib -OUT:llvm_demo.exe +link llvm_demo.obj kernel32.lib user32.lib /OUT:llvm_demo.exe ^ + /nologo /incremental:no /opt:ref /subsystem:CONSOLE /defaultlib:libcmt -debug ^ + && llvm_demo del *.obj > NUL 2> NUL diff --git a/core/mem/mem.odin b/core/mem/mem.odin index 144ba07a8..c3aa76304 100644 --- a/core/mem/mem.odin +++ b/core/mem/mem.odin @@ -15,14 +15,14 @@ set :: proc "contextless" (data: rawptr, value: byte, len: int) -> rawptr { foreign _ { when size_of(rawptr) == 8 { @(link_name="llvm.memset.p0i8.i64") - llvm_memset :: proc(dst: rawptr, val: byte, len: int, align: i32, is_volatile: bool) ---; + llvm_memset :: proc(dst: rawptr, val: byte, len: int, is_volatile: bool) ---; } else { @(link_name="llvm.memset.p0i8.i32") - llvm_memset :: proc(dst: rawptr, val: byte, len: int, align: i32, is_volatile: bool) ---; + llvm_memset :: proc(dst: rawptr, val: byte, len: int, is_volatile: bool) ---; } } - llvm_memset(data, value, len, 1, false); + llvm_memset(data, value, len, false); return data; } zero :: inline proc "contextless" (data: rawptr, len: int) -> rawptr { diff --git a/core/runtime/internal.odin b/core/runtime/internal.odin index 60359fd6c..553920dc7 100644 --- a/core/runtime/internal.odin +++ b/core/runtime/internal.odin @@ -42,10 +42,10 @@ mem_zero :: proc "contextless" (data: rawptr, len: int) -> rawptr { foreign _ { when size_of(rawptr) == 8 { @(link_name="llvm.memset.p0i8.i64") - memset :: proc(dst: rawptr, val: byte, len: int, align: i32 = 1, is_volatile: bool = false) ---; + memset :: proc(dst: rawptr, val: byte, len: int, is_volatile: bool = false) ---; } else { @(link_name="llvm.memset.p0i8.i32") - memset :: proc(dst: rawptr, val: byte, len: int, align: i32 = 1, is_volatile: bool = false) ---; + memset :: proc(dst: rawptr, val: byte, len: int, is_volatile: bool = false) ---; } } } @@ -59,13 +59,13 @@ mem_copy :: proc "contextless" (dst, src: rawptr, len: int) -> rawptr { foreign _ { when size_of(rawptr) == 8 { @(link_name="llvm.memmove.p0i8.p0i8.i64") - llvm_memmove :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) ---; + llvm_memmove :: proc(dst, src: rawptr, len: int, is_volatile: bool = false) ---; } else { @(link_name="llvm.memmove.p0i8.p0i8.i32") - llvm_memmove :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) ---; + llvm_memmove :: proc(dst, src: rawptr, len: int, is_volatile: bool = false) ---; } } - llvm_memmove(dst, src, len, 1, false); + llvm_memmove(dst, src, len); return dst; } @@ -75,13 +75,13 @@ mem_copy_non_overlapping :: proc "contextless" (dst, src: rawptr, len: int) -> r foreign _ { when size_of(rawptr) == 8 { @(link_name="llvm.memcpy.p0i8.p0i8.i64") - llvm_memcpy :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) ---; + llvm_memcpy :: proc(dst, src: rawptr, len: int, is_volatile: bool = false) ---; } else { @(link_name="llvm.memcpy.p0i8.p0i8.i32") - llvm_memcpy :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) ---; + llvm_memcpy :: proc(dst, src: rawptr, len: int, is_volatile: bool = false) ---; } } - llvm_memcpy(dst, src, len, 1, false); + llvm_memcpy(dst, src, len); return dst; } diff --git a/core/runtime/procs_windows_amd64.odin b/core/runtime/procs_windows_amd64.odin index f5f582ccc..ebcbbe44e 100644 --- a/core/runtime/procs_windows_amd64.odin +++ b/core/runtime/procs_windows_amd64.odin @@ -2,15 +2,15 @@ package runtime foreign import kernel32 "system:Kernel32.lib" -@private -@(link_name="_tls_index") -_tls_index: u32; +// @private +// @(link_name="_tls_index") +// _tls_index: u32; -@private -@(link_name="_fltused") -_fltused: i32 = 0x9875; +// @private +// @(link_name="_fltused") +// _fltused: i32 = 0x9875; -@(link_name="memcpy") +// @(link_name="memcpy") memcpy :: proc "c" (dst, src: rawptr, len: int) -> rawptr { foreign kernel32 { RtlCopyMemory :: proc "c" (dst, src: rawptr, len: int) --- @@ -19,7 +19,7 @@ memcpy :: proc "c" (dst, src: rawptr, len: int) -> rawptr { return dst; } -@(link_name="memmove") +// @(link_name="memmove") memmove :: proc "c" (dst, src: rawptr, len: int) -> rawptr { foreign kernel32 { RtlMoveMemory :: proc "c" (dst, src: rawptr, len: int) --- @@ -28,7 +28,7 @@ memmove :: proc "c" (dst, src: rawptr, len: int) -> rawptr { return dst; } -@(link_name="memset") +// @(link_name="memset") memset :: proc "c" (ptr: rawptr, val: i32, len: int) -> rawptr { foreign kernel32 { RtlFillMemory :: proc "c" (dst: rawptr, len: int, fill: byte) --- diff --git a/examples/llvm-demo/demo.odin b/examples/llvm-demo/demo.odin index 578f98e0a..f89088005 100644 --- a/examples/llvm-demo/demo.odin +++ b/examples/llvm-demo/demo.odin @@ -1,56 +1,62 @@ package demo import "core:os" +import "core:sys/win32" -BarBar :: struct { - x, y: int, -}; -foo :: proc(x: int) -> (b: BarBar) { - b = {1, 2}; - return; +foreign import kernel32 "system:Kernel32.lib" +foreign import user32 "system:User32.lib" + +foreign user32 { + MessageBoxA :: proc "c" (hWnd: rawptr, text, caption: cstring, uType: u32) -> i32 --- } -main :: proc() { - Foo :: enum {A=1, B, C, D}; - Foo_Set :: bit_set[Foo]; - foo_set := Foo_Set{.A, .C}; +foreign kernel32 { + FlushFileBuffers :: proc "c" (hFile: win32.Handle) -> b32 --- +} - array := [4]int{3 = 1, 0 .. 1 = 3, 2 = 9}; - slice := []int{1, 2, 3, 4}; - x: ^int = nil; - y := slice != nil; - @thread_local a: int; +main :: proc() { + f := os.get_std_handle(win32.STD_OUTPUT_HANDLE); + os.write_string(f, "Hellope!\n"); + + // Foo :: enum {A=1, B, C, D}; + // Foo_Set :: bit_set[Foo]; + // foo_set := Foo_Set{.A, .C}; + + // array := [4]int{3 = 1, 0 .. 1 = 3, 2 = 9}; + // slice := []int{1, 2, 3, 4}; - if true { - foo(1); - } + // x: ^int = nil; + // y := slice != nil; - x1 := i32(1); - y1 := i32(2); - z1 := x1 + y1; - w1 := z1 - 2; + // @thread_local a: int; - f := foo; + // if true { + // foo(1); + // } - c := 1 + 2i; - q := 1 + 2i + 3j + 4k; + // x := i32(1); + // y := i32(2); + // z := x + y; + // w := z - 2; - s := "Hellope"; + // f := foo; - b := true; - aaa := b ? int(123) : int(34); - defer aaa = 333; + // c := 1 + 2i; + // q := 1 + 2i + 3j + 4k; - p := proc(x: int) {}; + // s := "Hellope"; + // b := true; + // aaa := b ? int(123) : int(34); + // defer aaa = 333; - bb := BarBar{1, 2}; - pc: proc "contextless" (x: i32) -> BarBar; - po: proc "odin" (x: i32) -> BarBar; - e: enum{A, B, C}; - u: union{i32, bool}; - u1: union{i32}; - um: union #maybe {^int}; + // bb := BarBar{1, 2}; + // pc: proc "contextless" (x: i32) -> BarBar; + // po: proc "odin" (x: i32) -> BarBar; + // e: enum{A, B, C}; + // u: union{i32, bool}; + // u1: union{i32}; + // um: union #maybe {^int}; } diff --git a/src/checker.cpp b/src/checker.cpp index bfd2d3149..23e27af87 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1685,6 +1685,8 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) { str_lit("udivti3"), str_lit("memset"), + str_lit("memcpy"), + str_lit("memmove"), str_lit("memory_compare"), str_lit("memory_compare_zero"), diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 8d4b47e78..fd7b7030d 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -199,6 +199,10 @@ lbValue lb_addr_load(lbProcedure *p, lbAddr const &addr) { } else if (addr.kind == lbAddr_SoaVariable) { GB_PANIC("lbAddr_SoaVariable"); } + + if (is_type_proc(addr.addr.type)) { + return addr.addr; + } return lb_emit_load(p, addr.addr); } @@ -831,7 +835,6 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity) { lb_add_entity(m, entity, proc_value); lb_add_member(m, p->name, proc_value); - LLVMContextRef ctx = LLVMGetModuleContext(m->mod); // NOTE(bill): offset==0 is the return value isize offset = 1; @@ -874,8 +877,29 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity) { lb_add_proc_attribute_at_index(p, offset+parameter_index, "noalias"); lb_add_proc_attribute_at_index(p, offset+parameter_index, "nonnull"); lb_add_proc_attribute_at_index(p, offset+parameter_index, "nocapture"); + } + + { // Debug Information + unsigned line = cast(unsigned)entity->token.pos.line; + LLVMMetadataRef file = nullptr; + if (entity->file != nullptr) { + cast(LLVMMetadataRef)entity->file->llvm_metadata; + } + LLVMMetadataRef scope = nullptr; + + + LLVMMetadataRef res = LLVMDIBuilderCreateFunction(m->debug_builder, scope, + cast(char const *)entity->token.string.text, entity->token.string.len, + cast(char const *)p->name.text, p->name.len, + file, line, nullptr, + true, p->body == nullptr, + line, LLVMDIFlagZero, false + ); + GB_ASSERT(res != nullptr); + map_set(&m->debug_values, hash_pointer(p), res); } + return p; } @@ -3163,6 +3187,14 @@ lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) { lb_addr_store(p, default_value, value); return lb_emit_conv(p, lb_addr_load(p, default_value), t_any); } else if (dst->kind == Type_Basic) { + if (src->Basic.kind == Basic_string && dst->Basic.kind == Basic_cstring) { + unsigned indices[1] = {0}; + LLVMValueRef data = LLVMConstExtractValue(value.value, indices, 1); + char const *text = nullptr; + size_t length = 0; + text = LLVMGetAsString(data, &length); + GB_PANIC("HERE %.*s", cast(int)length, text); + } // if (is_type_float(dst)) { // return value; // } else if (is_type_integer(dst)) { @@ -4110,7 +4142,7 @@ lbValue lb_emit_call_internal(lbProcedure *p, lbValue value, lbValue return_ptr, LLVMBasicBlockRef curr_block = LLVMGetInsertBlock(p->builder); GB_ASSERT(curr_block != p->decl_block->block); - LLVMValueRef ret = LLVMBuildCall(p->builder, value.value, args, arg_count, "");; + LLVMValueRef ret = LLVMBuildCall2(p->builder, LLVMGetElementType(lb_type(p->module, value.type)), value.value, args, arg_count, "");; lbValue res = {}; res.value = ret; res.type = abi_rt; @@ -7310,6 +7342,9 @@ bool lb_init_generator(lbGenerator *gen, Checker *c) { // gen->ctx = LLVMContextCreate(); gen->module.ctx = LLVMGetGlobalContext(); gen->module.mod = LLVMModuleCreateWithNameInContext("odin_module", gen->module.ctx); + gen->module.debug_builder = LLVMCreateDIBuilder(gen->module.mod); + + gb_mutex_init(&gen->module.mutex); gbAllocator a = heap_allocator(); map_init(&gen->module.types, a); @@ -7321,6 +7356,8 @@ bool lb_init_generator(lbGenerator *gen, Checker *c) { map_init(&gen->module.anonymous_proc_lits, a); array_init(&gen->module.procedures_to_generate, a); + map_init(&gen->module.debug_values, a); + return true; } @@ -7366,6 +7403,30 @@ void lb_generate_code(lbGenerator *gen) { auto *min_dep_set = &info->minimum_dependency_set; + { // Debug Info + for_array(i, info->files.entries) { + AstFile *f = info->files.entries[i].value; + String fullpath = f->fullpath; + String filename = filename_from_path(fullpath); + String directory = directory_from_path(fullpath); + LLVMMetadataRef res = LLVMDIBuilderCreateFile(m->debug_builder, + cast(char const *)filename.text, filename.len, + cast(char const *)directory.text, directory.len); + map_set(&m->debug_values, hash_pointer(f), res); + f->llvm_metadata = res; + } + + m->debug_compile_unit = LLVMDIBuilderCreateCompileUnit(m->debug_builder, LLVMDWARFSourceLanguageC, + cast(LLVMMetadataRef)m->info->files.entries[0].value->llvm_metadata, + "odin", 4, + false, "", 0, + 1, "", 0, + LLVMDWARFEmissionFull, 0, true, + true + ); + + } + isize global_variable_max_count = 0; Entity *entry_point = info->entry_point; @@ -7507,9 +7568,6 @@ void lb_generate_code(lbGenerator *gen) { case Entity_Procedure: break; } - if (e->token.string == "RtlFillMemory") { - gb_printf_err("%.*s\n", LIT(e->token.string)); - } bool polymorphic_struct = false; if (e->type != nullptr && e->kind == Entity_TypeName) { @@ -7533,14 +7591,6 @@ void lb_generate_code(lbGenerator *gen) { break; case Entity_Procedure: { - - if (e->pkg->name == "demo") { - // } else if (e->pkg->name == "runtime") { - // } else if (e->pkg->name == "os") { - } else { - // continue; - } - lbProcedure *p = lb_create_procedure(m, e); array_add(&m->procedures_to_generate, p); } @@ -7558,38 +7608,157 @@ void lb_generate_code(lbGenerator *gen) { lb_end_procedure(p); if (LLVMVerifyFunction(p->value, LLVMReturnStatusAction)) { - gb_printf_err("FAILED FOR: %.*s\n", LIT(p->name)); + gb_printf_err("LLVM CODE GEN FAILED FOR PROCEDURE: %.*s\n", LIT(p->name)); LLVMDumpValue(p->value); gb_printf_err("\n\n\n\n"); LLVMVerifyFunction(p->value, LLVMAbortProcessAction); + } + } + + + LLVMPassRegistryRef pass_registry = LLVMGetGlobalPassRegistry(); + LLVMPassManagerRef function_pass_manager = LLVMCreateFunctionPassManagerForModule(mod); + defer (LLVMDisposePassManager(function_pass_manager)); + + LLVMAddPromoteMemoryToRegisterPass(function_pass_manager); + LLVMAddMergedLoadStoreMotionPass(function_pass_manager); + LLVMAddAggressiveInstCombinerPass(function_pass_manager); + LLVMAddConstantPropagationPass(function_pass_manager); + LLVMAddAggressiveDCEPass(function_pass_manager); + LLVMAddDeadStoreEliminationPass(function_pass_manager); + LLVMAddLoopIdiomPass(function_pass_manager); + LLVMAddPromoteMemoryToRegisterPass(function_pass_manager); + // LLVMAddUnifyFunctionExitNodesPass(function_pass_manager); + + for_array(i, m->procedures_to_generate) { + lbProcedure *p = m->procedures_to_generate[i]; + if (p->body != nullptr) { // Build Procedure + LLVMRunFunctionPassManager(function_pass_manager, p->value); } } + LLVMPassManagerRef module_pass_manager = LLVMCreatePassManager(); + defer (LLVMDisposePassManager(module_pass_manager)); + LLVMAddAlwaysInlinerPass(module_pass_manager); + LLVMAddStripDeadPrototypesPass(module_pass_manager); + + LLVMPassManagerBuilderRef pass_manager_builder = LLVMPassManagerBuilderCreate(); + defer (LLVMPassManagerBuilderDispose(pass_manager_builder)); + LLVMPassManagerBuilderSetOptLevel(pass_manager_builder, 0); + LLVMPassManagerBuilderSetSizeLevel(pass_manager_builder, 0); + + LLVMPassManagerBuilderPopulateLTOPassManager(pass_manager_builder, module_pass_manager, false, false); + LLVMRunPassManager(module_pass_manager, mod); + gb_printf_err("Done\n"); + + + + if (!(build_context.is_dll && !has_dll_main)) { + LLVMContextRef ctx = LLVMGetModuleContext(mod); + + LLVMTypeRef llvm_i32 = LLVMInt32TypeInContext(ctx); + + LLVMTypeRef ptr_cstr = LLVMPointerType(LLVMPointerType(LLVMInt8TypeInContext(ctx), 0), 0); + LLVMTypeRef params[2] = {llvm_i32, ptr_cstr}; + LLVMTypeRef func_type = LLVMFunctionType(llvm_i32, params, gb_count_of(params), false); + + LLVMValueRef fn = LLVMAddFunction(mod, "main", func_type); + + LLVMBuilderRef builder = LLVMCreateBuilder(); + LLVMBasicBlockRef block = LLVMAppendBasicBlockInContext(ctx, fn, "entry"); + LLVMPositionBuilderAtEnd(builder, block); + + // for_array(i, global_variables) { + // auto *var = &global_variables[i]; + // if (var->decl->init_expr != nullptr) { + // var->init = ir_build_expr(proc, var->decl->init_expr); + // } + + // Entity *e = var->var->Global.entity; + // GB_ASSERT(e->kind == Entity_Variable); + + // if (e->Variable.is_foreign) { + // Entity *fl = e->Procedure.foreign_library; + // ir_add_foreign_library_path(m, fl); + // } + + // if (e->flags & EntityFlag_Static) { + // var->var->Global.is_internal = true; + // } + + // if (var->init != nullptr) { + // Type *t = type_deref(ir_type(var->var)); + + // if (is_type_any(t)) { + // // NOTE(bill): Edge case for 'any' type + // Type *var_type = default_type(ir_type(var->init)); + // irValue *g = ir_add_global_generated(proc->module, var_type, var->init); + // ir_emit_store(proc, g, var->init); + + // irValue *data = ir_emit_struct_ep(proc, var->var, 0); + // irValue *ti = ir_emit_struct_ep(proc, var->var, 1); + // ir_emit_store(proc, data, ir_emit_conv(proc, g, t_rawptr)); + // ir_emit_store(proc, ti, ir_type_info(proc, var_type)); + // } else { + // ir_emit_store(proc, var->var, ir_emit_conv(proc, var->init, t)); + // } + // } + // } + + lbValue *found = map_get(&m->values, hash_entity(entry_point)); + GB_ASSERT(found != nullptr); + + LLVMBuildCall2(builder, LLVMGetElementType(lb_type(m, found->type)), found->value, nullptr, 0, ""); + LLVMBuildRet(builder, LLVMConstInt(llvm_i32, 0, false)); + + LLVMDisposeBuilder(builder); + + if (LLVMVerifyFunction(fn, LLVMReturnStatusAction)) { + gb_printf_err("LLVM CODE GEN FAILED FOR PROCEDURE: %s\n", "main"); + LLVMDumpValue(fn); + gb_printf_err("\n\n\n\n"); + LLVMVerifyFunction(fn, LLVMAbortProcessAction); + } + + LLVMRunFunctionPassManager(function_pass_manager, fn); + + } + char *llvm_error = nullptr; defer (LLVMDisposeMessage(llvm_error)); - LLVMDumpModule(mod); - // LLVMVerifyModule(mod, LLVMAbortProcessAction, &llvm_error); + LLVMDIBuilderFinalize(m->debug_builder); + LLVMVerifyModule(mod, LLVMAbortProcessAction, &llvm_error); + llvm_error = nullptr; + LLVMBool failure = LLVMPrintModuleToFile(mod, "llvm_demo.ll", &llvm_error); + LLVMInitializeAllTargetInfos(); + LLVMInitializeAllTargets(); + LLVMInitializeAllTargetMCs(); + LLVMInitializeAllAsmPrinters(); + LLVMInitializeAllAsmParsers(); + LLVMInitializeAllDisassemblers(); + LLVMInitializeNativeTarget(); + char const *target_triple = "x86_64-pc-windows-msvc"; + char const *target_data_layout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"; + LLVMSetTarget(mod, target_triple); - // char const *target_triple = "x86_64-pc-windows-msvc"; - // char const *target_data_layout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"; - // LLVMSetTarget(mod, target_triple); + LLVMTargetRef target = {}; + LLVMGetTargetFromTriple(target_triple, &target, &llvm_error); + GB_ASSERT(target != nullptr); - // LLVMTargetRef target = {}; - // LLVMGetTargetFromTriple(target_triple, &target, &llvm_error); - // GB_ASSERT(target != nullptr); + LLVMTargetMachineRef target_machine = LLVMCreateTargetMachine(target, target_triple, "generic", "", LLVMCodeGenLevelNone, LLVMRelocDefault, LLVMCodeModelDefault); + defer (LLVMDisposeTargetMachine(target_machine)); - // LLVMTargetMachineRef target_machine = LLVMCreateTargetMachine(target, target_triple, "generic", "", LLVMCodeGenLevelNone, LLVMRelocDefault, LLVMCodeModelDefault); - // defer (LLVMDisposeTargetMachine(target_machine)); + LLVMBool ok = LLVMTargetMachineEmitToFile(target_machine, mod, "llvm_demo.obj", LLVMObjectFile, &llvm_error); + if (ok) { + gb_printf_err("LLVM Error: %s\n", llvm_error); + return; + } + gb_printf_err(".obj generated\n"); - // LLVMBool ok = LLVMTargetMachineEmitToFile(target_machine, mod, "llvm_demo.obj", LLVMObjectFile, &llvm_error); - // if (ok) { - // gb_printf_err("LLVM Error: %s\n", llvm_error); - // return; - // } } diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index e807e1c06..47ff5962b 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -4,9 +4,14 @@ #include "llvm-c/Analysis.h" #include "llvm-c/Object.h" #include "llvm-c/BitWriter.h" +#include "llvm-c/DebugInfo.h" #include "llvm-c/Transforms/AggressiveInstCombine.h" #include "llvm-c/Transforms/InstCombine.h" #include "llvm-c/Transforms/IPO.h" +#include "llvm-c/Transforms/PassManagerBuilder.h" +#include "llvm-c/Transforms/Scalar.h" +#include "llvm-c/Transforms/Utils.h" +#include "llvm-c/Transforms/Vectorize.h" struct lbProcedure; @@ -49,6 +54,7 @@ struct lbAddr { struct lbModule { LLVMModuleRef mod; LLVMContextRef ctx; + CheckerInfo *info; gbMutex mutex; @@ -70,6 +76,11 @@ struct lbModule { u32 global_generated_index; Array procedures_to_generate; + + + LLVMDIBuilderRef debug_builder; + LLVMMetadataRef debug_compile_unit; + Map debug_values; // Key: Pointer }; struct lbGenerator { diff --git a/src/parser.hpp b/src/parser.hpp index 00366d79a..70ef82995 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -98,7 +98,6 @@ struct AstFile { Array imports; // 'import' 'using import' isize directive_count; - Ast * curr_proc; isize error_count; @@ -111,6 +110,9 @@ struct AstFile { #define PARSER_MAX_FIX_COUNT 6 isize fix_count; TokenPos fix_prev_pos; + + struct LLVMOpaqueMetadata *llvm_metadata; + struct LLVMOpaqueMetadata *llvm_metadata_scope; }; -- cgit v1.2.3 From 28502ba53b32a0e5eb9aa7d8c41424fa090ff7ef Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 8 Mar 2020 12:34:36 +0000 Subject: Fix `context` system; add more to -show-more-timings for LLVM API; Add `ODIN_USE_LLVM_API` global constant --- build.bat | 7 ++--- core/runtime/internal.odin | 40 +++++++++++++++++++------- examples/demo/demo.odin | 2 +- src/checker.cpp | 1 + src/ir.cpp | 2 +- src/llvm_backend.cpp | 70 ++++++++++++++++++++++++---------------------- 6 files changed, 73 insertions(+), 49 deletions(-) (limited to 'src/checker.cpp') diff --git a/build.bat b/build.bat index 4f3f665f2..436e7852f 100644 --- a/build.bat +++ b/build.bat @@ -49,15 +49,14 @@ del *.ilk > NUL 2> NUL cl %compiler_settings% "src\main.cpp" ^ /link %linker_settings% -OUT:%exe_name% ^ - && odin build examples/demo/demo.odin -llvm-api -show-timings - rem && odin build examples/llvm-demo/demo.odin -llvm-api -show-timings + && odin build examples/demo/demo.odin -llvm-api -show-more-timings if %errorlevel% neq 0 ( goto end_of_build ) link demo.obj kernel32.lib user32.lib /OUT:llvm_demo.exe ^ - /nologo /incremental:no /opt:ref /subsystem:CONSOLE /defaultlib:libcmt -debug ^ - && llvm_demo + /nologo /incremental:no /opt:ref /subsystem:CONSOLE /defaultlib:libcmt -debug + rem && llvm_demo del *.obj > NUL 2> NUL diff --git a/core/runtime/internal.odin b/core/runtime/internal.odin index 01b9ed616..bcc91eb6b 100644 --- a/core/runtime/internal.odin +++ b/core/runtime/internal.odin @@ -57,12 +57,22 @@ mem_copy :: proc "contextless" (dst, src: rawptr, len: int) -> rawptr { if src == nil do return dst; // NOTE(bill): This _must_ be implemented like C's memmove foreign _ { - when size_of(rawptr) == 8 { - @(link_name="llvm.memmove.p0i8.p0i8.i64") - llvm_memmove :: proc(dst, src: rawptr, len: int, is_volatile: bool = false) ---; + when ODIN_USE_LLVM_API { + when size_of(rawptr) == 8 { + @(link_name="llvm.memmove.p0i8.p0i8.i64") + llvm_memmove :: proc(dst, src: rawptr, len: int, is_volatile: bool = false) ---; + } else { + @(link_name="llvm.memmove.p0i8.p0i8.i32") + llvm_memmove :: proc(dst, src: rawptr, len: int, is_volatile: bool = false) ---; + } } else { - @(link_name="llvm.memmove.p0i8.p0i8.i32") - llvm_memmove :: proc(dst, src: rawptr, len: int, is_volatile: bool = false) ---; + when size_of(rawptr) == 8 { + @(link_name="llvm.memmove.p0i8.p0i8.i64") + llvm_memmove :: proc(dst, src: rawptr, len: int, align: i32 = 1, is_volatile: bool = false) ---; + } else { + @(link_name="llvm.memmove.p0i8.p0i8.i32") + llvm_memmove :: proc(dst, src: rawptr, len: int, align: i32 = 1, is_volatile: bool = false) ---; + } } } llvm_memmove(dst, src, len); @@ -73,12 +83,22 @@ mem_copy_non_overlapping :: proc "contextless" (dst, src: rawptr, len: int) -> r if src == nil do return dst; // NOTE(bill): This _must_ be implemented like C's memcpy foreign _ { - when size_of(rawptr) == 8 { - @(link_name="llvm.memcpy.p0i8.p0i8.i64") - llvm_memcpy :: proc(dst, src: rawptr, len: int, is_volatile: bool = false) ---; + when ODIN_USE_LLVM_API { + when size_of(rawptr) == 8 { + @(link_name="llvm.memcpy.p0i8.p0i8.i64") + llvm_memcpy :: proc(dst, src: rawptr, len: int, is_volatile: bool = false) ---; + } else { + @(link_name="llvm.memcpy.p0i8.p0i8.i32") + llvm_memcpy :: proc(dst, src: rawptr, len: int, is_volatile: bool = false) ---; + } } else { - @(link_name="llvm.memcpy.p0i8.p0i8.i32") - llvm_memcpy :: proc(dst, src: rawptr, len: int, is_volatile: bool = false) ---; + when size_of(rawptr) == 8 { + @(link_name="llvm.memcpy.p0i8.p0i8.i64") + llvm_memcpy :: proc(dst, src: rawptr, len: int, align: i32 = 1, is_volatile: bool = false) ---; + } else { + @(link_name="llvm.memcpy.p0i8.p0i8.i32") + llvm_memcpy :: proc(dst, src: rawptr, len: int, align: i32 = 1, is_volatile: bool = false) ---; + } } } llvm_memcpy(dst, src, len); diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin index ed39eba8d..4ef9b2a8c 100644 --- a/examples/demo/demo.odin +++ b/examples/demo/demo.odin @@ -1940,7 +1940,7 @@ main :: proc() { struct_type(); union_type(); using_statement(); - // implicit_context_system(); + implicit_context_system(); parametric_polymorphism(); array_programming(); map_type(); diff --git a/src/checker.cpp b/src/checker.cpp index 23e27af87..0494bde4b 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -711,6 +711,7 @@ void init_universal(void) { add_global_string_constant(str_lit("ODIN_ROOT"), bc->ODIN_ROOT); add_global_constant(str_lit("ODIN_DEBUG"), t_untyped_bool, exact_value_bool(bc->ODIN_DEBUG)); add_global_constant(str_lit("ODIN_DISABLE_ASSERT"), t_untyped_bool, exact_value_bool(bc->ODIN_DISABLE_ASSERT)); + add_global_constant(str_lit("ODIN_USE_LLVM_API"), t_untyped_bool, exact_value_bool(bc->use_llvm_api)); // Builtin Procedures diff --git a/src/ir.cpp b/src/ir.cpp index c5b140991..16999a209 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -11445,7 +11445,7 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info ir_emit_store(proc, results, ir_get_type_info_ptr(proc, t->Proc.results)); } ir_emit_store(proc, variadic, ir_const_bool(t->Proc.variadic)); - ir_emit_store(proc, convention, ir_const_int(t->Proc.calling_convention)); + ir_emit_store(proc, convention, ir_const_u8(t->Proc.calling_convention)); // TODO(bill): TypeInfo for procedures break; diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 8ddd37677..554323b54 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -303,6 +303,8 @@ lbValue lb_addr_load(lbProcedure *p, lbAddr const &addr) { lbValue a = addr.addr; lbValue b = lb_emit_deep_field_gep(p, a, addr.ctx.sel); return lb_emit_load(p, b); + } else { + return lb_emit_load(p, addr.addr); } } else if (addr.kind == lbAddr_SoaVariable) { Type *t = type_deref(addr.addr.type); @@ -2002,30 +2004,15 @@ void lb_close_scope(lbProcedure *p, lbDeferExitKind kind, lbBlock *block, bool p GB_ASSERT(p->scope_index > 0); // NOTE(bill): Remove `context`s made in that scope - - isize end_idx = p->context_stack.count-1; - isize pop_count = 0; - - for (;;) { - if (end_idx < 0) { - break; - } - lbContextData *end = &p->context_stack[end_idx]; - if (end == nullptr) { - break; - } - if (end->scope_index != p->scope_index) { - break; - } - end_idx -= 1; - pop_count += 1; - } - if (pop_stack) { - for (isize i = 0; i < pop_count; i++) { + while (p->context_stack.count > 0) { + lbContextData *ctx = &p->context_stack[p->context_stack.count-1]; + if (ctx->scope_index >= p->scope_index) { array_pop(&p->context_stack); + } else { + break; } - } + } p->scope_index -= 1; } @@ -5292,15 +5279,19 @@ lbValue lb_emit_transmute(lbProcedure *p, lbValue value, Type *t) { } -void lb_emit_init_context(lbProcedure *p, lbValue c) { +void lb_emit_init_context(lbProcedure *p, lbAddr addr) { + GB_ASSERT(addr.kind == lbAddr_Context); + GB_ASSERT(addr.ctx.sel.index.count == 0); + lbModule *m = p->module; gbAllocator a = heap_allocator(); auto args = array_make(a, 1); - args[0] = c.value != nullptr ? c : m->global_default_context.addr; + args[0] = addr.addr; lb_emit_runtime_call(p, "__init_context", args); } void lb_push_context_onto_stack(lbProcedure *p, lbAddr ctx) { + ctx.kind = lbAddr_Context; lbContextData cd = {ctx, p->scope_index}; array_add(&p->context_stack, cd); } @@ -5315,7 +5306,7 @@ lbAddr lb_find_or_generate_context_ptr(lbProcedure *p) { c.kind = lbAddr_Context; lb_push_context_onto_stack(p, c); lb_addr_store(p, c, lb_addr_load(p, p->module->global_default_context)); - lb_emit_init_context(p, c.addr); + lb_emit_init_context(p, c); return c; } @@ -8307,7 +8298,7 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) { sel = selection_combine(addr.ctx.sel, sel); } addr.ctx.sel = sel; - + addr.kind = lbAddr_Context; return addr; } else if (addr.kind == lbAddr_SoaVariable) { lbValue index = addr.soa.index; @@ -10042,6 +10033,10 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da void lb_generate_code(lbGenerator *gen) { + #define TIME_SECTION(str) do { if (build_context.show_more_timings) timings_start_section(&global_timings, str_lit(str)); } while (0) + + TIME_SECTION("LLVM Global Variables"); + lbModule *m = &gen->module; LLVMModuleRef mod = gen->module.mod; CheckerInfo *info = gen->info; @@ -10051,7 +10046,7 @@ void lb_generate_code(lbGenerator *gen) { gbAllocator temp_allocator = arena_allocator(&temp_arena); gen->module.global_default_context = lb_add_global_generated(m, t_context, {}); - + gen->module.global_default_context.kind = lbAddr_Context; auto *min_dep_set = &info->minimum_dependency_set; @@ -10278,6 +10273,7 @@ void lb_generate_code(lbGenerator *gen) { } + TIME_SECTION("LLVM Global Procedures and Types"); for_array(i, info->entities) { // arena_free_all(&temp_arena); // gbAllocator a = temp_allocator; @@ -10335,6 +10331,7 @@ void lb_generate_code(lbGenerator *gen) { } } + TIME_SECTION("LLVM Procedure Generation"); for_array(i, m->procedures_to_generate) { lbProcedure *p = m->procedures_to_generate[i]; if (p->is_done) { @@ -10350,14 +10347,14 @@ void lb_generate_code(lbGenerator *gen) { if (LLVMVerifyFunction(p->value, LLVMReturnStatusAction)) { gb_printf_err("LLVM CODE GEN FAILED FOR PROCEDURE: %.*s\n", LIT(p->name)); - // LLVMDumpValue(p->value); - // gb_printf_err("\n\n\n\n"); - // LLVMVerifyFunction(p->value, LLVMAbortProcessAction); - exit(1); + LLVMDumpValue(p->value); + gb_printf_err("\n\n\n\n"); + LLVMVerifyFunction(p->value, LLVMAbortProcessAction); } } + TIME_SECTION("LLVM Function Pass"); LLVMPassRegistryRef pass_registry = LLVMGetGlobalPassRegistry(); LLVMPassManagerRef function_pass_manager = LLVMCreateFunctionPassManagerForModule(mod); @@ -10432,7 +10429,7 @@ void lb_generate_code(lbGenerator *gen) { } } - lb_emit_init_context(p, {}); + lb_emit_init_context(p, p->module->global_default_context); lb_end_procedure_body(p); @@ -10483,6 +10480,8 @@ void lb_generate_code(lbGenerator *gen) { } + TIME_SECTION("LLVM Module Pass"); + LLVMPassManagerRef module_pass_manager = LLVMCreatePassManager(); defer (LLVMDisposePassManager(module_pass_manager)); LLVMAddAlwaysInlinerPass(module_pass_manager); @@ -10490,8 +10489,8 @@ void lb_generate_code(lbGenerator *gen) { LLVMPassManagerBuilderRef pass_manager_builder = LLVMPassManagerBuilderCreate(); defer (LLVMPassManagerBuilderDispose(pass_manager_builder)); - LLVMPassManagerBuilderSetOptLevel(pass_manager_builder, 3); - LLVMPassManagerBuilderSetSizeLevel(pass_manager_builder, 3); + LLVMPassManagerBuilderSetOptLevel(pass_manager_builder, build_context.optimization_level); + LLVMPassManagerBuilderSetSizeLevel(pass_manager_builder, build_context.optimization_level); LLVMPassManagerBuilderPopulateLTOPassManager(pass_manager_builder, module_pass_manager, false, false); LLVMRunPassManager(module_pass_manager, mod); @@ -10513,6 +10512,8 @@ void lb_generate_code(lbGenerator *gen) { LLVMVerifyModule(mod, LLVMAbortProcessAction, &llvm_error); llvm_error = nullptr; + TIME_SECTION("LLVM Initializtion"); + LLVMInitializeAllTargetInfos(); LLVMInitializeAllTargets(); LLVMInitializeAllTargetMCs(); @@ -10521,6 +10522,8 @@ void lb_generate_code(lbGenerator *gen) { LLVMInitializeAllDisassemblers(); LLVMInitializeNativeTarget(); + timings_start_section(&global_timings, str_lit("LLVM Object Generation")); + char const *target_triple = "x86_64-pc-windows-msvc"; char const *target_data_layout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"; LLVMSetTarget(mod, target_triple); @@ -10539,4 +10542,5 @@ void lb_generate_code(lbGenerator *gen) { return; } +#undef TIME_SECTION } -- cgit v1.2.3