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/bin/llvm/windows/LLVM-C.lib b/bin/llvm/windows/LLVM-C.lib new file mode 100644 index 000000000..2353c6a39 Binary files /dev/null and b/bin/llvm/windows/LLVM-C.lib differ diff --git a/build.bat b/build.bat index 013a199a7..f39e8cbac 100644 --- a/build.bat +++ b/build.bat @@ -13,12 +13,14 @@ if "%1" == "1" ( ) set compiler_flags= -nologo -Oi -TP -fp:precise -Gm- -MP -FC -EHsc- -GR- -GF +set compiler_defines= -DLLVM_BACKEND_SUPPORT + if %release_mode% EQU 0 ( rem Debug set compiler_flags=%compiler_flags% -Od -MDd -Z7 - rem -DDISPLAY_TIMING ) else ( rem Release - set compiler_flags=%compiler_flags% -O2 -MT -Z7 -DNO_ARRAY_BOUNDS_CHECK + set compiler_flags=%compiler_flags% -O2 -MT -Z7 + set compiler_defines=%compiler_defines% -DNO_ARRAY_BOUNDS_CHECK ) set compiler_warnings= ^ @@ -30,7 +32,8 @@ set compiler_warnings= ^ set compiler_includes= set libs= ^ - kernel32.lib + kernel32.lib ^ + bin\llvm\windows\LLVM-C.lib set linker_flags= -incremental:no -opt:ref -subsystem:console @@ -40,7 +43,7 @@ if %release_mode% EQU 0 ( rem Debug set linker_flags=%linker_flags% -debug ) -set compiler_settings=%compiler_includes% %compiler_flags% %compiler_warnings% +set compiler_settings=%compiler_includes% %compiler_flags% %compiler_warnings% %compiler_defines% set linker_settings=%libs% %linker_flags% del *.pdb > NUL 2> NUL @@ -49,6 +52,9 @@ del *.ilk > NUL 2> NUL cl %compiler_settings% "src\main.cpp" ^ /link %linker_settings% -OUT:%exe_name% ^ && odin run examples/demo/demo.odin +if %errorlevel% neq 0 ( + goto end_of_build +) del *.obj > NUL 2> NUL diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index b9bb1ee2c..372002e8f 100644 --- a/core/fmt/fmt.odin +++ b/core/fmt/fmt.odin @@ -59,13 +59,13 @@ fprintf :: proc(fd: os.Handle, fmt: string, args: ..any) -> int { // print* procedures return the number of bytes written -print :: proc(args: ..any) -> int { return fprint(context.stdout, ..args); } -println :: proc(args: ..any) -> int { return fprintln(context.stdout, ..args); } -printf :: proc(fmt: string, args: ..any) -> int { return fprintf(context.stdout, fmt, ..args); } +print :: proc(args: ..any) -> int { return fprint(os.stdout, ..args); } +println :: proc(args: ..any) -> int { return fprintln(os.stdout, ..args); } +printf :: proc(fmt: string, args: ..any) -> int { return fprintf(os.stdout, fmt, ..args); } -eprint :: proc(args: ..any) -> int { return fprint(context.stderr, ..args); } -eprintln :: proc(args: ..any) -> int { return fprintln(context.stderr, ..args); } -eprintf :: proc(fmt: string, args: ..any) -> int { return fprintf(context.stderr, fmt, ..args); } +eprint :: proc(args: ..any) -> int { return fprint(os.stderr, ..args); } +eprintln :: proc(args: ..any) -> int { return fprintln(os.stderr, ..args); } +eprintf :: proc(fmt: string, args: ..any) -> int { return fprintf(os.stderr, fmt, ..args); } @(deprecated="prefer eprint") print_err :: proc(args: ..any) -> int { return eprint(..args); } diff --git a/core/mem/mem.odin b/core/mem/mem.odin index 36313e95b..f753a579d 100644 --- a/core/mem/mem.odin +++ b/core/mem/mem.odin @@ -13,16 +13,26 @@ swap :: proc{swap16, swap32, swap64}; 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) ---; + when ODIN_USE_LLVM_API { + when size_of(rawptr) == 8 { + @(link_name="llvm.memset.p0i8.i64") + 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, is_volatile: bool = false) ---; + } } else { - @(link_name="llvm.memset.p0i8.i32") - llvm_memset :: proc(dst: rawptr, val: byte, len: int, align: i32, is_volatile: bool) ---; + 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) ---; + } else { + @(link_name="llvm.memset.p0i8.i32") + memset :: proc(dst: rawptr, val: byte, len: int, align: i32 = 1, is_volatile: bool = false) ---; + } } } - llvm_memset(data, value, len, 1, false); + memset(data, value, len); return data; } zero :: inline proc "contextless" (data: rawptr, len: int) -> rawptr { diff --git a/core/os/os_windows.odin b/core/os/os_windows.odin index 0b1a53955..4eb9a3ec8 100644 --- a/core/os/os_windows.odin +++ b/core/os/os_windows.odin @@ -201,7 +201,7 @@ stdout := get_std_handle(win32.STD_OUTPUT_HANDLE); stderr := get_std_handle(win32.STD_ERROR_HANDLE); -get_std_handle :: proc(h: int) -> Handle { +get_std_handle :: proc "contextless" (h: int) -> Handle { fd := win32.get_std_handle(i32(h)); win32.set_handle_information(fd, win32.HANDLE_FLAG_INHERIT, 0); return Handle(fd); diff --git a/core/runtime/core.odin b/core/runtime/core.odin index 87af6b7bb..13b3ef008 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -288,9 +288,9 @@ Context :: struct { assertion_failure_proc: Assertion_Failure_Proc, logger: Logger, - stdin: os.Handle, - stdout: os.Handle, - stderr: os.Handle, + // stdin: os.Handle, + // stdout: os.Handle, + // stderr: os.Handle, thread_id: int, @@ -463,9 +463,9 @@ __init_context :: proc "contextless" (c: ^Context) { c.logger.procedure = default_logger_proc; c.logger.data = nil; - c.stdin = os.stdin; - c.stdout = os.stdout; - c.stderr = os.stderr; + // c.stdin = os.stdin; + // c.stdout = os.stdout; + // c.stderr = os.stderr; } @builtin @@ -474,7 +474,7 @@ init_global_temporary_allocator :: proc(data: []byte, backup_allocator := contex } default_assertion_failure_proc :: proc(prefix, message: string, loc: Source_Code_Location) { - fd := context.stderr; + fd := os.stderr; print_caller_location(fd, loc); os.write_string(fd, " "); os.write_string(fd, prefix); diff --git a/core/runtime/internal.odin b/core/runtime/internal.odin index 68d613c1b..2d4388bb2 100644 --- a/core/runtime/internal.odin +++ b/core/runtime/internal.odin @@ -40,12 +40,22 @@ mem_zero :: proc "contextless" (data: rawptr, len: int) -> rawptr { if len < 0 do return data; when !#defined(memset) { 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) ---; + when ODIN_USE_LLVM_API { + when size_of(rawptr) == 8 { + @(link_name="llvm.memset.p0i8.i64") + 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, 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) ---; + 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) ---; + } else { + @(link_name="llvm.memset.p0i8.i32") + memset :: proc(dst: rawptr, val: byte, len: int, align: i32 = 1, is_volatile: bool = false) ---; + } } } } @@ -57,15 +67,25 @@ 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, align: i32, is_volatile: bool) ---; + 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, align: i32, is_volatile: bool) ---; + 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, 1, false); + llvm_memmove(dst, src, len); return dst; } @@ -73,15 +93,25 @@ 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, align: i32, is_volatile: bool) ---; + 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, align: i32, is_volatile: bool) ---; + 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, 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/demo/demo.odin b/examples/demo/demo.odin index 9704d3e36..4ef9b2a8c 100644 --- a/examples/demo/demo.odin +++ b/examples/demo/demo.odin @@ -1245,7 +1245,7 @@ implicit_selector_expression :: proc() { switch f { case .A: - fmt.println("HERE"); + fmt.println("HITHER"); case .B: fmt.println("NEVER"); case .C: @@ -1742,6 +1742,7 @@ range_statements_with_multiple_return_values :: proc() { } } + soa_struct_layout :: proc() { // IMPORTANT NOTE(bill, 2019-11-03): This feature is subject to be changed/removed // NOTE(bill): Most likely #soa [N]T diff --git a/examples/llvm-demo/demo.odin b/examples/llvm-demo/demo.odin new file mode 100644 index 000000000..03ea5fbb4 --- /dev/null +++ b/examples/llvm-demo/demo.odin @@ -0,0 +1,7 @@ +package demo + +import "core:fmt" + +main :: proc() { + fmt.println("Hellope!", 123, true, 1.3); +} diff --git a/src/build_settings.cpp b/src/build_settings.cpp index e5f3bf5a2..8cb40cadc 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -128,6 +128,8 @@ struct BuildContext { bool cross_compiling; bool use_subsystem_windows; + bool use_llvm_api; + QueryDataSetSettings query_data_set_settings; gbAffinity affinity; diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 0e12a2822..13f05c5b5 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -625,6 +625,7 @@ void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) { check_open_scope(ctx, pl->type); defer (check_close_scope(ctx)); + ctx->scope->procedure_entity = e; Type *decl_type = nullptr; diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 4fdffcaa3..cda9debfa 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -5675,7 +5675,7 @@ isize add_dependencies_from_unpacking(CheckerContext *c, Entity **lhs, isize lhs c->decl = decl; // will be reset by the 'defer' any way for_array(k, decl->deps.entries) { Entity *dep = decl->deps.entries[k].ptr; - add_declaration_dependency(c, dep); // TODO(bill): Should this be here? + add_declaration_dependency(c, dep); // TODO(bill): Should this be here? } } } @@ -7257,6 +7257,16 @@ ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *call, Type *t } Type *pt = base_type(proc_type); + + #if 0 + if (pt->kind == Type_Proc && pt->Proc.calling_convention == ProcCC_Odin) { + init_core_context(c->checker); + GB_ASSERT(t_context != nullptr); + GB_ASSERT(t_context->kind == Type_Named); + add_declaration_dependency(c, t_context->Named.type_name); + } + #endif + if (result_type == nullptr) { operand->mode = Addressing_NoValue; } else { @@ -7680,6 +7690,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type return kind; } + pl->decl = decl; check_procedure_later(ctx.checker, ctx.file, empty_token, decl, type, pl->body, pl->tags); } check_close_scope(&ctx); diff --git a/src/checker.cpp b/src/checker.cpp index c840faa45..c8b737df8 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 @@ -1627,6 +1628,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); @@ -1672,8 +1674,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"), @@ -1686,6 +1688,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/checker.hpp b/src/checker.hpp index afa16e261..bd36971df 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -182,6 +182,7 @@ struct Scope { union { AstPackage *pkg; AstFile * file; + Entity * procedure_entity; }; }; @@ -381,3 +382,5 @@ void destroy_checker_poly_path(CheckerPolyPath *); void check_poly_path_push(CheckerContext *c, Type *t); Type *check_poly_path_pop (CheckerContext *c); + +void init_core_context(Checker *c); diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 6c1b5a792..32cc3809d 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -1021,8 +1021,7 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type * } else if (is_type_enumerated_array(type)) { ast_node(cl, CompoundLit, value.value_compound); - Type *index_type = type->EnumeratedArray.elem; - Type *elem_type = type->Array.elem; + Type *elem_type = type->EnumeratedArray.elem; isize elem_count = cl->elems.count; if (elem_count == 0) { ir_write_str_lit(f, "zeroinitializer"); diff --git a/src/llvm-c/Analysis.h b/src/llvm-c/Analysis.h new file mode 100644 index 000000000..cb9e8ece3 --- /dev/null +++ b/src/llvm-c/Analysis.h @@ -0,0 +1,65 @@ +/*===-- llvm-c/Analysis.h - Analysis Library C Interface --------*- C++ -*-===*\ +|* *| +|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *| +|* Exceptions. *| +|* See https://llvm.org/LICENSE.txt for license information. *| +|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This header declares the C interface to libLLVMAnalysis.a, which *| +|* implements various analyses of the LLVM IR. *| +|* *| +|* Many exotic languages can interoperate with C code but have a harder time *| +|* with C++ due to name mangling. So in addition to C, this interface enables *| +|* tools written in such languages. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_C_ANALYSIS_H +#define LLVM_C_ANALYSIS_H + +#include "llvm-c/Types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup LLVMCAnalysis Analysis + * @ingroup LLVMC + * + * @{ + */ + +typedef enum { + LLVMAbortProcessAction, /* verifier will print to stderr and abort() */ + LLVMPrintMessageAction, /* verifier will print to stderr and return 1 */ + LLVMReturnStatusAction /* verifier will just return 1 */ +} LLVMVerifierFailureAction; + + +/* Verifies that a module is valid, taking the specified action if not. + Optionally returns a human-readable description of any invalid constructs. + OutMessage must be disposed with LLVMDisposeMessage. */ +LLVMBool LLVMVerifyModule(LLVMModuleRef M, LLVMVerifierFailureAction Action, + char **OutMessage); + +/* Verifies that a single function is valid, taking the specified action. Useful + for debugging. */ +LLVMBool LLVMVerifyFunction(LLVMValueRef Fn, LLVMVerifierFailureAction Action); + +/* Open up a ghostview window that displays the CFG of the current function. + Useful for debugging. */ +void LLVMViewFunctionCFG(LLVMValueRef Fn); +void LLVMViewFunctionCFGOnly(LLVMValueRef Fn); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/llvm-c/BitReader.h b/src/llvm-c/BitReader.h new file mode 100644 index 000000000..b307ee979 --- /dev/null +++ b/src/llvm-c/BitReader.h @@ -0,0 +1,85 @@ +/*===-- llvm-c/BitReader.h - BitReader Library C Interface ------*- C++ -*-===*\ +|* *| +|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *| +|* Exceptions. *| +|* See https://llvm.org/LICENSE.txt for license information. *| +|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This header declares the C interface to libLLVMBitReader.a, which *| +|* implements input of the LLVM bitcode format. *| +|* *| +|* Many exotic languages can interoperate with C code but have a harder time *| +|* with C++ due to name mangling. So in addition to C, this interface enables *| +|* tools written in such languages. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_C_BITREADER_H +#define LLVM_C_BITREADER_H + +#include "llvm-c/Types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup LLVMCBitReader Bit Reader + * @ingroup LLVMC + * + * @{ + */ + +/* Builds a module from the bitcode in the specified memory buffer, returning a + reference to the module via the OutModule parameter. Returns 0 on success. + Optionally returns a human-readable error message via OutMessage. + + This is deprecated. Use LLVMParseBitcode2. */ +LLVMBool LLVMParseBitcode(LLVMMemoryBufferRef MemBuf, LLVMModuleRef *OutModule, + char **OutMessage); + +/* Builds a module from the bitcode in the specified memory buffer, returning a + reference to the module via the OutModule parameter. Returns 0 on success. */ +LLVMBool LLVMParseBitcode2(LLVMMemoryBufferRef MemBuf, + LLVMModuleRef *OutModule); + +/* This is deprecated. Use LLVMParseBitcodeInContext2. */ +LLVMBool LLVMParseBitcodeInContext(LLVMContextRef ContextRef, + LLVMMemoryBufferRef MemBuf, + LLVMModuleRef *OutModule, char **OutMessage); + +LLVMBool LLVMParseBitcodeInContext2(LLVMContextRef ContextRef, + LLVMMemoryBufferRef MemBuf, + LLVMModuleRef *OutModule); + +/** Reads a module from the specified path, returning via the OutMP parameter + a module provider which performs lazy deserialization. Returns 0 on success. + Optionally returns a human-readable error message via OutMessage. + This is deprecated. Use LLVMGetBitcodeModuleInContext2. */ +LLVMBool LLVMGetBitcodeModuleInContext(LLVMContextRef ContextRef, + LLVMMemoryBufferRef MemBuf, + LLVMModuleRef *OutM, char **OutMessage); + +/** Reads a module from the specified path, returning via the OutMP parameter a + * module provider which performs lazy deserialization. Returns 0 on success. */ +LLVMBool LLVMGetBitcodeModuleInContext2(LLVMContextRef ContextRef, + LLVMMemoryBufferRef MemBuf, + LLVMModuleRef *OutM); + +/* This is deprecated. Use LLVMGetBitcodeModule2. */ +LLVMBool LLVMGetBitcodeModule(LLVMMemoryBufferRef MemBuf, LLVMModuleRef *OutM, + char **OutMessage); + +LLVMBool LLVMGetBitcodeModule2(LLVMMemoryBufferRef MemBuf, LLVMModuleRef *OutM); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/llvm-c/BitWriter.h b/src/llvm-c/BitWriter.h new file mode 100644 index 000000000..187051555 --- /dev/null +++ b/src/llvm-c/BitWriter.h @@ -0,0 +1,59 @@ +/*===-- llvm-c/BitWriter.h - BitWriter Library C Interface ------*- C++ -*-===*\ +|* *| +|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *| +|* Exceptions. *| +|* See https://llvm.org/LICENSE.txt for license information. *| +|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This header declares the C interface to libLLVMBitWriter.a, which *| +|* implements output of the LLVM bitcode format. *| +|* *| +|* Many exotic languages can interoperate with C code but have a harder time *| +|* with C++ due to name mangling. So in addition to C, this interface enables *| +|* tools written in such languages. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_C_BITWRITER_H +#define LLVM_C_BITWRITER_H + +#include "llvm-c/Types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup LLVMCBitWriter Bit Writer + * @ingroup LLVMC + * + * @{ + */ + +/*===-- Operations on modules ---------------------------------------------===*/ + +/** Writes a module to the specified path. Returns 0 on success. */ +int LLVMWriteBitcodeToFile(LLVMModuleRef M, const char *Path); + +/** Writes a module to an open file descriptor. Returns 0 on success. */ +int LLVMWriteBitcodeToFD(LLVMModuleRef M, int FD, int ShouldClose, + int Unbuffered); + +/** Deprecated for LLVMWriteBitcodeToFD. Writes a module to an open file + descriptor. Returns 0 on success. Closes the Handle. */ +int LLVMWriteBitcodeToFileHandle(LLVMModuleRef M, int Handle); + +/** Writes a module to a new memory buffer and returns it. */ +LLVMMemoryBufferRef LLVMWriteBitcodeToMemoryBuffer(LLVMModuleRef M); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/llvm-c/Comdat.h b/src/llvm-c/Comdat.h new file mode 100644 index 000000000..81fee3fc9 --- /dev/null +++ b/src/llvm-c/Comdat.h @@ -0,0 +1,75 @@ +/*===-- llvm-c/Comdat.h - Module Comdat C Interface -------------*- C++ -*-===*\ +|* *| +|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *| +|* Exceptions. *| +|* See https://llvm.org/LICENSE.txt for license information. *| +|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This file defines the C interface to COMDAT. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_C_COMDAT_H +#define LLVM_C_COMDAT_H + +#include "llvm-c/Types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + LLVMAnyComdatSelectionKind, ///< The linker may choose any COMDAT. + LLVMExactMatchComdatSelectionKind, ///< The data referenced by the COMDAT must + ///< be the same. + LLVMLargestComdatSelectionKind, ///< The linker will choose the largest + ///< COMDAT. + LLVMNoDuplicatesComdatSelectionKind, ///< No other Module may specify this + ///< COMDAT. + LLVMSameSizeComdatSelectionKind ///< The data referenced by the COMDAT must be + ///< the same size. +} LLVMComdatSelectionKind; + +/** + * Return the Comdat in the module with the specified name. It is created + * if it didn't already exist. + * + * @see llvm::Module::getOrInsertComdat() + */ +LLVMComdatRef LLVMGetOrInsertComdat(LLVMModuleRef M, const char *Name); + +/** + * Get the Comdat assigned to the given global object. + * + * @see llvm::GlobalObject::getComdat() + */ +LLVMComdatRef LLVMGetComdat(LLVMValueRef V); + +/** + * Assign the Comdat to the given global object. + * + * @see llvm::GlobalObject::setComdat() + */ +void LLVMSetComdat(LLVMValueRef V, LLVMComdatRef C); + +/* + * Get the conflict resolution selection kind for the Comdat. + * + * @see llvm::Comdat::getSelectionKind() + */ +LLVMComdatSelectionKind LLVMGetComdatSelectionKind(LLVMComdatRef C); + +/* + * Set the conflict resolution selection kind for the Comdat. + * + * @see llvm::Comdat::setSelectionKind() + */ +void LLVMSetComdatSelectionKind(LLVMComdatRef C, LLVMComdatSelectionKind Kind); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/llvm-c/Config/AsmParsers.def b/src/llvm-c/Config/AsmParsers.def new file mode 100644 index 000000000..7aaab6e50 --- /dev/null +++ b/src/llvm-c/Config/AsmParsers.def @@ -0,0 +1,44 @@ +/*===- llvm/Config/AsmParsers.def - LLVM Assembly Parsers -------*- C++ -*-===*\ +|* *| +|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *| +|* Exceptions. *| +|* See https://llvm.org/LICENSE.txt for license information. *| +|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This file enumerates all of the assembly-language parsers *| +|* supported by this build of LLVM. Clients of this file should define *| +|* the LLVM_ASM_PARSER macro to be a function-like macro with a *| +|* single parameter (the name of the target whose assembly can be *| +|* generated); including this file will then enumerate all of the *| +|* targets with assembly parsers. *| +|* *| +|* The set of targets supported by LLVM is generated at configuration *| +|* time, at which point this header is generated. Do not modify this *| +|* header directly. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_ASM_PARSER +# error Please define the macro LLVM_ASM_PARSER(TargetName) +#endif + +LLVM_ASM_PARSER(AArch64) +LLVM_ASM_PARSER(AMDGPU) +LLVM_ASM_PARSER(ARM) +LLVM_ASM_PARSER(BPF) +LLVM_ASM_PARSER(Hexagon) +LLVM_ASM_PARSER(Lanai) +LLVM_ASM_PARSER(Mips) +LLVM_ASM_PARSER(MSP430) +LLVM_ASM_PARSER(PowerPC) +LLVM_ASM_PARSER(RISCV) +LLVM_ASM_PARSER(Sparc) +LLVM_ASM_PARSER(SystemZ) +LLVM_ASM_PARSER(WebAssembly) +LLVM_ASM_PARSER(X86) +LLVM_ASM_PARSER(AVR) + + +#undef LLVM_ASM_PARSER diff --git a/src/llvm-c/Config/AsmPrinters.def b/src/llvm-c/Config/AsmPrinters.def new file mode 100644 index 000000000..3ecc3644f --- /dev/null +++ b/src/llvm-c/Config/AsmPrinters.def @@ -0,0 +1,46 @@ +/*===- llvm/Config/AsmPrinters.def - LLVM Assembly Printers -----*- C++ -*-===*\ +|* *| +|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *| +|* Exceptions. *| +|* See https://llvm.org/LICENSE.txt for license information. *| +|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This file enumerates all of the assembly-language printers *| +|* supported by this build of LLVM. Clients of this file should define *| +|* the LLVM_ASM_PRINTER macro to be a function-like macro with a *| +|* single parameter (the name of the target whose assembly can be *| +|* generated); including this file will then enumerate all of the *| +|* targets with assembly printers. *| +|* *| +|* The set of targets supported by LLVM is generated at configuration *| +|* time, at which point this header is generated. Do not modify this *| +|* header directly. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_ASM_PRINTER +# error Please define the macro LLVM_ASM_PRINTER(TargetName) +#endif + +LLVM_ASM_PRINTER(AArch64) +LLVM_ASM_PRINTER(AMDGPU) +LLVM_ASM_PRINTER(ARM) +LLVM_ASM_PRINTER(BPF) +LLVM_ASM_PRINTER(Hexagon) +LLVM_ASM_PRINTER(Lanai) +LLVM_ASM_PRINTER(Mips) +LLVM_ASM_PRINTER(MSP430) +LLVM_ASM_PRINTER(NVPTX) +LLVM_ASM_PRINTER(PowerPC) +LLVM_ASM_PRINTER(RISCV) +LLVM_ASM_PRINTER(Sparc) +LLVM_ASM_PRINTER(SystemZ) +LLVM_ASM_PRINTER(WebAssembly) +LLVM_ASM_PRINTER(X86) +LLVM_ASM_PRINTER(XCore) +LLVM_ASM_PRINTER(AVR) + + +#undef LLVM_ASM_PRINTER diff --git a/src/llvm-c/Config/Disassemblers.def b/src/llvm-c/Config/Disassemblers.def new file mode 100644 index 000000000..4485af241 --- /dev/null +++ b/src/llvm-c/Config/Disassemblers.def @@ -0,0 +1,45 @@ +/*===- llvm/Config/Disassemblers.def - LLVM Assembly Parsers ----*- C++ -*-===*\ +|* *| +|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *| +|* Exceptions. *| +|* See https://llvm.org/LICENSE.txt for license information. *| +|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This file enumerates all of the assembly-language parsers *| +|* supported by this build of LLVM. Clients of this file should define *| +|* the LLVM_DISASSEMBLER macro to be a function-like macro with a *| +|* single parameter (the name of the target whose assembly can be *| +|* generated); including this file will then enumerate all of the *| +|* targets with assembly parsers. *| +|* *| +|* The set of targets supported by LLVM is generated at configuration *| +|* time, at which point this header is generated. Do not modify this *| +|* header directly. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_DISASSEMBLER +# error Please define the macro LLVM_DISASSEMBLER(TargetName) +#endif + +LLVM_DISASSEMBLER(AArch64) +LLVM_DISASSEMBLER(AMDGPU) +LLVM_DISASSEMBLER(ARM) +LLVM_DISASSEMBLER(BPF) +LLVM_DISASSEMBLER(Hexagon) +LLVM_DISASSEMBLER(Lanai) +LLVM_DISASSEMBLER(Mips) +LLVM_DISASSEMBLER(MSP430) +LLVM_DISASSEMBLER(PowerPC) +LLVM_DISASSEMBLER(RISCV) +LLVM_DISASSEMBLER(Sparc) +LLVM_DISASSEMBLER(SystemZ) +LLVM_DISASSEMBLER(WebAssembly) +LLVM_DISASSEMBLER(X86) +LLVM_DISASSEMBLER(XCore) +LLVM_DISASSEMBLER(AVR) + + +#undef LLVM_DISASSEMBLER diff --git a/src/llvm-c/Config/Targets.def b/src/llvm-c/Config/Targets.def new file mode 100644 index 000000000..4962add96 --- /dev/null +++ b/src/llvm-c/Config/Targets.def @@ -0,0 +1,45 @@ +/*===- llvm/Config/Targets.def - LLVM Target Architectures ------*- C++ -*-===*\ +|* *| +|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *| +|* Exceptions. *| +|* See https://llvm.org/LICENSE.txt for license information. *| +|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This file enumerates all of the target architectures supported by *| +|* this build of LLVM. Clients of this file should define the *| +|* LLVM_TARGET macro to be a function-like macro with a single *| +|* parameter (the name of the target); including this file will then *| +|* enumerate all of the targets. *| +|* *| +|* The set of targets supported by LLVM is generated at configuration *| +|* time, at which point this header is generated. Do not modify this *| +|* header directly. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_TARGET +# error Please define the macro LLVM_TARGET(TargetName) +#endif + +LLVM_TARGET(AArch64) +LLVM_TARGET(AMDGPU) +LLVM_TARGET(ARM) +LLVM_TARGET(BPF) +LLVM_TARGET(Hexagon) +LLVM_TARGET(Lanai) +LLVM_TARGET(Mips) +LLVM_TARGET(MSP430) +LLVM_TARGET(NVPTX) +LLVM_TARGET(PowerPC) +LLVM_TARGET(RISCV) +LLVM_TARGET(Sparc) +LLVM_TARGET(SystemZ) +LLVM_TARGET(WebAssembly) +LLVM_TARGET(X86) +LLVM_TARGET(XCore) +LLVM_TARGET(AVR) + + +#undef LLVM_TARGET diff --git a/src/llvm-c/Config/abi-breaking.h b/src/llvm-c/Config/abi-breaking.h new file mode 100644 index 000000000..fd32bf381 --- /dev/null +++ b/src/llvm-c/Config/abi-breaking.h @@ -0,0 +1,62 @@ +/*===------- llvm/Config/abi-breaking.h - llvm configuration -------*- C -*-===*/ +/* */ +/* Part of the LLVM Project, under the Apache License v2.0 with LLVM */ +/* Exceptions. */ +/* See https://llvm.org/LICENSE.txt for license information. */ +/* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception */ +/* */ +/*===----------------------------------------------------------------------===*/ + +/* This file controls the C++ ABI break introduced in LLVM public header. */ + +#ifndef LLVM_ABI_BREAKING_CHECKS_H +#define LLVM_ABI_BREAKING_CHECKS_H + +/* Define to enable checks that alter the LLVM C++ ABI */ +#define LLVM_ENABLE_ABI_BREAKING_CHECKS 0 + +/* Define to enable reverse iteration of unordered llvm containers */ +#define LLVM_ENABLE_REVERSE_ITERATION 0 + +/* Allow selectively disabling link-time mismatch checking so that header-only + ADT content from LLVM can be used without linking libSupport. */ +#if !LLVM_DISABLE_ABI_BREAKING_CHECKS_ENFORCING + +// ABI_BREAKING_CHECKS protection: provides link-time failure when clients build +// mismatch with LLVM +#if defined(_MSC_VER) +// Use pragma with MSVC +#define LLVM_XSTR(s) LLVM_STR(s) +#define LLVM_STR(s) #s +#pragma detect_mismatch("LLVM_ENABLE_ABI_BREAKING_CHECKS", LLVM_XSTR(LLVM_ENABLE_ABI_BREAKING_CHECKS)) +#undef LLVM_XSTR +#undef LLVM_STR +#elif defined(_WIN32) || defined(__CYGWIN__) // Win32 w/o #pragma detect_mismatch +// FIXME: Implement checks without weak. +#elif defined(__cplusplus) +#if !(defined(_AIX) && defined(__GNUC__) && !defined(__clang__)) +#define LLVM_HIDDEN_VISIBILITY __attribute__ ((visibility("hidden"))) +#else +// GCC on AIX does not support visibility attributes. Symbols are not +// exported by default on AIX. +#define LLVM_HIDDEN_VISIBILITY +#endif +namespace llvm { +#if LLVM_ENABLE_ABI_BREAKING_CHECKS +extern int EnableABIBreakingChecks; +LLVM_HIDDEN_VISIBILITY +__attribute__((weak)) int *VerifyEnableABIBreakingChecks = + &EnableABIBreakingChecks; +#else +extern int DisableABIBreakingChecks; +LLVM_HIDDEN_VISIBILITY +__attribute__((weak)) int *VerifyDisableABIBreakingChecks = + &DisableABIBreakingChecks; +#endif +} +#undef LLVM_HIDDEN_VISIBILITY +#endif // _MSC_VER + +#endif // LLVM_DISABLE_ABI_BREAKING_CHECKS_ENFORCING + +#endif diff --git a/src/llvm-c/Config/llvm-config.h b/src/llvm-c/Config/llvm-config.h new file mode 100644 index 000000000..cdc6d47e7 --- /dev/null +++ b/src/llvm-c/Config/llvm-config.h @@ -0,0 +1,85 @@ +/*===------- llvm/Config/llvm-config.h - llvm configuration -------*- C -*-===*/ +/* */ +/* Part of the LLVM Project, under the Apache License v2.0 with LLVM */ +/* Exceptions. */ +/* See https://llvm.org/LICENSE.txt for license information. */ +/* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception */ +/* */ +/*===----------------------------------------------------------------------===*/ + +/* This file enumerates variables from the LLVM configuration so that they + can be in exported headers and won't override package specific directives. + This is a C header that can be included in the llvm-c headers. */ + +#ifndef LLVM_CONFIG_H +#define LLVM_CONFIG_H + +/* Define if LLVM_ENABLE_DUMP is enabled */ +/* #undef LLVM_ENABLE_DUMP */ + +/* Define if we link Polly to the tools */ +/* #undef LINK_POLLY_INTO_TOOLS */ + +/* Target triple LLVM will generate code for by default */ +#define LLVM_DEFAULT_TARGET_TRIPLE "x86_64-pc-windows-msvc" + +/* Define if threads enabled */ +#define LLVM_ENABLE_THREADS 1 + +/* Has gcc/MSVC atomic intrinsics */ +#define LLVM_HAS_ATOMICS 1 + +/* Host triple LLVM will be executed on */ +#define LLVM_HOST_TRIPLE "x86_64-pc-windows-msvc" + +/* LLVM architecture name for the native architecture, if available */ +#define LLVM_NATIVE_ARCH X86 + +/* LLVM name for the native AsmParser init function, if available */ +#define LLVM_NATIVE_ASMPARSER LLVMInitializeX86AsmParser + +/* LLVM name for the native AsmPrinter init function, if available */ +#define LLVM_NATIVE_ASMPRINTER LLVMInitializeX86AsmPrinter + +/* LLVM name for the native Disassembler init function, if available */ +#define LLVM_NATIVE_DISASSEMBLER LLVMInitializeX86Disassembler + +/* LLVM name for the native Target init function, if available */ +#define LLVM_NATIVE_TARGET LLVMInitializeX86Target + +/* LLVM name for the native TargetInfo init function, if available */ +#define LLVM_NATIVE_TARGETINFO LLVMInitializeX86TargetInfo + +/* LLVM name for the native target MC init function, if available */ +#define LLVM_NATIVE_TARGETMC LLVMInitializeX86TargetMC + +/* Define if this is Unixish platform */ +/* #undef LLVM_ON_UNIX */ + +/* Define if we have the Intel JIT API runtime support library */ +#define LLVM_USE_INTEL_JITEVENTS 0 + +/* Define if we have the oprofile JIT-support library */ +#define LLVM_USE_OPROFILE 0 + +/* Define if we have the perf JIT-support library */ +#define LLVM_USE_PERF 0 + +/* Major version of the LLVM API */ +#define LLVM_VERSION_MAJOR 9 + +/* Minor version of the LLVM API */ +#define LLVM_VERSION_MINOR 0 + +/* Patch version of the LLVM API */ +#define LLVM_VERSION_PATCH 0 + +/* LLVM version string */ +#define LLVM_VERSION_STRING "9.0.0" + +/* Whether LLVM records statistics for use with GetStatistics(), + * PrintStatistics() or PrintStatisticsJSON() + */ +#define LLVM_FORCE_ENABLE_STATS 0 + +#endif diff --git a/src/llvm-c/Core.h b/src/llvm-c/Core.h new file mode 100644 index 000000000..51f160818 --- /dev/null +++ b/src/llvm-c/Core.h @@ -0,0 +1,4079 @@ +/*===-- llvm-c/Core.h - Core Library C Interface ------------------*- C -*-===*\ +|* *| +|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *| +|* Exceptions. *| +|* See https://llvm.org/LICENSE.txt for license information. *| +|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This header declares the C interface to libLLVMCore.a, which implements *| +|* the LLVM intermediate representation. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_C_CORE_H +#define LLVM_C_CORE_H + +#include "llvm-c/ErrorHandling.h" +#include "llvm-c/Types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup LLVMC LLVM-C: C interface to LLVM + * + * This module exposes parts of the LLVM library as a C API. + * + * @{ + */ + +/** + * @defgroup LLVMCTransforms Transforms + */ + +/** + * @defgroup LLVMCCore Core + * + * This modules provide an interface to libLLVMCore, which implements + * the LLVM intermediate representation as well as other related types + * and utilities. + * + * Many exotic languages can interoperate with C code but have a harder time + * with C++ due to name mangling. So in addition to C, this interface enables + * tools written in such languages. + * + * @{ + */ + +/** + * @defgroup LLVMCCoreTypes Types and Enumerations + * + * @{ + */ + +/// External users depend on the following values being stable. It is not safe +/// to reorder them. +typedef enum { + /* Terminator Instructions */ + LLVMRet = 1, + LLVMBr = 2, + LLVMSwitch = 3, + LLVMIndirectBr = 4, + LLVMInvoke = 5, + /* removed 6 due to API changes */ + LLVMUnreachable = 7, + LLVMCallBr = 67, + + /* Standard Unary Operators */ + LLVMFNeg = 66, + + /* Standard Binary Operators */ + LLVMAdd = 8, + LLVMFAdd = 9, + LLVMSub = 10, + LLVMFSub = 11, + LLVMMul = 12, + LLVMFMul = 13, + LLVMUDiv = 14, + LLVMSDiv = 15, + LLVMFDiv = 16, + LLVMURem = 17, + LLVMSRem = 18, + LLVMFRem = 19, + + /* Logical Operators */ + LLVMShl = 20, + LLVMLShr = 21, + LLVMAShr = 22, + LLVMAnd = 23, + LLVMOr = 24, + LLVMXor = 25, + + /* Memory Operators */ + LLVMAlloca = 26, + LLVMLoad = 27, + LLVMStore = 28, + LLVMGetElementPtr = 29, + + /* Cast Operators */ + LLVMTrunc = 30, + LLVMZExt = 31, + LLVMSExt = 32, + LLVMFPToUI = 33, + LLVMFPToSI = 34, + LLVMUIToFP = 35, + LLVMSIToFP = 36, + LLVMFPTrunc = 37, + LLVMFPExt = 38, + LLVMPtrToInt = 39, + LLVMIntToPtr = 40, + LLVMBitCast = 41, + LLVMAddrSpaceCast = 60, + + /* Other Operators */ + LLVMICmp = 42, + LLVMFCmp = 43, + LLVMPHI = 44, + LLVMCall = 45, + LLVMSelect = 46, + LLVMUserOp1 = 47, + LLVMUserOp2 = 48, + LLVMVAArg = 49, + LLVMExtractElement = 50, + LLVMInsertElement = 51, + LLVMShuffleVector = 52, + LLVMExtractValue = 53, + LLVMInsertValue = 54, + + /* Atomic operators */ + LLVMFence = 55, + LLVMAtomicCmpXchg = 56, + LLVMAtomicRMW = 57, + + /* Exception Handling Operators */ + LLVMResume = 58, + LLVMLandingPad = 59, + LLVMCleanupRet = 61, + LLVMCatchRet = 62, + LLVMCatchPad = 63, + LLVMCleanupPad = 64, + LLVMCatchSwitch = 65 +} LLVMOpcode; + +typedef enum { + LLVMVoidTypeKind, /**< type with no size */ + LLVMHalfTypeKind, /**< 16 bit floating point type */ + LLVMFloatTypeKind, /**< 32 bit floating point type */ + LLVMDoubleTypeKind, /**< 64 bit floating point type */ + LLVMX86_FP80TypeKind, /**< 80 bit floating point type (X87) */ + LLVMFP128TypeKind, /**< 128 bit floating point type (112-bit mantissa)*/ + LLVMPPC_FP128TypeKind, /**< 128 bit floating point type (two 64-bits) */ + LLVMLabelTypeKind, /**< Labels */ + LLVMIntegerTypeKind, /**< Arbitrary bit width integers */ + LLVMFunctionTypeKind, /**< Functions */ + LLVMStructTypeKind, /**< Structures */ + LLVMArrayTypeKind, /**< Arrays */ + LLVMPointerTypeKind, /**< Pointers */ + LLVMVectorTypeKind, /**< SIMD 'packed' format, or other vector type */ + LLVMMetadataTypeKind, /**< Metadata */ + LLVMX86_MMXTypeKind, /**< X86 MMX */ + LLVMTokenTypeKind /**< Tokens */ +} LLVMTypeKind; + +typedef enum { + LLVMExternalLinkage, /**< Externally visible function */ + LLVMAvailableExternallyLinkage, + LLVMLinkOnceAnyLinkage, /**< Keep one copy of function when linking (inline)*/ + LLVMLinkOnceODRLinkage, /**< Same, but only replaced by something + equivalent. */ + LLVMLinkOnceODRAutoHideLinkage, /**< Obsolete */ + LLVMWeakAnyLinkage, /**< Keep one copy of function when linking (weak) */ + LLVMWeakODRLinkage, /**< Same, but only replaced by something + equivalent. */ + LLVMAppendingLinkage, /**< Special purpose, only applies to global arrays */ + LLVMInternalLinkage, /**< Rename collisions when linking (static + functions) */ + LLVMPrivateLinkage, /**< Like Internal, but omit from symbol table */ + LLVMDLLImportLinkage, /**< Obsolete */ + LLVMDLLExportLinkage, /**< Obsolete */ + LLVMExternalWeakLinkage,/**< ExternalWeak linkage description */ + LLVMGhostLinkage, /**< Obsolete */ + LLVMCommonLinkage, /**< Tentative definitions */ + LLVMLinkerPrivateLinkage, /**< Like Private, but linker removes. */ + LLVMLinkerPrivateWeakLinkage /**< Like LinkerPrivate, but is weak. */ +} LLVMLinkage; + +typedef enum { + LLVMDefaultVisibility, /**< The GV is visible */ + LLVMHiddenVisibility, /**< The GV is hidden */ + LLVMProtectedVisibility /**< The GV is protected */ +} LLVMVisibility; + +typedef enum { + LLVMNoUnnamedAddr, /**< Address of the GV is significant. */ + LLVMLocalUnnamedAddr, /**< Address of the GV is locally insignificant. */ + LLVMGlobalUnnamedAddr /**< Address of the GV is globally insignificant. */ +} LLVMUnnamedAddr; + +typedef enum { + LLVMDefaultStorageClass = 0, + LLVMDLLImportStorageClass = 1, /**< Function to be imported from DLL. */ + LLVMDLLExportStorageClass = 2 /**< Function to be accessible from DLL. */ +} LLVMDLLStorageClass; + +typedef enum { + LLVMCCallConv = 0, + LLVMFastCallConv = 8, + LLVMColdCallConv = 9, + LLVMGHCCallConv = 10, + LLVMHiPECallConv = 11, + LLVMWebKitJSCallConv = 12, + LLVMAnyRegCallConv = 13, + LLVMPreserveMostCallConv = 14, + LLVMPreserveAllCallConv = 15, + LLVMSwiftCallConv = 16, + LLVMCXXFASTTLSCallConv = 17, + LLVMX86StdcallCallConv = 64, + LLVMX86FastcallCallConv = 65, + LLVMARMAPCSCallConv = 66, + LLVMARMAAPCSCallConv = 67, + LLVMARMAAPCSVFPCallConv = 68, + LLVMMSP430INTRCallConv = 69, + LLVMX86ThisCallCallConv = 70, + LLVMPTXKernelCallConv = 71, + LLVMPTXDeviceCallConv = 72, + LLVMSPIRFUNCCallConv = 75, + LLVMSPIRKERNELCallConv = 76, + LLVMIntelOCLBICallConv = 77, + LLVMX8664SysVCallConv = 78, + LLVMWin64CallConv = 79, + LLVMX86VectorCallCallConv = 80, + LLVMHHVMCallConv = 81, + LLVMHHVMCCallConv = 82, + LLVMX86INTRCallConv = 83, + LLVMAVRINTRCallConv = 84, + LLVMAVRSIGNALCallConv = 85, + LLVMAVRBUILTINCallConv = 86, + LLVMAMDGPUVSCallConv = 87, + LLVMAMDGPUGSCallConv = 88, + LLVMAMDGPUPSCallConv = 89, + LLVMAMDGPUCSCallConv = 90, + LLVMAMDGPUKERNELCallConv = 91, + LLVMX86RegCallCallConv = 92, + LLVMAMDGPUHSCallConv = 93, + LLVMMSP430BUILTINCallConv = 94, + LLVMAMDGPULSCallConv = 95, + LLVMAMDGPUESCallConv = 96 +} LLVMCallConv; + +typedef enum { + LLVMArgumentValueKind, + LLVMBasicBlockValueKind, + LLVMMemoryUseValueKind, + LLVMMemoryDefValueKind, + LLVMMemoryPhiValueKind, + + LLVMFunctionValueKind, + LLVMGlobalAliasValueKind, + LLVMGlobalIFuncValueKind, + LLVMGlobalVariableValueKind, + LLVMBlockAddressValueKind, + LLVMConstantExprValueKind, + LLVMConstantArrayValueKind, + LLVMConstantStructValueKind, + LLVMConstantVectorValueKind, + + LLVMUndefValueValueKind, + LLVMConstantAggregateZeroValueKind, + LLVMConstantDataArrayValueKind, + LLVMConstantDataVectorValueKind, + LLVMConstantIntValueKind, + LLVMConstantFPValueKind, + LLVMConstantPointerNullValueKind, + LLVMConstantTokenNoneValueKind, + + LLVMMetadataAsValueValueKind, + LLVMInlineAsmValueKind, + + LLVMInstructionValueKind, +} LLVMValueKind; + +typedef enum { + LLVMIntEQ = 32, /**< equal */ + LLVMIntNE, /**< not equal */ + LLVMIntUGT, /**< unsigned greater than */ + LLVMIntUGE, /**< unsigned greater or equal */ + LLVMIntULT, /**< unsigned less than */ + LLVMIntULE, /**< unsigned less or equal */ + LLVMIntSGT, /**< signed greater than */ + LLVMIntSGE, /**< signed greater or equal */ + LLVMIntSLT, /**< signed less than */ + LLVMIntSLE /**< signed less or equal */ +} LLVMIntPredicate; + +typedef enum { + LLVMRealPredicateFalse, /**< Always false (always folded) */ + LLVMRealOEQ, /**< True if ordered and equal */ + LLVMRealOGT, /**< True if ordered and greater than */ + LLVMRealOGE, /**< True if ordered and greater than or equal */ + LLVMRealOLT, /**< True if ordered and less than */ + LLVMRealOLE, /**< True if ordered and less than or equal */ + LLVMRealONE, /**< True if ordered and operands are unequal */ + LLVMRealORD, /**< True if ordered (no nans) */ + LLVMRealUNO, /**< True if unordered: isnan(X) | isnan(Y) */ + LLVMRealUEQ, /**< True if unordered or equal */ + LLVMRealUGT, /**< True if unordered or greater than */ + LLVMRealUGE, /**< True if unordered, greater than, or equal */ + LLVMRealULT, /**< True if unordered or less than */ + LLVMRealULE, /**< True if unordered, less than, or equal */ + LLVMRealUNE, /**< True if unordered or not equal */ + LLVMRealPredicateTrue /**< Always true (always folded) */ +} LLVMRealPredicate; + +typedef enum { + LLVMLandingPadCatch, /**< A catch clause */ + LLVMLandingPadFilter /**< A filter clause */ +} LLVMLandingPadClauseTy; + +typedef enum { + LLVMNotThreadLocal = 0, + LLVMGeneralDynamicTLSModel, + LLVMLocalDynamicTLSModel, + LLVMInitialExecTLSModel, + LLVMLocalExecTLSModel +} LLVMThreadLocalMode; + +typedef enum { + LLVMAtomicOrderingNotAtomic = 0, /**< A load or store which is not atomic */ + LLVMAtomicOrderingUnordered = 1, /**< Lowest level of atomicity, guarantees + somewhat sane results, lock free. */ + LLVMAtomicOrderingMonotonic = 2, /**< guarantees that if you take all the + operations affecting a specific address, + a consistent ordering exists */ + LLVMAtomicOrderingAcquire = 4, /**< Acquire provides a barrier of the sort + necessary to acquire a lock to access other + memory with normal loads and stores. */ + LLVMAtomicOrderingRelease = 5, /**< Release is similar to Acquire, but with + a barrier of the sort necessary to release + a lock. */ + LLVMAtomicOrderingAcquireRelease = 6, /**< provides both an Acquire and a + Release barrier (for fences and + operations which both read and write + memory). */ + LLVMAtomicOrderingSequentiallyConsistent = 7 /**< provides Acquire semantics + for loads and Release + semantics for stores. + Additionally, it guarantees + that a total ordering exists + between all + SequentiallyConsistent + operations. */ +} LLVMAtomicOrdering; + +typedef enum { + LLVMAtomicRMWBinOpXchg, /**< Set the new value and return the one old */ + LLVMAtomicRMWBinOpAdd, /**< Add a value and return the old one */ + LLVMAtomicRMWBinOpSub, /**< Subtract a value and return the old one */ + LLVMAtomicRMWBinOpAnd, /**< And a value and return the old one */ + LLVMAtomicRMWBinOpNand, /**< Not-And a value and return the old one */ + LLVMAtomicRMWBinOpOr, /**< OR a value and return the old one */ + LLVMAtomicRMWBinOpXor, /**< Xor a value and return the old one */ + LLVMAtomicRMWBinOpMax, /**< Sets the value if it's greater than the + original using a signed comparison and return + the old one */ + LLVMAtomicRMWBinOpMin, /**< Sets the value if it's Smaller than the + original using a signed comparison and return + the old one */ + LLVMAtomicRMWBinOpUMax, /**< Sets the value if it's greater than the + original using an unsigned comparison and return + the old one */ + LLVMAtomicRMWBinOpUMin /**< Sets the value if it's greater than the + original using an unsigned comparison and return + the old one */ +} LLVMAtomicRMWBinOp; + +typedef enum { + LLVMDSError, + LLVMDSWarning, + LLVMDSRemark, + LLVMDSNote +} LLVMDiagnosticSeverity; + +typedef enum { + LLVMInlineAsmDialectATT, + LLVMInlineAsmDialectIntel +} LLVMInlineAsmDialect; + +typedef enum { + /** + * Emits an error if two values disagree, otherwise the resulting value is + * that of the operands. + * + * @see Module::ModFlagBehavior::Error + */ + LLVMModuleFlagBehaviorError, + /** + * Emits a warning if two values disagree. The result value will be the + * operand for the flag from the first module being linked. + * + * @see Module::ModFlagBehavior::Warning + */ + LLVMModuleFlagBehaviorWarning, + /** + * Adds a requirement that another module flag be present and have a + * specified value after linking is performed. The value must be a metadata + * pair, where the first element of the pair is the ID of the module flag + * to be restricted, and the second element of the pair is the value the + * module flag should be restricted to. This behavior can be used to + * restrict the allowable results (via triggering of an error) of linking + * IDs with the **Override** behavior. + * + * @see Module::ModFlagBehavior::Require + */ + LLVMModuleFlagBehaviorRequire, + /** + * Uses the specified value, regardless of the behavior or value of the + * other module. If both modules specify **Override**, but the values + * differ, an error will be emitted. + * + * @see Module::ModFlagBehavior::Override + */ + LLVMModuleFlagBehaviorOverride, + /** + * Appends the two values, which are required to be metadata nodes. + * + * @see Module::ModFlagBehavior::Append + */ + LLVMModuleFlagBehaviorAppend, + /** + * Appends the two values, which are required to be metadata + * nodes. However, duplicate entries in the second list are dropped + * during the append operation. + * + * @see Module::ModFlagBehavior::AppendUnique + */ + LLVMModuleFlagBehaviorAppendUnique, +} LLVMModuleFlagBehavior; + +/** + * Attribute index are either LLVMAttributeReturnIndex, + * LLVMAttributeFunctionIndex or a parameter number from 1 to N. + */ +enum { + LLVMAttributeReturnIndex = 0U, + // ISO C restricts enumerator values to range of 'int' + // (4294967295 is too large) + // LLVMAttributeFunctionIndex = ~0U, + LLVMAttributeFunctionIndex = -1, +}; + +typedef unsigned LLVMAttributeIndex; + +/** + * @} + */ + +void LLVMInitializeCore(LLVMPassRegistryRef R); + +/** Deallocate and destroy all ManagedStatic variables. + @see llvm::llvm_shutdown + @see ManagedStatic */ +void LLVMShutdown(void); + +/*===-- Error handling ----------------------------------------------------===*/ + +char *LLVMCreateMessage(const char *Message); +void LLVMDisposeMessage(char *Message); + +/** + * @defgroup LLVMCCoreContext Contexts + * + * Contexts are execution states for the core LLVM IR system. + * + * Most types are tied to a context instance. Multiple contexts can + * exist simultaneously. A single context is not thread safe. However, + * different contexts can execute on different threads simultaneously. + * + * @{ + */ + +typedef void (*LLVMDiagnosticHandler)(LLVMDiagnosticInfoRef, void *); +typedef void (*LLVMYieldCallback)(LLVMContextRef, void *); + +/** + * Create a new context. + * + * Every call to this function should be paired with a call to + * LLVMContextDispose() or the context will leak memory. + */ +LLVMContextRef LLVMContextCreate(void); + +/** + * Obtain the global context instance. + */ +LLVMContextRef LLVMGetGlobalContext(void); + +/** + * Set the diagnostic handler for this context. + */ +void LLVMContextSetDiagnosticHandler(LLVMContextRef C, + LLVMDiagnosticHandler Handler, + void *DiagnosticContext); + +/** + * Get the diagnostic handler of this context. + */ +LLVMDiagnosticHandler LLVMContextGetDiagnosticHandler(LLVMContextRef C); + +/** + * Get the diagnostic context of this context. + */ +void *LLVMContextGetDiagnosticContext(LLVMContextRef C); + +/** + * Set the yield callback function for this context. + * + * @see LLVMContext::setYieldCallback() + */ +void LLVMContextSetYieldCallback(LLVMContextRef C, LLVMYieldCallback Callback, + void *OpaqueHandle); + +/** + * Retrieve whether the given context is set to discard all value names. + * + * @see LLVMContext::shouldDiscardValueNames() + */ +LLVMBool LLVMContextShouldDiscardValueNames(LLVMContextRef C); + +/** + * Set whether the given context discards all value names. + * + * If true, only the names of GlobalValue objects will be available in the IR. + * This can be used to save memory and runtime, especially in release mode. + * + * @see LLVMContext::setDiscardValueNames() + */ +void LLVMContextSetDiscardValueNames(LLVMContextRef C, LLVMBool Discard); + +/** + * Destroy a context instance. + * + * This should be called for every call to LLVMContextCreate() or memory + * will be leaked. + */ +void LLVMContextDispose(LLVMContextRef C); + +/** + * Return a string representation of the DiagnosticInfo. Use + * LLVMDisposeMessage to free the string. + * + * @see DiagnosticInfo::print() + */ +char *LLVMGetDiagInfoDescription(LLVMDiagnosticInfoRef DI); + +/** + * Return an enum LLVMDiagnosticSeverity. + * + * @see DiagnosticInfo::getSeverity() + */ +LLVMDiagnosticSeverity LLVMGetDiagInfoSeverity(LLVMDiagnosticInfoRef DI); + +unsigned LLVMGetMDKindIDInContext(LLVMContextRef C, const char *Name, + unsigned SLen); +unsigned LLVMGetMDKindID(const char *Name, unsigned SLen); + +/** + * Return an unique id given the name of a enum attribute, + * or 0 if no attribute by that name exists. + * + * See http://llvm.org/docs/LangRef.html#parameter-attributes + * and http://llvm.org/docs/LangRef.html#function-attributes + * for the list of available attributes. + * + * NB: Attribute names and/or id are subject to change without + * going through the C API deprecation cycle. + */ +unsigned LLVMGetEnumAttributeKindForName(const char *Name, size_t SLen); +unsigned LLVMGetLastEnumAttributeKind(void); + +/** + * Create an enum attribute. + */ +LLVMAttributeRef LLVMCreateEnumAttribute(LLVMContextRef C, unsigned KindID, + uint64_t Val); + +/** + * Get the unique id corresponding to the enum attribute + * passed as argument. + */ +unsigned LLVMGetEnumAttributeKind(LLVMAttributeRef A); + +/** + * Get the enum attribute's value. 0 is returned if none exists. + */ +uint64_t LLVMGetEnumAttributeValue(LLVMAttributeRef A); + +/** + * Create a string attribute. + */ +LLVMAttributeRef LLVMCreateStringAttribute(LLVMContextRef C, + const char *K, unsigned KLength, + const char *V, unsigned VLength); + +/** + * Get the string attribute's kind. + */ +const char *LLVMGetStringAttributeKind(LLVMAttributeRef A, unsigned *Length); + +/** + * Get the string attribute's value. + */ +const char *LLVMGetStringAttributeValue(LLVMAttributeRef A, unsigned *Length); + +/** + * Check for the different types of attributes. + */ +LLVMBool LLVMIsEnumAttribute(LLVMAttributeRef A); +LLVMBool LLVMIsStringAttribute(LLVMAttributeRef A); + +/** + * @} + */ + +/** + * @defgroup LLVMCCoreModule Modules + * + * Modules represent the top-level structure in an LLVM program. An LLVM + * module is effectively a translation unit or a collection of + * translation units merged together. + * + * @{ + */ + +/** + * Create a new, empty module in the global context. + * + * This is equivalent to calling LLVMModuleCreateWithNameInContext with + * LLVMGetGlobalContext() as the context parameter. + * + * Every invocation should be paired with LLVMDisposeModule() or memory + * will be leaked. + */ +LLVMModuleRef LLVMModuleCreateWithName(const char *ModuleID); + +/** + * Create a new, empty module in a specific context. + * + * Every invocation should be paired with LLVMDisposeModule() or memory + * will be leaked. + */ +LLVMModuleRef LLVMModuleCreateWithNameInContext(const char *ModuleID, + LLVMContextRef C); +/** + * Return an exact copy of the specified module. + */ +LLVMModuleRef LLVMCloneModule(LLVMModuleRef M); + +/** + * Destroy a module instance. + * + * This must be called for every created module or memory will be + * leaked. + */ +void LLVMDisposeModule(LLVMModuleRef M); + +/** + * Obtain the identifier of a module. + * + * @param M Module to obtain identifier of + * @param Len Out parameter which holds the length of the returned string. + * @return The identifier of M. + * @see Module::getModuleIdentifier() + */ +const char *LLVMGetModuleIdentifier(LLVMModuleRef M, size_t *Len); + +/** + * Set the identifier of a module to a string Ident with length Len. + * + * @param M The module to set identifier + * @param Ident The string to set M's identifier to + * @param Len Length of Ident + * @see Module::setModuleIdentifier() + */ +void LLVMSetModuleIdentifier(LLVMModuleRef M, const char *Ident, size_t Len); + +/** + * Obtain the module's original source file name. + * + * @param M Module to obtain the name of + * @param Len Out parameter which holds the length of the returned string + * @return The original source file name of M + * @see Module::getSourceFileName() + */ +const char *LLVMGetSourceFileName(LLVMModuleRef M, size_t *Len); + +/** + * Set the original source file name of a module to a string Name with length + * Len. + * + * @param M The module to set the source file name of + * @param Name The string to set M's source file name to + * @param Len Length of Name + * @see Module::setSourceFileName() + */ +void LLVMSetSourceFileName(LLVMModuleRef M, const char *Name, size_t Len); + +/** + * Obtain the data layout for a module. + * + * @see Module::getDataLayoutStr() + * + * LLVMGetDataLayout is DEPRECATED, as the name is not only incorrect, + * but match the name of another method on the module. Prefer the use + * of LLVMGetDataLayoutStr, which is not ambiguous. + */ +const char *LLVMGetDataLayoutStr(LLVMModuleRef M); +const char *LLVMGetDataLayout(LLVMModuleRef M); + +/** + * Set the data layout for a module. + * + * @see Module::setDataLayout() + */ +void LLVMSetDataLayout(LLVMModuleRef M, const char *DataLayoutStr); + +/** + * Obtain the target triple for a module. + * + * @see Module::getTargetTriple() + */ +const char *LLVMGetTarget(LLVMModuleRef M); + +/** + * Set the target triple for a module. + * + * @see Module::setTargetTriple() + */ +void LLVMSetTarget(LLVMModuleRef M, const char *Triple); + +/** + * Returns the module flags as an array of flag-key-value triples. The caller + * is responsible for freeing this array by calling + * \c LLVMDisposeModuleFlagsMetadata. + * + * @see Module::getModuleFlagsMetadata() + */ +LLVMModuleFlagEntry *LLVMCopyModuleFlagsMetadata(LLVMModuleRef M, size_t *Len); + +/** + * Destroys module flags metadata entries. + */ +void LLVMDisposeModuleFlagsMetadata(LLVMModuleFlagEntry *Entries); + +/** + * Returns the flag behavior for a module flag entry at a specific index. + * + * @see Module::ModuleFlagEntry::Behavior + */ +LLVMModuleFlagBehavior +LLVMModuleFlagEntriesGetFlagBehavior(LLVMModuleFlagEntry *Entries, + unsigned Index); + +/** + * Returns the key for a module flag entry at a specific index. + * + * @see Module::ModuleFlagEntry::Key + */ +const char *LLVMModuleFlagEntriesGetKey(LLVMModuleFlagEntry *Entries, + unsigned Index, size_t *Len); + +/** + * Returns the metadata for a module flag entry at a specific index. + * + * @see Module::ModuleFlagEntry::Val + */ +LLVMMetadataRef LLVMModuleFlagEntriesGetMetadata(LLVMModuleFlagEntry *Entries, + unsigned Index); + +/** + * Add a module-level flag to the module-level flags metadata if it doesn't + * already exist. + * + * @see Module::getModuleFlag() + */ +LLVMMetadataRef LLVMGetModuleFlag(LLVMModuleRef M, + const char *Key, size_t KeyLen); + +/** + * Add a module-level flag to the module-level flags metadata if it doesn't + * already exist. + * + * @see Module::addModuleFlag() + */ +void LLVMAddModuleFlag(LLVMModuleRef M, LLVMModuleFlagBehavior Behavior, + const char *Key, size_t KeyLen, + LLVMMetadataRef Val); + +/** + * Dump a representation of a module to stderr. + * + * @see Module::dump() + */ +void LLVMDumpModule(LLVMModuleRef M); + +/** + * Print a representation of a module to a file. The ErrorMessage needs to be + * disposed with LLVMDisposeMessage. Returns 0 on success, 1 otherwise. + * + * @see Module::print() + */ +LLVMBool LLVMPrintModuleToFile(LLVMModuleRef M, const char *Filename, + char **ErrorMessage); + +/** + * Return a string representation of the module. Use + * LLVMDisposeMessage to free the string. + * + * @see Module::print() + */ +char *LLVMPrintModuleToString(LLVMModuleRef M); + +/** + * Get inline assembly for a module. + * + * @see Module::getModuleInlineAsm() + */ +const char *LLVMGetModuleInlineAsm(LLVMModuleRef M, size_t *Len); + +/** + * Set inline assembly for a module. + * + * @see Module::setModuleInlineAsm() + */ +void LLVMSetModuleInlineAsm2(LLVMModuleRef M, const char *Asm, size_t Len); + +/** + * Append inline assembly to a module. + * + * @see Module::appendModuleInlineAsm() + */ +void LLVMAppendModuleInlineAsm(LLVMModuleRef M, const char *Asm, size_t Len); + +/** + * Create the specified uniqued inline asm string. + * + * @see InlineAsm::get() + */ +LLVMValueRef LLVMGetInlineAsm(LLVMTypeRef Ty, + char *AsmString, size_t AsmStringSize, + char *Constraints, size_t ConstraintsSize, + LLVMBool HasSideEffects, LLVMBool IsAlignStack, + LLVMInlineAsmDialect Dialect); + +/** + * Obtain the context to which this module is associated. + * + * @see Module::getContext() + */ +LLVMContextRef LLVMGetModuleContext(LLVMModuleRef M); + +/** + * Obtain a Type from a module by its registered name. + */ +LLVMTypeRef LLVMGetTypeByName(LLVMModuleRef M, const char *Name); + +/** + * Obtain an iterator to the first NamedMDNode in a Module. + * + * @see llvm::Module::named_metadata_begin() + */ +LLVMNamedMDNodeRef LLVMGetFirstNamedMetadata(LLVMModuleRef M); + +/** + * Obtain an iterator to the last NamedMDNode in a Module. + * + * @see llvm::Module::named_metadata_end() + */ +LLVMNamedMDNodeRef LLVMGetLastNamedMetadata(LLVMModuleRef M); + +/** + * Advance a NamedMDNode iterator to the next NamedMDNode. + * + * Returns NULL if the iterator was already at the end and there are no more + * named metadata nodes. + */ +LLVMNamedMDNodeRef LLVMGetNextNamedMetadata(LLVMNamedMDNodeRef NamedMDNode); + +/** + * Decrement a NamedMDNode iterator to the previous NamedMDNode. + * + * Returns NULL if the iterator was already at the beginning and there are + * no previous named metadata nodes. + */ +LLVMNamedMDNodeRef LLVMGetPreviousNamedMetadata(LLVMNamedMDNodeRef NamedMDNode); + +/** + * Retrieve a NamedMDNode with the given name, returning NULL if no such + * node exists. + * + * @see llvm::Module::getNamedMetadata() + */ +LLVMNamedMDNodeRef LLVMGetNamedMetadata(LLVMModuleRef M, + const char *Name, size_t NameLen); + +/** + * Retrieve a NamedMDNode with the given name, creating a new node if no such + * node exists. + * + * @see llvm::Module::getOrInsertNamedMetadata() + */ +LLVMNamedMDNodeRef LLVMGetOrInsertNamedMetadata(LLVMModuleRef M, + const char *Name, + size_t NameLen); + +/** + * Retrieve the name of a NamedMDNode. + * + * @see llvm::NamedMDNode::getName() + */ +const char *LLVMGetNamedMetadataName(LLVMNamedMDNodeRef NamedMD, + size_t *NameLen); + +/** + * Obtain the number of operands for named metadata in a module. + * + * @see llvm::Module::getNamedMetadata() + */ +unsigned LLVMGetNamedMetadataNumOperands(LLVMModuleRef M, const char *Name); + +/** + * Obtain the named metadata operands for a module. + * + * The passed LLVMValueRef pointer should refer to an array of + * LLVMValueRef at least LLVMGetNamedMetadataNumOperands long. This + * array will be populated with the LLVMValueRef instances. Each + * instance corresponds to a llvm::MDNode. + * + * @see llvm::Module::getNamedMetadata() + * @see llvm::MDNode::getOperand() + */ +void LLVMGetNamedMetadataOperands(LLVMModuleRef M, const char *Name, + LLVMValueRef *Dest); + +/** + * Add an operand to named metadata. + * + * @see llvm::Module::getNamedMetadata() + * @see llvm::MDNode::addOperand() + */ +void LLVMAddNamedMetadataOperand(LLVMModuleRef M, const char *Name, + LLVMValueRef Val); + +/** + * Return the directory of the debug location for this value, which must be + * an llvm::Instruction, llvm::GlobalVariable, or llvm::Function. + * + * @see llvm::Instruction::getDebugLoc() + * @see llvm::GlobalVariable::getDebugInfo() + * @see llvm::Function::getSubprogram() + */ +const char *LLVMGetDebugLocDirectory(LLVMValueRef Val, unsigned *Length); + +/** + * Return the filename of the debug location for this value, which must be + * an llvm::Instruction, llvm::GlobalVariable, or llvm::Function. + * + * @see llvm::Instruction::getDebugLoc() + * @see llvm::GlobalVariable::getDebugInfo() + * @see llvm::Function::getSubprogram() + */ +const char *LLVMGetDebugLocFilename(LLVMValueRef Val, unsigned *Length); + +/** + * Return the line number of the debug location for this value, which must be + * an llvm::Instruction, llvm::GlobalVariable, or llvm::Function. + * + * @see llvm::Instruction::getDebugLoc() + * @see llvm::GlobalVariable::getDebugInfo() + * @see llvm::Function::getSubprogram() + */ +unsigned LLVMGetDebugLocLine(LLVMValueRef Val); + +/** + * Return the column number of the debug location for this value, which must be + * an llvm::Instruction. + * + * @see llvm::Instruction::getDebugLoc() + */ +unsigned LLVMGetDebugLocColumn(LLVMValueRef Val); + +/** + * Add a function to a module under a specified name. + * + * @see llvm::Function::Create() + */ +LLVMValueRef LLVMAddFunction(LLVMModuleRef M, const char *Name, + LLVMTypeRef FunctionTy); + +/** + * Obtain a Function value from a Module by its name. + * + * The returned value corresponds to a llvm::Function value. + * + * @see llvm::Module::getFunction() + */ +LLVMValueRef LLVMGetNamedFunction(LLVMModuleRef M, const char *Name); + +/** + * Obtain an iterator to the first Function in a Module. + * + * @see llvm::Module::begin() + */ +LLVMValueRef LLVMGetFirstFunction(LLVMModuleRef M); + +/** + * Obtain an iterator to the last Function in a Module. + * + * @see llvm::Module::end() + */ +LLVMValueRef LLVMGetLastFunction(LLVMModuleRef M); + +/** + * Advance a Function iterator to the next Function. + * + * Returns NULL if the iterator was already at the end and there are no more + * functions. + */ +LLVMValueRef LLVMGetNextFunction(LLVMValueRef Fn); + +/** + * Decrement a Function iterator to the previous Function. + * + * Returns NULL if the iterator was already at the beginning and there are + * no previous functions. + */ +LLVMValueRef LLVMGetPreviousFunction(LLVMValueRef Fn); + +/** Deprecated: Use LLVMSetModuleInlineAsm2 instead. */ +void LLVMSetModuleInlineAsm(LLVMModuleRef M, const char *Asm); + +/** + * @} + */ + +/** + * @defgroup LLVMCCoreType Types + * + * Types represent the type of a value. + * + * Types are associated with a context instance. The context internally + * deduplicates types so there is only 1 instance of a specific type + * alive at a time. In other words, a unique type is shared among all + * consumers within a context. + * + * A Type in the C API corresponds to llvm::Type. + * + * Types have the following hierarchy: + * + * types: + * integer type + * real type + * function type + * sequence types: + * array type + * pointer type + * vector type + * void type + * label type + * opaque type + * + * @{ + */ + +/** + * Obtain the enumerated type of a Type instance. + * + * @see llvm::Type:getTypeID() + */ +LLVMTypeKind LLVMGetTypeKind(LLVMTypeRef Ty); + +/** + * Whether the type has a known size. + * + * Things that don't have a size are abstract types, labels, and void.a + * + * @see llvm::Type::isSized() + */ +LLVMBool LLVMTypeIsSized(LLVMTypeRef Ty); + +/** + * Obtain the context to which this type instance is associated. + * + * @see llvm::Type::getContext() + */ +LLVMContextRef LLVMGetTypeContext(LLVMTypeRef Ty); + +/** + * Dump a representation of a type to stderr. + * + * @see llvm::Type::dump() + */ +void LLVMDumpType(LLVMTypeRef Val); + +/** + * Return a string representation of the type. Use + * LLVMDisposeMessage to free the string. + * + * @see llvm::Type::print() + */ +char *LLVMPrintTypeToString(LLVMTypeRef Val); + +/** + * @defgroup LLVMCCoreTypeInt Integer Types + * + * Functions in this section operate on integer types. + * + * @{ + */ + +/** + * Obtain an integer type from a context with specified bit width. + */ +LLVMTypeRef LLVMInt1TypeInContext(LLVMContextRef C); +LLVMTypeRef LLVMInt8TypeInContext(LLVMContextRef C); +LLVMTypeRef LLVMInt16TypeInContext(LLVMContextRef C); +LLVMTypeRef LLVMInt32TypeInContext(LLVMContextRef C); +LLVMTypeRef LLVMInt64TypeInContext(LLVMContextRef C); +LLVMTypeRef LLVMInt128TypeInContext(LLVMContextRef C); +LLVMTypeRef LLVMIntTypeInContext(LLVMContextRef C, unsigned NumBits); + +/** + * Obtain an integer type from the global context with a specified bit + * width. + */ +LLVMTypeRef LLVMInt1Type(void); +LLVMTypeRef LLVMInt8Type(void); +LLVMTypeRef LLVMInt16Type(void); +LLVMTypeRef LLVMInt32Type(void); +LLVMTypeRef LLVMInt64Type(void); +LLVMTypeRef LLVMInt128Type(void); +LLVMTypeRef LLVMIntType(unsigned NumBits); +unsigned LLVMGetIntTypeWidth(LLVMTypeRef IntegerTy); + +/** + * @} + */ + +/** + * @defgroup LLVMCCoreTypeFloat Floating Point Types + * + * @{ + */ + +/** + * Obtain a 16-bit floating point type from a context. + */ +LLVMTypeRef LLVMHalfTypeInContext(LLVMContextRef C); + +/** + * Obtain a 32-bit floating point type from a context. + */ +LLVMTypeRef LLVMFloatTypeInContext(LLVMContextRef C); + +/** + * Obtain a 64-bit floating point type from a context. + */ +LLVMTypeRef LLVMDoubleTypeInContext(LLVMContextRef C); + +/** + * Obtain a 80-bit floating point type (X87) from a context. + */ +LLVMTypeRef LLVMX86FP80TypeInContext(LLVMContextRef C); + +/** + * Obtain a 128-bit floating point type (112-bit mantissa) from a + * context. + */ +LLVMTypeRef LLVMFP128TypeInContext(LLVMContextRef C); + +/** + * Obtain a 128-bit floating point type (two 64-bits) from a context. + */ +LLVMTypeRef LLVMPPCFP128TypeInContext(LLVMContextRef C); + +/** + * Obtain a floating point type from the global context. + * + * These map to the functions in this group of the same name. + */ +LLVMTypeRef LLVMHalfType(void); +LLVMTypeRef LLVMFloatType(void); +LLVMTypeRef LLVMDoubleType(void); +LLVMTypeRef LLVMX86FP80Type(void); +LLVMTypeRef LLVMFP128Type(void); +LLVMTypeRef LLVMPPCFP128Type(void); + +/** + * @} + */ + +/** + * @defgroup LLVMCCoreTypeFunction Function Types + * + * @{ + */ + +/** + * Obtain a function type consisting of a specified signature. + * + * The function is defined as a tuple of a return Type, a list of + * parameter types, and whether the function is variadic. + */ +LLVMTypeRef LLVMFunctionType(LLVMTypeRef ReturnType, + LLVMTypeRef *ParamTypes, unsigned ParamCount, + LLVMBool IsVarArg); + +/** + * Returns whether a function type is variadic. + */ +LLVMBool LLVMIsFunctionVarArg(LLVMTypeRef FunctionTy); + +/** + * Obtain the Type this function Type returns. + */ +LLVMTypeRef LLVMGetReturnType(LLVMTypeRef FunctionTy); + +/** + * Obtain the number of parameters this function accepts. + */ +unsigned LLVMCountParamTypes(LLVMTypeRef FunctionTy); + +/** + * Obtain the types of a function's parameters. + * + * The Dest parameter should point to a pre-allocated array of + * LLVMTypeRef at least LLVMCountParamTypes() large. On return, the + * first LLVMCountParamTypes() entries in the array will be populated + * with LLVMTypeRef instances. + * + * @param FunctionTy The function type to operate on. + * @param Dest Memory address of an array to be filled with result. + */ +void LLVMGetParamTypes(LLVMTypeRef FunctionTy, LLVMTypeRef *Dest); + +/** + * @} + */ + +/** + * @defgroup LLVMCCoreTypeStruct Structure Types + * + * These functions relate to LLVMTypeRef instances. + * + * @see llvm::StructType + * + * @{ + */ + +/** + * Create a new structure type in a context. + * + * A structure is specified by a list of inner elements/types and + * whether these can be packed together. + * + * @see llvm::StructType::create() + */ +LLVMTypeRef LLVMStructTypeInContext(LLVMContextRef C, LLVMTypeRef *ElementTypes, + unsigned ElementCount, LLVMBool Packed); + +/** + * Create a new structure type in the global context. + * + * @see llvm::StructType::create() + */ +LLVMTypeRef LLVMStructType(LLVMTypeRef *ElementTypes, unsigned ElementCount, + LLVMBool Packed); + +/** + * Create an empty structure in a context having a specified name. + * + * @see llvm::StructType::create() + */ +LLVMTypeRef LLVMStructCreateNamed(LLVMContextRef C, const char *Name); + +/** + * Obtain the name of a structure. + * + * @see llvm::StructType::getName() + */ +const char *LLVMGetStructName(LLVMTypeRef Ty); + +/** + * Set the contents of a structure type. + * + * @see llvm::StructType::setBody() + */ +void LLVMStructSetBody(LLVMTypeRef StructTy, LLVMTypeRef *ElementTypes, + unsigned ElementCount, LLVMBool Packed); + +/** + * Get the number of elements defined inside the structure. + * + * @see llvm::StructType::getNumElements() + */ +unsigned LLVMCountStructElementTypes(LLVMTypeRef StructTy); + +/** + * Get the elements within a structure. + * + * The function is passed the address of a pre-allocated array of + * LLVMTypeRef at least LLVMCountStructElementTypes() long. After + * invocation, this array will be populated with the structure's + * elements. The objects in the destination array will have a lifetime + * of the structure type itself, which is the lifetime of the context it + * is contained in. + */ +void LLVMGetStructElementTypes(LLVMTypeRef StructTy, LLVMTypeRef *Dest); + +/** + * Get the type of the element at a given index in the structure. + * + * @see llvm::StructType::getTypeAtIndex() + */ +LLVMTypeRef LLVMStructGetTypeAtIndex(LLVMTypeRef StructTy, unsigned i); + +/** + * Determine whether a structure is packed. + * + * @see llvm::StructType::isPacked() + */ +LLVMBool LLVMIsPackedStruct(LLVMTypeRef StructTy); + +/** + * Determine whether a structure is opaque. + * + * @see llvm::StructType::isOpaque() + */ +LLVMBool LLVMIsOpaqueStruct(LLVMTypeRef StructTy); + +/** + * Determine whether a structure is literal. + * + * @see llvm::StructType::isLiteral() + */ +LLVMBool LLVMIsLiteralStruct(LLVMTypeRef StructTy); + +/** + * @} + */ + +/** + * @defgroup LLVMCCoreTypeSequential Sequential Types + * + * Sequential types represents "arrays" of types. This is a super class + * for array, vector, and pointer types. + * + * @{ + */ + +/** + * Obtain the type of elements within a sequential type. + * + * This works on array, vector, and pointer types. + * + * @see llvm::SequentialType::getElementType() + */ +LLVMTypeRef LLVMGetElementType(LLVMTypeRef Ty); + +/** + * Returns type's subtypes + * + * @see llvm::Type::subtypes() + */ +void LLVMGetSubtypes(LLVMTypeRef Tp, LLVMTypeRef *Arr); + +/** + * Return the number of types in the derived type. + * + * @see llvm::Type::getNumContainedTypes() + */ +unsigned LLVMGetNumContainedTypes(LLVMTypeRef Tp); + +/** + * Create a fixed size array type that refers to a specific type. + * + * The created type will exist in the context that its element type + * exists in. + * + * @see llvm::ArrayType::get() + */ +LLVMTypeRef LLVMArrayType(LLVMTypeRef ElementType, unsigned ElementCount); + +/** + * Obtain the length of an array type. + * + * This only works on types that represent arrays. + * + * @see llvm::ArrayType::getNumElements() + */ +unsigned LLVMGetArrayLength(LLVMTypeRef ArrayTy); + +/** + * Create a pointer type that points to a defined type. + * + * The created type will exist in the context that its pointee type + * exists in. + * + * @see llvm::PointerType::get() + */ +LLVMTypeRef LLVMPointerType(LLVMTypeRef ElementType, unsigned AddressSpace); + +/** + * Obtain the address space of a pointer type. + * + * This only works on types that represent pointers. + * + * @see llvm::PointerType::getAddressSpace() + */ +unsigned LLVMGetPointerAddressSpace(LLVMTypeRef PointerTy); + +/** + * Create a vector type that contains a defined type and has a specific + * number of elements. + * + * The created type will exist in the context thats its element type + * exists in. + * + * @see llvm::VectorType::get() + */ +LLVMTypeRef LLVMVectorType(LLVMTypeRef ElementType, unsigned ElementCount); + +/** + * Obtain the number of elements in a vector type. + * + * This only works on types that represent vectors. + * + * @see llvm::VectorType::getNumElements() + */ +unsigned LLVMGetVectorSize(LLVMTypeRef VectorTy); + +/** + * @} + */ + +/** + * @defgroup LLVMCCoreTypeOther Other Types + * + * @{ + */ + +/** + * Create a void type in a context. + */ +LLVMTypeRef LLVMVoidTypeInContext(LLVMContextRef C); + +/** + * Create a label type in a context. + */ +LLVMTypeRef LLVMLabelTypeInContext(LLVMContextRef C); + +/** + * Create a X86 MMX type in a context. + */ +LLVMTypeRef LLVMX86MMXTypeInContext(LLVMContextRef C); + +/** + * Create a token type in a context. + */ +LLVMTypeRef LLVMTokenTypeInContext(LLVMContextRef C); + +/** + * Create a metadata type in a context. + */ +LLVMTypeRef LLVMMetadataTypeInContext(LLVMContextRef C); + +/** + * These are similar to the above functions except they operate on the + * global context. + */ +LLVMTypeRef LLVMVoidType(void); +LLVMTypeRef LLVMLabelType(void); +LLVMTypeRef LLVMX86MMXType(void); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @defgroup LLVMCCoreValues Values + * + * The bulk of LLVM's object model consists of values, which comprise a very + * rich type hierarchy. + * + * LLVMValueRef essentially represents llvm::Value. There is a rich + * hierarchy of classes within this type. Depending on the instance + * obtained, not all APIs are available. + * + * Callers can determine the type of an LLVMValueRef by calling the + * LLVMIsA* family of functions (e.g. LLVMIsAArgument()). These + * functions are defined by a macro, so it isn't obvious which are + * available by looking at the Doxygen source code. Instead, look at the + * source definition of LLVM_FOR_EACH_VALUE_SUBCLASS and note the list + * of value names given. These value names also correspond to classes in + * the llvm::Value hierarchy. + * + * @{ + */ + +#define LLVM_FOR_EACH_VALUE_SUBCLASS(macro) \ + macro(Argument) \ + macro(BasicBlock) \ + macro(InlineAsm) \ + macro(User) \ + macro(Constant) \ + macro(BlockAddress) \ + macro(ConstantAggregateZero) \ + macro(ConstantArray) \ + macro(ConstantDataSequential) \ + macro(ConstantDataArray) \ + macro(ConstantDataVector) \ + macro(ConstantExpr) \ + macro(ConstantFP) \ + macro(ConstantInt) \ + macro(ConstantPointerNull) \ + macro(ConstantStruct) \ + macro(ConstantTokenNone) \ + macro(ConstantVector) \ + macro(GlobalValue) \ + macro(GlobalAlias) \ + macro(GlobalIFunc) \ + macro(GlobalObject) \ + macro(Function) \ + macro(GlobalVariable) \ + macro(UndefValue) \ + macro(Instruction) \ + macro(BinaryOperator) \ + macro(CallInst) \ + macro(IntrinsicInst) \ + macro(DbgInfoIntrinsic) \ + macro(DbgVariableIntrinsic) \ + macro(DbgDeclareInst) \ + macro(DbgLabelInst) \ + macro(MemIntrinsic) \ + macro(MemCpyInst) \ + macro(MemMoveInst) \ + macro(MemSetInst) \ + macro(CmpInst) \ + macro(FCmpInst) \ + macro(ICmpInst) \ + macro(ExtractElementInst) \ + macro(GetElementPtrInst) \ + macro(InsertElementInst) \ + macro(InsertValueInst) \ + macro(LandingPadInst) \ + macro(PHINode) \ + macro(SelectInst) \ + macro(ShuffleVectorInst) \ + macro(StoreInst) \ + macro(BranchInst) \ + macro(IndirectBrInst) \ + macro(InvokeInst) \ + macro(ReturnInst) \ + macro(SwitchInst) \ + macro(UnreachableInst) \ + macro(ResumeInst) \ + macro(CleanupReturnInst) \ + macro(CatchReturnInst) \ + macro(FuncletPadInst) \ + macro(CatchPadInst) \ + macro(CleanupPadInst) \ + macro(UnaryInstruction) \ + macro(AllocaInst) \ + macro(CastInst) \ + macro(AddrSpaceCastInst) \ + macro(BitCastInst) \ + macro(FPExtInst) \ + macro(FPToSIInst) \ + macro(FPToUIInst) \ + macro(FPTruncInst) \ + macro(IntToPtrInst) \ + macro(PtrToIntInst) \ + macro(SExtInst) \ + macro(SIToFPInst) \ + macro(TruncInst) \ + macro(UIToFPInst) \ + macro(ZExtInst) \ + macro(ExtractValueInst) \ + macro(LoadInst) \ + macro(VAArgInst) + +/** + * @defgroup LLVMCCoreValueGeneral General APIs + * + * Functions in this section work on all LLVMValueRef instances, + * regardless of their sub-type. They correspond to functions available + * on llvm::Value. + * + * @{ + */ + +/** + * Obtain the type of a value. + * + * @see llvm::Value::getType() + */ +LLVMTypeRef LLVMTypeOf(LLVMValueRef Val); + +/** + * Obtain the enumerated type of a Value instance. + * + * @see llvm::Value::getValueID() + */ +LLVMValueKind LLVMGetValueKind(LLVMValueRef Val); + +/** + * Obtain the string name of a value. + * + * @see llvm::Value::getName() + */ +const char *LLVMGetValueName2(LLVMValueRef Val, size_t *Length); + +/** + * Set the string name of a value. + * + * @see llvm::Value::setName() + */ +void LLVMSetValueName2(LLVMValueRef Val, const char *Name, size_t NameLen); + +/** + * Dump a representation of a value to stderr. + * + * @see llvm::Value::dump() + */ +void LLVMDumpValue(LLVMValueRef Val); + +/** + * Return a string representation of the value. Use + * LLVMDisposeMessage to free the string. + * + * @see llvm::Value::print() + */ +char *LLVMPrintValueToString(LLVMValueRef Val); + +/** + * Replace all uses of a value with another one. + * + * @see llvm::Value::replaceAllUsesWith() + */ +void LLVMReplaceAllUsesWith(LLVMValueRef OldVal, LLVMValueRef NewVal); + +/** + * Determine whether the specified value instance is constant. + */ +LLVMBool LLVMIsConstant(LLVMValueRef Val); + +/** + * Determine whether a value instance is undefined. + */ +LLVMBool LLVMIsUndef(LLVMValueRef Val); + +/** + * Convert value instances between types. + * + * Internally, an LLVMValueRef is "pinned" to a specific type. This + * series of functions allows you to cast an instance to a specific + * type. + * + * If the cast is not valid for the specified type, NULL is returned. + * + * @see llvm::dyn_cast_or_null<> + */ +#define LLVM_DECLARE_VALUE_CAST(name) \ + LLVMValueRef LLVMIsA##name(LLVMValueRef Val); +LLVM_FOR_EACH_VALUE_SUBCLASS(LLVM_DECLARE_VALUE_CAST) + +LLVMValueRef LLVMIsAMDNode(LLVMValueRef Val); +LLVMValueRef LLVMIsAMDString(LLVMValueRef Val); + +/** Deprecated: Use LLVMGetValueName2 instead. */ +const char *LLVMGetValueName(LLVMValueRef Val); +/** Deprecated: Use LLVMSetValueName2 instead. */ +void LLVMSetValueName(LLVMValueRef Val, const char *Name); + +/** + * @} + */ + +/** + * @defgroup LLVMCCoreValueUses Usage + * + * This module defines functions that allow you to inspect the uses of a + * LLVMValueRef. + * + * It is possible to obtain an LLVMUseRef for any LLVMValueRef instance. + * Each LLVMUseRef (which corresponds to a llvm::Use instance) holds a + * llvm::User and llvm::Value. + * + * @{ + */ + +/** + * Obtain the first use of a value. + * + * Uses are obtained in an iterator fashion. First, call this function + * to obtain a reference to the first use. Then, call LLVMGetNextUse() + * on that instance and all subsequently obtained instances until + * LLVMGetNextUse() returns NULL. + * + * @see llvm::Value::use_begin() + */ +LLVMUseRef LLVMGetFirstUse(LLVMValueRef Val); + +/** + * Obtain the next use of a value. + * + * This effectively advances the iterator. It returns NULL if you are on + * the final use and no more are available. + */ +LLVMUseRef LLVMGetNextUse(LLVMUseRef U); + +/** + * Obtain the user value for a user. + * + * The returned value corresponds to a llvm::User type. + * + * @see llvm::Use::getUser() + */ +LLVMValueRef LLVMGetUser(LLVMUseRef U); + +/** + * Obtain the value this use corresponds to. + * + * @see llvm::Use::get(). + */ +LLVMValueRef LLVMGetUsedValue(LLVMUseRef U); + +/** + * @} + */ + +/** + * @defgroup LLVMCCoreValueUser User value + * + * Function in this group pertain to LLVMValueRef instances that descent + * from llvm::User. This includes constants, instructions, and + * operators. + * + * @{ + */ + +/** + * Obtain an operand at a specific index in a llvm::User value. + * + * @see llvm::User::getOperand() + */ +LLVMValueRef LLVMGetOperand(LLVMValueRef Val, unsigned Index); + +/** + * Obtain the use of an operand at a specific index in a llvm::User value. + * + * @see llvm::User::getOperandUse() + */ +LLVMUseRef LLVMGetOperandUse(LLVMValueRef Val, unsigned Index); + +/** + * Set an operand at a specific index in a llvm::User value. + * + * @see llvm::User::setOperand() + */ +void LLVMSetOperand(LLVMValueRef User, unsigned Index, LLVMValueRef Val); + +/** + * Obtain the number of operands in a llvm::User value. + * + * @see llvm::User::getNumOperands() + */ +int LLVMGetNumOperands(LLVMValueRef Val); + +/** + * @} + */ + +/** + * @defgroup LLVMCCoreValueConstant Constants + * + * This section contains APIs for interacting with LLVMValueRef that + * correspond to llvm::Constant instances. + * + * These functions will work for any LLVMValueRef in the llvm::Constant + * class hierarchy. + * + * @{ + */ + +/** + * Obtain a constant value referring to the null instance of a type. + * + * @see llvm::Constant::getNullValue() + */ +LLVMValueRef LLVMConstNull(LLVMTypeRef Ty); /* all zeroes */ + +/** + * Obtain a constant value referring to the instance of a type + * consisting of all ones. + * + * This is only valid for integer types. + * + * @see llvm::Constant::getAllOnesValue() + */ +LLVMValueRef LLVMConstAllOnes(LLVMTypeRef Ty); + +/** + * Obtain a constant value referring to an undefined value of a type. + * + * @see llvm::UndefValue::get() + */ +LLVMValueRef LLVMGetUndef(LLVMTypeRef Ty); + +/** + * Determine whether a value instance is null. + * + * @see llvm::Constant::isNullValue() + */ +LLVMBool LLVMIsNull(LLVMValueRef Val); + +/** + * Obtain a constant that is a constant pointer pointing to NULL for a + * specified type. + */ +LLVMValueRef LLVMConstPointerNull(LLVMTypeRef Ty); + +/** + * @defgroup LLVMCCoreValueConstantScalar Scalar constants + * + * Functions in this group model LLVMValueRef instances that correspond + * to constants referring to scalar types. + * + * For integer types, the LLVMTypeRef parameter should correspond to a + * llvm::IntegerType instance and the returned LLVMValueRef will + * correspond to a llvm::ConstantInt. + * + * For floating point types, the LLVMTypeRef returned corresponds to a + * llvm::ConstantFP. + * + * @{ + */ + +/** + * Obtain a constant value for an integer type. + * + * The returned value corresponds to a llvm::ConstantInt. + * + * @see llvm::ConstantInt::get() + * + * @param IntTy Integer type to obtain value of. + * @param N The value the returned instance should refer to. + * @param SignExtend Whether to sign extend the produced value. + */ +LLVMValueRef LLVMConstInt(LLVMTypeRef IntTy, unsigned long long N, + LLVMBool SignExtend); + +/** + * Obtain a constant value for an integer of arbitrary precision. + * + * @see llvm::ConstantInt::get() + */ +LLVMValueRef LLVMConstIntOfArbitraryPrecision(LLVMTypeRef IntTy, + unsigned NumWords, + const uint64_t Words[]); + +/** + * Obtain a constant value for an integer parsed from a string. + * + * A similar API, LLVMConstIntOfStringAndSize is also available. If the + * string's length is available, it is preferred to call that function + * instead. + * + * @see llvm::ConstantInt::get() + */ +LLVMValueRef LLVMConstIntOfString(LLVMTypeRef IntTy, const char *Text, + uint8_t Radix); + +/** + * Obtain a constant value for an integer parsed from a string with + * specified length. + * + * @see llvm::ConstantInt::get() + */ +LLVMValueRef LLVMConstIntOfStringAndSize(LLVMTypeRef IntTy, const char *Text, + unsigned SLen, uint8_t Radix); + +/** + * Obtain a constant value referring to a double floating point value. + */ +LLVMValueRef LLVMConstReal(LLVMTypeRef RealTy, double N); + +/** + * Obtain a constant for a floating point value parsed from a string. + * + * A similar API, LLVMConstRealOfStringAndSize is also available. It + * should be used if the input string's length is known. + */ +LLVMValueRef LLVMConstRealOfString(LLVMTypeRef RealTy, const char *Text); + +/** + * Obtain a constant for a floating point value parsed from a string. + */ +LLVMValueRef LLVMConstRealOfStringAndSize(LLVMTypeRef RealTy, const char *Text, + unsigned SLen); + +/** + * Obtain the zero extended value for an integer constant value. + * + * @see llvm::ConstantInt::getZExtValue() + */ +unsigned long long LLVMConstIntGetZExtValue(LLVMValueRef ConstantVal); + +/** + * Obtain the sign extended value for an integer constant value. + * + * @see llvm::ConstantInt::getSExtValue() + */ +long long LLVMConstIntGetSExtValue(LLVMValueRef ConstantVal); + +/** + * Obtain the double value for an floating point constant value. + * losesInfo indicates if some precision was lost in the conversion. + * + * @see llvm::ConstantFP::getDoubleValue + */ +double LLVMConstRealGetDouble(LLVMValueRef ConstantVal, LLVMBool *losesInfo); + +/** + * @} + */ + +/** + * @defgroup LLVMCCoreValueConstantComposite Composite Constants + * + * Functions in this group operate on composite constants. + * + * @{ + */ + +/** + * Create a ConstantDataSequential and initialize it with a string. + * + * @see llvm::ConstantDataArray::getString() + */ +LLVMValueRef LLVMConstStringInContext(LLVMContextRef C, const char *Str, + unsigned Length, LLVMBool DontNullTerminate); + +/** + * Create a ConstantDataSequential with string content in the global context. + * + * This is the same as LLVMConstStringInContext except it operates on the + * global context. + * + * @see LLVMConstStringInContext() + * @see llvm::ConstantDataArray::getString() + */ +LLVMValueRef LLVMConstString(const char *Str, unsigned Length, + LLVMBool DontNullTerminate); + +/** + * Returns true if the specified constant is an array of i8. + * + * @see ConstantDataSequential::getAsString() + */ +LLVMBool LLVMIsConstantString(LLVMValueRef c); + +/** + * Get the given constant data sequential as a string. + * + * @see ConstantDataSequential::getAsString() + */ +const char *LLVMGetAsString(LLVMValueRef c, size_t *Length); + +/** + * Create an anonymous ConstantStruct with the specified values. + * + * @see llvm::ConstantStruct::getAnon() + */ +LLVMValueRef LLVMConstStructInContext(LLVMContextRef C, + LLVMValueRef *ConstantVals, + unsigned Count, LLVMBool Packed); + +/** + * Create a ConstantStruct in the global Context. + * + * This is the same as LLVMConstStructInContext except it operates on the + * global Context. + * + * @see LLVMConstStructInContext() + */ +LLVMValueRef LLVMConstStruct(LLVMValueRef *ConstantVals, unsigned Count, + LLVMBool Packed); + +/** + * Create a ConstantArray from values. + * + * @see llvm::ConstantArray::get() + */ +LLVMValueRef LLVMConstArray(LLVMTypeRef ElementTy, + LLVMValueRef *ConstantVals, unsigned Length); + +/** + * Create a non-anonymous ConstantStruct from values. + * + * @see llvm::ConstantStruct::get() + */ +LLVMValueRef LLVMConstNamedStruct(LLVMTypeRef StructTy, + LLVMValueRef *ConstantVals, + unsigned Count); + +/** + * Get an element at specified index as a constant. + * + * @see ConstantDataSequential::getElementAsConstant() + */ +LLVMValueRef LLVMGetElementAsConstant(LLVMValueRef C, unsigned idx); + +/** + * Create a ConstantVector from values. + * + * @see llvm::ConstantVector::get() + */ +LLVMValueRef LLVMConstVector(LLVMValueRef *ScalarConstantVals, unsigned Size); + +/** + * @} + */ + +/** + * @defgroup LLVMCCoreValueConstantExpressions Constant Expressions + * + * Functions in this group correspond to APIs on llvm::ConstantExpr. + * + * @see llvm::ConstantExpr. + * + * @{ + */ +LLVMOpcode LLVMGetConstOpcode(LLVMValueRef ConstantVal); +LLVMValueRef LLVMAlignOf(LLVMTypeRef Ty); +LLVMValueRef LLVMSizeOf(LLVMTypeRef Ty); +LLVMValueRef LLVMConstNeg(LLVMValueRef ConstantVal); +LLVMValueRef LLVMConstNSWNeg(LLVMValueRef ConstantVal); +LLVMValueRef LLVMConstNUWNeg(LLVMValueRef ConstantVal); +LLVMValueRef LLVMConstFNeg(LLVMValueRef ConstantVal); +LLVMValueRef LLVMConstNot(LLVMValueRef ConstantVal); +LLVMValueRef LLVMConstAdd(LLVMValueRef LHSConstant, LLVMValueRef RHSConstant); +LLVMValueRef LLVMConstNSWAdd(LLVMValueRef LHSConstant, LLVMValueRef RHSConstant); +LLVMValueRef LLVMConstNUWAdd(LLVMValueRef LHSConstant, LLVMValueRef RHSConstant); +LLVMValueRef LLVMConstFAdd(LLVMValueRef LHSConstant, LLVMValueRef RHSConstant); +LLVMValueRef LLVMConstSub(LLVMValueRef LHSConstant, LLVMValueRef RHSConstant); +LLVMValueRef LLVMConstNSWSub(LLVMValueRef LHSConstant, LLVMValueRef RHSConstant); +LLVMValueRef LLVMConstNUWSub(LLVMValueRef LHSConstant, LLVMValueRef RHSConstant); +LLVMValueRef LLVMConstFSub(LLVMValueRef LHSConstant, LLVMValueRef RHSConstant); +LLVMValueRef LLVMConstMul(LLVMValueRef LHSConstant, LLVMValueRef RHSConstant); +LLVMValueRef LLVMConstNSWMul(LLVMValueRef LHSConstant, LLVMValueRef RHSConstant); +LLVMValueRef LLVMConstNUWMul(LLVMValueRef LHSConstant, LLVMValueRef RHSConstant); +LLVMValueRef LLVMConstFMul(LLVMValueRef LHSConstant, LLVMValueRef RHSConstant); +LLVMValueRef LLVMConstUDiv(LLVMValueRef LHSConstant, LLVMValueRef RHSConstant); +LLVMValueRef LLVMConstExactUDiv(LLVMValueRef LHSConstant, LLVMValueRef RHSConstant); +LLVMValueRef LLVMConstSDiv(LLVMValueRef LHSConstant, LLVMValueRef RHSConstant); +LLVMValueRef LLVMConstExactSDiv(LLVMValueRef LHSConstant, LLVMValueRef RHSConstant); +LLVMValueRef LLVMConstFDiv(LLVMValueRef LHSConstant, LLVMValueRef RHSConstant); +LLVMValueRef LLVMConstURem(LLVMValueRef LHSConstant, LLVMValueRef RHSConstant); +LLVMValueRef LLVMConstSRem(LLVMValueRef LHSConstant, LLVMValueRef RHSConstant); +LLVMValueRef LLVMConstFRem(LLVMValueRef LHSConstant, LLVMValueRef RHSConstant); +LLVMValueRef LLVMConstAnd(LLVMValueRef LHSConstant, LLVMValueRef RHSConstant); +LLVMValueRef LLVMConstOr(LLVMValueRef LHSConstant, LLVMValueRef RHSConstant); +LLVMValueRef LLVMConstXor(LLVMValueRef LHSConstant, LLVMValueRef RHSConstant); +LLVMValueRef LLVMConstICmp(LLVMIntPredicate Predicate, + LLVMValueRef LHSConstant, LLVMValueRef RHSConstant); +LLVMValueRef LLVMConstFCmp(LLVMRealPredicate Predicate, + LLVMValueRef LHSConstant, LLVMValueRef RHSConstant); +LLVMValueRef LLVMConstShl(LLVMValueRef LHSConstant, LLVMValueRef RHSConstant); +LLVMValueRef LLVMConstLShr(LLVMValueRef LHSConstant, LLVMValueRef RHSConstant); +LLVMValueRef LLVMConstAShr(LLVMValueRef LHSConstant, LLVMValueRef RHSConstant); +LLVMValueRef LLVMConstGEP(LLVMValueRef ConstantVal, + LLVMValueRef *ConstantIndices, unsigned NumIndices); +LLVMValueRef LLVMConstGEP2(LLVMTypeRef Ty, LLVMValueRef ConstantVal, + LLVMValueRef *ConstantIndices, unsigned NumIndices); +LLVMValueRef LLVMConstInBoundsGEP(LLVMValueRef ConstantVal, + LLVMValueRef *ConstantIndices, + unsigned NumIndices); +LLVMValueRef LLVMConstInBoundsGEP2(LLVMTypeRef Ty, LLVMValueRef ConstantVal, + LLVMValueRef *ConstantIndices, + unsigned NumIndices); +LLVMValueRef LLVMConstTrunc(LLVMValueRef ConstantVal, LLVMTypeRef ToType); +LLVMValueRef LLVMConstSExt(LLVMValueRef ConstantVal, LLVMTypeRef ToType); +LLVMValueRef LLVMConstZExt(LLVMValueRef ConstantVal, LLVMTypeRef ToType); +LLVMValueRef LLVMConstFPTrunc(LLVMValueRef ConstantVal, LLVMTypeRef ToType); +LLVMValueRef LLVMConstFPExt(LLVMValueRef ConstantVal, LLVMTypeRef ToType); +LLVMValueRef LLVMConstUIToFP(LLVMValueRef ConstantVal, LLVMTypeRef ToType); +LLVMValueRef LLVMConstSIToFP(LLVMValueRef ConstantVal, LLVMTypeRef ToType); +LLVMValueRef LLVMConstFPToUI(LLVMValueRef ConstantVal, LLVMTypeRef ToType); +LLVMValueRef LLVMConstFPToSI(LLVMValueRef ConstantVal, LLVMTypeRef ToType); +LLVMValueRef LLVMConstPtrToInt(LLVMValueRef ConstantVal, LLVMTypeRef ToType); +LLVMValueRef LLVMConstIntToPtr(LLVMValueRef ConstantVal, LLVMTypeRef ToType); +LLVMValueRef LLVMConstBitCast(LLVMValueRef ConstantVal, LLVMTypeRef ToType); +LLVMValueRef LLVMConstAddrSpaceCast(LLVMValueRef ConstantVal, LLVMTypeRef ToType); +LLVMValueRef LLVMConstZExtOrBitCast(LLVMValueRef ConstantVal, + LLVMTypeRef ToType); +LLVMValueRef LLVMConstSExtOrBitCast(LLVMValueRef ConstantVal, + LLVMTypeRef ToType); +LLVMValueRef LLVMConstTruncOrBitCast(LLVMValueRef ConstantVal, + LLVMTypeRef ToType); +LLVMValueRef LLVMConstPointerCast(LLVMValueRef ConstantVal, + LLVMTypeRef ToType); +LLVMValueRef LLVMConstIntCast(LLVMValueRef ConstantVal, LLVMTypeRef ToType, + LLVMBool isSigned); +LLVMValueRef LLVMConstFPCast(LLVMValueRef ConstantVal, LLVMTypeRef ToType); +LLVMValueRef LLVMConstSelect(LLVMValueRef ConstantCondition, + LLVMValueRef ConstantIfTrue, + LLVMValueRef ConstantIfFalse); +LLVMValueRef LLVMConstExtractElement(LLVMValueRef VectorConstant, + LLVMValueRef IndexConstant); +LLVMValueRef LLVMConstInsertElement(LLVMValueRef VectorConstant, + LLVMValueRef ElementValueConstant, + LLVMValueRef IndexConstant); +LLVMValueRef LLVMConstShuffleVector(LLVMValueRef VectorAConstant, + LLVMValueRef VectorBConstant, + LLVMValueRef MaskConstant); +LLVMValueRef LLVMConstExtractValue(LLVMValueRef AggConstant, unsigned *IdxList, + unsigned NumIdx); +LLVMValueRef LLVMConstInsertValue(LLVMValueRef AggConstant, + LLVMValueRef ElementValueConstant, + unsigned *IdxList, unsigned NumIdx); +LLVMValueRef LLVMBlockAddress(LLVMValueRef F, LLVMBasicBlockRef BB); + +/** Deprecated: Use LLVMGetInlineAsm instead. */ +LLVMValueRef LLVMConstInlineAsm(LLVMTypeRef Ty, + const char *AsmString, const char *Constraints, + LLVMBool HasSideEffects, LLVMBool IsAlignStack); + +/** + * @} + */ + +/** + * @defgroup LLVMCCoreValueConstantGlobals Global Values + * + * This group contains functions that operate on global values. Functions in + * this group relate to functions in the llvm::GlobalValue class tree. + * + * @see llvm::GlobalValue + * + * @{ + */ + +LLVMModuleRef LLVMGetGlobalParent(LLVMValueRef Global); +LLVMBool LLVMIsDeclaration(LLVMValueRef Global); +LLVMLinkage LLVMGetLinkage(LLVMValueRef Global); +void LLVMSetLinkage(LLVMValueRef Global, LLVMLinkage Linkage); +const char *LLVMGetSection(LLVMValueRef Global); +void LLVMSetSection(LLVMValueRef Global, const char *Section); +LLVMVisibility LLVMGetVisibility(LLVMValueRef Global); +void LLVMSetVisibility(LLVMValueRef Global, LLVMVisibility Viz); +LLVMDLLStorageClass LLVMGetDLLStorageClass(LLVMValueRef Global); +void LLVMSetDLLStorageClass(LLVMValueRef Global, LLVMDLLStorageClass Class); +LLVMUnnamedAddr LLVMGetUnnamedAddress(LLVMValueRef Global); +void LLVMSetUnnamedAddress(LLVMValueRef Global, LLVMUnnamedAddr UnnamedAddr); + +/** + * Returns the "value type" of a global value. This differs from the formal + * type of a global value which is always a pointer type. + * + * @see llvm::GlobalValue::getValueType() + */ +LLVMTypeRef LLVMGlobalGetValueType(LLVMValueRef Global); + +/** Deprecated: Use LLVMGetUnnamedAddress instead. */ +LLVMBool LLVMHasUnnamedAddr(LLVMValueRef Global); +/** Deprecated: Use LLVMSetUnnamedAddress instead. */ +void LLVMSetUnnamedAddr(LLVMValueRef Global, LLVMBool HasUnnamedAddr); + +/** + * @defgroup LLVMCCoreValueWithAlignment Values with alignment + * + * Functions in this group only apply to values with alignment, i.e. + * global variables, load and store instructions. + */ + +/** + * Obtain the preferred alignment of the value. + * @see llvm::AllocaInst::getAlignment() + * @see llvm::LoadInst::getAlignment() + * @see llvm::StoreInst::getAlignment() + * @see llvm::GlobalValue::getAlignment() + */ +unsigned LLVMGetAlignment(LLVMValueRef V); + +/** + * Set the preferred alignment of the value. + * @see llvm::AllocaInst::setAlignment() + * @see llvm::LoadInst::setAlignment() + * @see llvm::StoreInst::setAlignment() + * @see llvm::GlobalValue::setAlignment() + */ +void LLVMSetAlignment(LLVMValueRef V, unsigned Bytes); + +/** + * Sets a metadata attachment, erasing the existing metadata attachment if + * it already exists for the given kind. + * + * @see llvm::GlobalObject::setMetadata() + */ +void LLVMGlobalSetMetadata(LLVMValueRef Global, unsigned Kind, + LLVMMetadataRef MD); + +/** + * Erases a metadata attachment of the given kind if it exists. + * + * @see llvm::GlobalObject::eraseMetadata() + */ +void LLVMGlobalEraseMetadata(LLVMValueRef Global, unsigned Kind); + +/** + * Removes all metadata attachments from this value. + * + * @see llvm::GlobalObject::clearMetadata() + */ +void LLVMGlobalClearMetadata(LLVMValueRef Global); + +/** + * Retrieves an array of metadata entries representing the metadata attached to + * this value. The caller is responsible for freeing this array by calling + * \c LLVMDisposeValueMetadataEntries. + * + * @see llvm::GlobalObject::getAllMetadata() + */ +LLVMValueMetadataEntry *LLVMGlobalCopyAllMetadata(LLVMValueRef Value, + size_t *NumEntries); + +/** + * Destroys value metadata entries. + */ +void LLVMDisposeValueMetadataEntries(LLVMValueMetadataEntry *Entries); + +/** + * Returns the kind of a value metadata entry at a specific index. + */ +unsigned LLVMValueMetadataEntriesGetKind(LLVMValueMetadataEntry *Entries, + unsigned Index); + +/** + * Returns the underlying metadata node of a value metadata entry at a + * specific index. + */ +LLVMMetadataRef +LLVMValueMetadataEntriesGetMetadata(LLVMValueMetadataEntry *Entries, + unsigned Index); + +/** + * @} + */ + +/** + * @defgroup LLVMCoreValueConstantGlobalVariable Global Variables + * + * This group contains functions that operate on global variable values. + * + * @see llvm::GlobalVariable + * + * @{ + */ +LLVMValueRef LLVMAddGlobal(LLVMModuleRef M, LLVMTypeRef Ty, const char *Name); +LLVMValueRef LLVMAddGlobalInAddressSpace(LLVMModuleRef M, LLVMTypeRef Ty, + const char *Name, + unsigned AddressSpace); +LLVMValueRef LLVMGetNamedGlobal(LLVMModuleRef M, const char *Name); +LLVMValueRef LLVMGetFirstGlobal(LLVMModuleRef M); +LLVMValueRef LLVMGetLastGlobal(LLVMModuleRef M); +LLVMValueRef LLVMGetNextGlobal(LLVMValueRef GlobalVar); +LLVMValueRef LLVMGetPreviousGlobal(LLVMValueRef GlobalVar); +void LLVMDeleteGlobal(LLVMValueRef GlobalVar); +LLVMValueRef LLVMGetInitializer(LLVMValueRef GlobalVar); +void LLVMSetInitializer(LLVMValueRef GlobalVar, LLVMValueRef ConstantVal); +LLVMBool LLVMIsThreadLocal(LLVMValueRef GlobalVar); +void LLVMSetThreadLocal(LLVMValueRef GlobalVar, LLVMBool IsThreadLocal); +LLVMBool LLVMIsGlobalConstant(LLVMValueRef GlobalVar); +void LLVMSetGlobalConstant(LLVMValueRef GlobalVar, LLVMBool IsConstant); +LLVMThreadLocalMode LLVMGetThreadLocalMode(LLVMValueRef GlobalVar); +void LLVMSetThreadLocalMode(LLVMValueRef GlobalVar, LLVMThreadLocalMode Mode); +LLVMBool LLVMIsExternallyInitialized(LLVMValueRef GlobalVar); +void LLVMSetExternallyInitialized(LLVMValueRef GlobalVar, LLVMBool IsExtInit); + +/** + * @} + */ + +/** + * @defgroup LLVMCoreValueConstantGlobalAlias Global Aliases + * + * This group contains function that operate on global alias values. + * + * @see llvm::GlobalAlias + * + * @{ + */ +LLVMValueRef LLVMAddAlias(LLVMModuleRef M, LLVMTypeRef Ty, LLVMValueRef Aliasee, + const char *Name); + +/** + * Obtain a GlobalAlias value from a Module by its name. + * + * The returned value corresponds to a llvm::GlobalAlias value. + * + * @see llvm::Module::getNamedAlias() + */ +LLVMValueRef LLVMGetNamedGlobalAlias(LLVMModuleRef M, + const char *Name, size_t NameLen); + +/** + * Obtain an iterator to the first GlobalAlias in a Module. + * + * @see llvm::Module::alias_begin() + */ +LLVMValueRef LLVMGetFirstGlobalAlias(LLVMModuleRef M); + +/** + * Obtain an iterator to the last GlobalAlias in a Module. + * + * @see llvm::Module::alias_end() + */ +LLVMValueRef LLVMGetLastGlobalAlias(LLVMModuleRef M); + +/** + * Advance a GlobalAlias iterator to the next GlobalAlias. + * + * Returns NULL if the iterator was already at the end and there are no more + * global aliases. + */ +LLVMValueRef LLVMGetNextGlobalAlias(LLVMValueRef GA); + +/** + * Decrement a GlobalAlias iterator to the previous GlobalAlias. + * + * Returns NULL if the iterator was already at the beginning and there are + * no previous global aliases. + */ +LLVMValueRef LLVMGetPreviousGlobalAlias(LLVMValueRef GA); + +/** + * Retrieve the target value of an alias. + */ +LLVMValueRef LLVMAliasGetAliasee(LLVMValueRef Alias); + +/** + * Set the target value of an alias. + */ +void LLVMAliasSetAliasee(LLVMValueRef Alias, LLVMValueRef Aliasee); + +/** + * @} + */ + +/** + * @defgroup LLVMCCoreValueFunction Function values + * + * Functions in this group operate on LLVMValueRef instances that + * correspond to llvm::Function instances. + * + * @see llvm::Function + * + * @{ + */ + +/** + * Remove a function from its containing module and deletes it. + * + * @see llvm::Function::eraseFromParent() + */ +void LLVMDeleteFunction(LLVMValueRef Fn); + +/** + * Check whether the given function has a personality function. + * + * @see llvm::Function::hasPersonalityFn() + */ +LLVMBool LLVMHasPersonalityFn(LLVMValueRef Fn); + +/** + * Obtain the personality function attached to the function. + * + * @see llvm::Function::getPersonalityFn() + */ +LLVMValueRef LLVMGetPersonalityFn(LLVMValueRef Fn); + +/** + * Set the personality function attached to the function. + * + * @see llvm::Function::setPersonalityFn() + */ +void LLVMSetPersonalityFn(LLVMValueRef Fn, LLVMValueRef PersonalityFn); + +/** + * Obtain the intrinsic ID number which matches the given function name. + * + * @see llvm::Function::lookupIntrinsicID() + */ +unsigned LLVMLookupIntrinsicID(const char *Name, size_t NameLen); + +/** + * Obtain the ID number from a function instance. + * + * @see llvm::Function::getIntrinsicID() + */ +unsigned LLVMGetIntrinsicID(LLVMValueRef Fn); + +/** + * Create or insert the declaration of an intrinsic. For overloaded intrinsics, + * parameter types must be provided to uniquely identify an overload. + * + * @see llvm::Intrinsic::getDeclaration() + */ +LLVMValueRef LLVMGetIntrinsicDeclaration(LLVMModuleRef Mod, + unsigned ID, + LLVMTypeRef *ParamTypes, + size_t ParamCount); + +/** + * Retrieves the type of an intrinsic. For overloaded intrinsics, parameter + * types must be provided to uniquely identify an overload. + * + * @see llvm::Intrinsic::getType() + */ +LLVMTypeRef LLVMIntrinsicGetType(LLVMContextRef Ctx, unsigned ID, + LLVMTypeRef *ParamTypes, size_t ParamCount); + +/** + * Retrieves the name of an intrinsic. + * + * @see llvm::Intrinsic::getName() + */ +const char *LLVMIntrinsicGetName(unsigned ID, size_t *NameLength); + +/** + * Copies the name of an overloaded intrinsic identified by a given list of + * parameter types. + * + * Unlike LLVMIntrinsicGetName, the caller is responsible for freeing the + * returned string. + * + * @see llvm::Intrinsic::getName() + */ +const char *LLVMIntrinsicCopyOverloadedName(unsigned ID, + LLVMTypeRef *ParamTypes, + size_t ParamCount, + size_t *NameLength); + +/** + * Obtain if the intrinsic identified by the given ID is overloaded. + * + * @see llvm::Intrinsic::isOverloaded() + */ +LLVMBool LLVMIntrinsicIsOverloaded(unsigned ID); + +/** + * Obtain the calling function of a function. + * + * The returned value corresponds to the LLVMCallConv enumeration. + * + * @see llvm::Function::getCallingConv() + */ +unsigned LLVMGetFunctionCallConv(LLVMValueRef Fn); + +/** + * Set the calling convention of a function. + * + * @see llvm::Function::setCallingConv() + * + * @param Fn Function to operate on + * @param CC LLVMCallConv to set calling convention to + */ +void LLVMSetFunctionCallConv(LLVMValueRef Fn, unsigned CC); + +/** + * Obtain the name of the garbage collector to use during code + * generation. + * + * @see llvm::Function::getGC() + */ +const char *LLVMGetGC(LLVMValueRef Fn); + +/** + * Define the garbage collector to use during code generation. + * + * @see llvm::Function::setGC() + */ +void LLVMSetGC(LLVMValueRef Fn, const char *Name); + +/** + * Add an attribute to a function. + * + * @see llvm::Function::addAttribute() + */ +void LLVMAddAttributeAtIndex(LLVMValueRef F, LLVMAttributeIndex Idx, + LLVMAttributeRef A); +unsigned LLVMGetAttributeCountAtIndex(LLVMValueRef F, LLVMAttributeIndex Idx); +void LLVMGetAttributesAtIndex(LLVMValueRef F, LLVMAttributeIndex Idx, + LLVMAttributeRef *Attrs); +LLVMAttributeRef LLVMGetEnumAttributeAtIndex(LLVMValueRef F, + LLVMAttributeIndex Idx, + unsigned KindID); +LLVMAttributeRef LLVMGetStringAttributeAtIndex(LLVMValueRef F, + LLVMAttributeIndex Idx, + const char *K, unsigned KLen); +void LLVMRemoveEnumAttributeAtIndex(LLVMValueRef F, LLVMAttributeIndex Idx, + unsigned KindID); +void LLVMRemoveStringAttributeAtIndex(LLVMValueRef F, LLVMAttributeIndex Idx, + const char *K, unsigned KLen); + +/** + * Add a target-dependent attribute to a function + * @see llvm::AttrBuilder::addAttribute() + */ +void LLVMAddTargetDependentFunctionAttr(LLVMValueRef Fn, const char *A, + const char *V); + +/** + * @defgroup LLVMCCoreValueFunctionParameters Function Parameters + * + * Functions in this group relate to arguments/parameters on functions. + * + * Functions in this group expect LLVMValueRef instances that correspond + * to llvm::Function instances. + * + * @{ + */ + +/** + * Obtain the number of parameters in a function. + * + * @see llvm::Function::arg_size() + */ +unsigned LLVMCountParams(LLVMValueRef Fn); + +/** + * Obtain the parameters in a function. + * + * The takes a pointer to a pre-allocated array of LLVMValueRef that is + * at least LLVMCountParams() long. This array will be filled with + * LLVMValueRef instances which correspond to the parameters the + * function receives. Each LLVMValueRef corresponds to a llvm::Argument + * instance. + * + * @see llvm::Function::arg_begin() + */ +void LLVMGetParams(LLVMValueRef Fn, LLVMValueRef *Params); + +/** + * Obtain the parameter at the specified index. + * + * Parameters are indexed from 0. + * + * @see llvm::Function::arg_begin() + */ +LLVMValueRef LLVMGetParam(LLVMValueRef Fn, unsigned Index); + +/** + * Obtain the function to which this argument belongs. + * + * Unlike other functions in this group, this one takes an LLVMValueRef + * that corresponds to a llvm::Attribute. + * + * The returned LLVMValueRef is the llvm::Function to which this + * argument belongs. + */ +LLVMValueRef LLVMGetParamParent(LLVMValueRef Inst); + +/** + * Obtain the first parameter to a function. + * + * @see llvm::Function::arg_begin() + */ +LLVMValueRef LLVMGetFirstParam(LLVMValueRef Fn); + +/** + * Obtain the last parameter to a function. + * + * @see llvm::Function::arg_end() + */ +LLVMValueRef LLVMGetLastParam(LLVMValueRef Fn); + +/** + * Obtain the next parameter to a function. + * + * This takes an LLVMValueRef obtained from LLVMGetFirstParam() (which is + * actually a wrapped iterator) and obtains the next parameter from the + * underlying iterator. + */ +LLVMValueRef LLVMGetNextParam(LLVMValueRef Arg); + +/** + * Obtain the previous parameter to a function. + * + * This is the opposite of LLVMGetNextParam(). + */ +LLVMValueRef LLVMGetPreviousParam(LLVMValueRef Arg); + +/** + * Set the alignment for a function parameter. + * + * @see llvm::Argument::addAttr() + * @see llvm::AttrBuilder::addAlignmentAttr() + */ +void LLVMSetParamAlignment(LLVMValueRef Arg, unsigned Align); + +/** + * @} + */ + +/** + * @defgroup LLVMCCoreValueGlobalIFunc IFuncs + * + * Functions in this group relate to indirect functions. + * + * Functions in this group expect LLVMValueRef instances that correspond + * to llvm::GlobalIFunc instances. + * + * @{ + */ + +/** + * Add a global indirect function to a module under a specified name. + * + * @see llvm::GlobalIFunc::create() + */ +LLVMValueRef LLVMAddGlobalIFunc(LLVMModuleRef M, + const char *Name, size_t NameLen, + LLVMTypeRef Ty, unsigned AddrSpace, + LLVMValueRef Resolver); + +/** + * Obtain a GlobalIFunc value from a Module by its name. + * + * The returned value corresponds to a llvm::GlobalIFunc value. + * + * @see llvm::Module::getNamedIFunc() + */ +LLVMValueRef LLVMGetNamedGlobalIFunc(LLVMModuleRef M, + const char *Name, size_t NameLen); + +/** + * Obtain an iterator to the first GlobalIFunc in a Module. + * + * @see llvm::Module::ifunc_begin() + */ +LLVMValueRef LLVMGetFirstGlobalIFunc(LLVMModuleRef M); + +/** + * Obtain an iterator to the last GlobalIFunc in a Module. + * + * @see llvm::Module::ifunc_end() + */ +LLVMValueRef LLVMGetLastGlobalIFunc(LLVMModuleRef M); + +/** + * Advance a GlobalIFunc iterator to the next GlobalIFunc. + * + * Returns NULL if the iterator was already at the end and there are no more + * global aliases. + */ +LLVMValueRef LLVMGetNextGlobalIFunc(LLVMValueRef IFunc); + +/** + * Decrement a GlobalIFunc iterator to the previous GlobalIFunc. + * + * Returns NULL if the iterator was already at the beginning and there are + * no previous global aliases. + */ +LLVMValueRef LLVMGetPreviousGlobalIFunc(LLVMValueRef IFunc); + +/** + * Retrieves the resolver function associated with this indirect function, or + * NULL if it doesn't not exist. + * + * @see llvm::GlobalIFunc::getResolver() + */ +LLVMValueRef LLVMGetGlobalIFuncResolver(LLVMValueRef IFunc); + +/** + * Sets the resolver function associated with this indirect function. + * + * @see llvm::GlobalIFunc::setResolver() + */ +void LLVMSetGlobalIFuncResolver(LLVMValueRef IFunc, LLVMValueRef Resolver); + +/** + * Remove a global indirect function from its parent module and delete it. + * + * @see llvm::GlobalIFunc::eraseFromParent() + */ +void LLVMEraseGlobalIFunc(LLVMValueRef IFunc); + +/** + * Remove a global indirect function from its parent module. + * + * This unlinks the global indirect function from its containing module but + * keeps it alive. + * + * @see llvm::GlobalIFunc::removeFromParent() + */ +void LLVMRemoveGlobalIFunc(LLVMValueRef IFunc); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @defgroup LLVMCCoreValueMetadata Metadata + * + * @{ + */ + +/** + * Create an MDString value from a given string value. + * + * The MDString value does not take ownership of the given string, it remains + * the responsibility of the caller to free it. + * + * @see llvm::MDString::get() + */ +LLVMMetadataRef LLVMMDStringInContext2(LLVMContextRef C, const char *Str, + size_t SLen); + +/** + * Create an MDNode value with the given array of operands. + * + * @see llvm::MDNode::get() + */ +LLVMMetadataRef LLVMMDNodeInContext2(LLVMContextRef C, LLVMMetadataRef *MDs, + size_t Count); + +/** + * Obtain a Metadata as a Value. + */ +LLVMValueRef LLVMMetadataAsValue(LLVMContextRef C, LLVMMetadataRef MD); + +/** + * Obtain a Value as a Metadata. + */ +LLVMMetadataRef LLVMValueAsMetadata(LLVMValueRef Val); + +/** + * Obtain the underlying string from a MDString value. + * + * @param V Instance to obtain string from. + * @param Length Memory address which will hold length of returned string. + * @return String data in MDString. + */ +const char *LLVMGetMDString(LLVMValueRef V, unsigned *Length); + +/** + * Obtain the number of operands from an MDNode value. + * + * @param V MDNode to get number of operands from. + * @return Number of operands of the MDNode. + */ +unsigned LLVMGetMDNodeNumOperands(LLVMValueRef V); + +/** + * Obtain the given MDNode's operands. + * + * The passed LLVMValueRef pointer should point to enough memory to hold all of + * the operands of the given MDNode (see LLVMGetMDNodeNumOperands) as + * LLVMValueRefs. This memory will be populated with the LLVMValueRefs of the + * MDNode's operands. + * + * @param V MDNode to get the operands from. + * @param Dest Destination array for operands. + */ +void LLVMGetMDNodeOperands(LLVMValueRef V, LLVMValueRef *Dest); + +/** Deprecated: Use LLVMMDStringInContext2 instead. */ +LLVMValueRef LLVMMDStringInContext(LLVMContextRef C, const char *Str, + unsigned SLen); +/** Deprecated: Use LLVMMDStringInContext2 instead. */ +LLVMValueRef LLVMMDString(const char *Str, unsigned SLen); +/** Deprecated: Use LLVMMDNodeInContext2 instead. */ +LLVMValueRef LLVMMDNodeInContext(LLVMContextRef C, LLVMValueRef *Vals, + unsigned Count); +/** Deprecated: Use LLVMMDNodeInContext2 instead. */ +LLVMValueRef LLVMMDNode(LLVMValueRef *Vals, unsigned Count); + +/** + * @} + */ + +/** + * @defgroup LLVMCCoreValueBasicBlock Basic Block + * + * A basic block represents a single entry single exit section of code. + * Basic blocks contain a list of instructions which form the body of + * the block. + * + * Basic blocks belong to functions. They have the type of label. + * + * Basic blocks are themselves values. However, the C API models them as + * LLVMBasicBlockRef. + * + * @see llvm::BasicBlock + * + * @{ + */ + +/** + * Convert a basic block instance to a value type. + */ +LLVMValueRef LLVMBasicBlockAsValue(LLVMBasicBlockRef BB); + +/** + * Determine whether an LLVMValueRef is itself a basic block. + */ +LLVMBool LLVMValueIsBasicBlock(LLVMValueRef Val); + +/** + * Convert an LLVMValueRef to an LLVMBasicBlockRef instance. + */ +LLVMBasicBlockRef LLVMValueAsBasicBlock(LLVMValueRef Val); + +/** + * Obtain the string name of a basic block. + */ +const char *LLVMGetBasicBlockName(LLVMBasicBlockRef BB); + +/** + * Obtain the function to which a basic block belongs. + * + * @see llvm::BasicBlock::getParent() + */ +LLVMValueRef LLVMGetBasicBlockParent(LLVMBasicBlockRef BB); + +/** + * Obtain the terminator instruction for a basic block. + * + * If the basic block does not have a terminator (it is not well-formed + * if it doesn't), then NULL is returned. + * + * The returned LLVMValueRef corresponds to an llvm::Instruction. + * + * @see llvm::BasicBlock::getTerminator() + */ +LLVMValueRef LLVMGetBasicBlockTerminator(LLVMBasicBlockRef BB); + +/** + * Obtain the number of basic blocks in a function. + * + * @param Fn Function value to operate on. + */ +unsigned LLVMCountBasicBlocks(LLVMValueRef Fn); + +/** + * Obtain all of the basic blocks in a function. + * + * This operates on a function value. The BasicBlocks parameter is a + * pointer to a pre-allocated array of LLVMBasicBlockRef of at least + * LLVMCountBasicBlocks() in length. This array is populated with + * LLVMBasicBlockRef instances. + */ +void LLVMGetBasicBlocks(LLVMValueRef Fn, LLVMBasicBlockRef *BasicBlocks); + +/** + * Obtain the first basic block in a function. + * + * The returned basic block can be used as an iterator. You will likely + * eventually call into LLVMGetNextBasicBlock() with it. + * + * @see llvm::Function::begin() + */ +LLVMBasicBlockRef LLVMGetFirstBasicBlock(LLVMValueRef Fn); + +/** + * Obtain the last basic block in a function. + * + * @see llvm::Function::end() + */ +LLVMBasicBlockRef LLVMGetLastBasicBlock(LLVMValueRef Fn); + +/** + * Advance a basic block iterator. + */ +LLVMBasicBlockRef LLVMGetNextBasicBlock(LLVMBasicBlockRef BB); + +/** + * Go backwards in a basic block iterator. + */ +LLVMBasicBlockRef LLVMGetPreviousBasicBlock(LLVMBasicBlockRef BB); + +/** + * Obtain the basic block that corresponds to the entry point of a + * function. + * + * @see llvm::Function::getEntryBlock() + */ +LLVMBasicBlockRef LLVMGetEntryBasicBlock(LLVMValueRef Fn); + +/** + * Insert the given basic block after the insertion point of the given builder. + * + * The insertion point must be valid. + * + * @see llvm::Function::BasicBlockListType::insertAfter() + */ +void LLVMInsertExistingBasicBlockAfterInsertBlock(LLVMBuilderRef Builder, + LLVMBasicBlockRef BB); + +/** + * Append the given basic block to the basic block list of the given function. + * + * @see llvm::Function::BasicBlockListType::push_back() + */ +void LLVMAppendExistingBasicBlock(LLVMValueRef Fn, + LLVMBasicBlockRef BB); + +/** + * Create a new basic block without inserting it into a function. + * + * @see llvm::BasicBlock::Create() + */ +LLVMBasicBlockRef LLVMCreateBasicBlockInContext(LLVMContextRef C, + const char *Name); + +/** + * Append a basic block to the end of a function. + * + * @see llvm::BasicBlock::Create() + */ +LLVMBasicBlockRef LLVMAppendBasicBlockInContext(LLVMContextRef C, + LLVMValueRef Fn, + const char *Name); + +/** + * Append a basic block to the end of a function using the global + * context. + * + * @see llvm::BasicBlock::Create() + */ +LLVMBasicBlockRef LLVMAppendBasicBlock(LLVMValueRef Fn, const char *Name); + +/** + * Insert a basic block in a function before another basic block. + * + * The function to add to is determined by the function of the + * passed basic block. + * + * @see llvm::BasicBlock::Create() + */ +LLVMBasicBlockRef LLVMInsertBasicBlockInContext(LLVMContextRef C, + LLVMBasicBlockRef BB, + const char *Name); + +/** + * Insert a basic block in a function using the global context. + * + * @see llvm::BasicBlock::Create() + */ +LLVMBasicBlockRef LLVMInsertBasicBlock(LLVMBasicBlockRef InsertBeforeBB, + const char *Name); + +/** + * Remove a basic block from a function and delete it. + * + * This deletes the basic block from its containing function and deletes + * the basic block itself. + * + * @see llvm::BasicBlock::eraseFromParent() + */ +void LLVMDeleteBasicBlock(LLVMBasicBlockRef BB); + +/** + * Remove a basic block from a function. + * + * This deletes the basic block from its containing function but keep + * the basic block alive. + * + * @see llvm::BasicBlock::removeFromParent() + */ +void LLVMRemoveBasicBlockFromParent(LLVMBasicBlockRef BB); + +/** + * Move a basic block to before another one. + * + * @see llvm::BasicBlock::moveBefore() + */ +void LLVMMoveBasicBlockBefore(LLVMBasicBlockRef BB, LLVMBasicBlockRef MovePos); + +/** + * Move a basic block to after another one. + * + * @see llvm::BasicBlock::moveAfter() + */ +void LLVMMoveBasicBlockAfter(LLVMBasicBlockRef BB, LLVMBasicBlockRef MovePos); + +/** + * Obtain the first instruction in a basic block. + * + * The returned LLVMValueRef corresponds to a llvm::Instruction + * instance. + */ +LLVMValueRef LLVMGetFirstInstruction(LLVMBasicBlockRef BB); + +/** + * Obtain the last instruction in a basic block. + * + * The returned LLVMValueRef corresponds to an LLVM:Instruction. + */ +LLVMValueRef LLVMGetLastInstruction(LLVMBasicBlockRef BB); + +/** + * @} + */ + +/** + * @defgroup LLVMCCoreValueInstruction Instructions + * + * Functions in this group relate to the inspection and manipulation of + * individual instructions. + * + * In the C++ API, an instruction is modeled by llvm::Instruction. This + * class has a large number of descendents. llvm::Instruction is a + * llvm::Value and in the C API, instructions are modeled by + * LLVMValueRef. + * + * This group also contains sub-groups which operate on specific + * llvm::Instruction types, e.g. llvm::CallInst. + * + * @{ + */ + +/** + * Determine whether an instruction has any metadata attached. + */ +int LLVMHasMetadata(LLVMValueRef Val); + +/** + * Return metadata associated with an instruction value. + */ +LLVMValueRef LLVMGetMetadata(LLVMValueRef Val, unsigned KindID); + +/** + * Set metadata associated with an instruction value. + */ +void LLVMSetMetadata(LLVMValueRef Val, unsigned KindID, LLVMValueRef Node); + +/** + * Returns the metadata associated with an instruction value, but filters out + * all the debug locations. + * + * @see llvm::Instruction::getAllMetadataOtherThanDebugLoc() + */ +LLVMValueMetadataEntry * +LLVMInstructionGetAllMetadataOtherThanDebugLoc(LLVMValueRef Instr, + size_t *NumEntries); + +/** + * Obtain the basic block to which an instruction belongs. + * + * @see llvm::Instruction::getParent() + */ +LLVMBasicBlockRef LLVMGetInstructionParent(LLVMValueRef Inst); + +/** + * Obtain the instruction that occurs after the one specified. + * + * The next instruction will be from the same basic block. + * + * If this is the last instruction in a basic block, NULL will be + * returned. + */ +LLVMValueRef LLVMGetNextInstruction(LLVMValueRef Inst); + +/** + * Obtain the instruction that occurred before this one. + * + * If the instruction is the first instruction in a basic block, NULL + * will be returned. + */ +LLVMValueRef LLVMGetPreviousInstruction(LLVMValueRef Inst); + +/** + * Remove and delete an instruction. + * + * The instruction specified is removed from its containing building + * block but is kept alive. + * + * @see llvm::Instruction::removeFromParent() + */ +void LLVMInstructionRemoveFromParent(LLVMValueRef Inst); + +/** + * Remove and delete an instruction. + * + * The instruction specified is removed from its containing building + * block and then deleted. + * + * @see llvm::Instruction::eraseFromParent() + */ +void LLVMInstructionEraseFromParent(LLVMValueRef Inst); + +/** + * Obtain the code opcode for an individual instruction. + * + * @see llvm::Instruction::getOpCode() + */ +LLVMOpcode LLVMGetInstructionOpcode(LLVMValueRef Inst); + +/** + * Obtain the predicate of an instruction. + * + * This is only valid for instructions that correspond to llvm::ICmpInst + * or llvm::ConstantExpr whose opcode is llvm::Instruction::ICmp. + * + * @see llvm::ICmpInst::getPredicate() + */ +LLVMIntPredicate LLVMGetICmpPredicate(LLVMValueRef Inst); + +/** + * Obtain the float predicate of an instruction. + * + * This is only valid for instructions that correspond to llvm::FCmpInst + * or llvm::ConstantExpr whose opcode is llvm::Instruction::FCmp. + * + * @see llvm::FCmpInst::getPredicate() + */ +LLVMRealPredicate LLVMGetFCmpPredicate(LLVMValueRef Inst); + +/** + * Create a copy of 'this' instruction that is identical in all ways + * except the following: + * * The instruction has no parent + * * The instruction has no name + * + * @see llvm::Instruction::clone() + */ +LLVMValueRef LLVMInstructionClone(LLVMValueRef Inst); + +/** + * Determine whether an instruction is a terminator. This routine is named to + * be compatible with historical functions that did this by querying the + * underlying C++ type. + * + * @see llvm::Instruction::isTerminator() + */ +LLVMValueRef LLVMIsATerminatorInst(LLVMValueRef Inst); + +/** + * @defgroup LLVMCCoreValueInstructionCall Call Sites and Invocations + * + * Functions in this group apply to instructions that refer to call + * sites and invocations. These correspond to C++ types in the + * llvm::CallInst class tree. + * + * @{ + */ + +/** + * Obtain the argument count for a call instruction. + * + * This expects an LLVMValueRef that corresponds to a llvm::CallInst, + * llvm::InvokeInst, or llvm:FuncletPadInst. + * + * @see llvm::CallInst::getNumArgOperands() + * @see llvm::InvokeInst::getNumArgOperands() + * @see llvm::FuncletPadInst::getNumArgOperands() + */ +unsigned LLVMGetNumArgOperands(LLVMValueRef Instr); + +/** + * Set the calling convention for a call instruction. + * + * This expects an LLVMValueRef that corresponds to a llvm::CallInst or + * llvm::InvokeInst. + * + * @see llvm::CallInst::setCallingConv() + * @see llvm::InvokeInst::setCallingConv() + */ +void LLVMSetInstructionCallConv(LLVMValueRef Instr, unsigned CC); + +/** + * Obtain the calling convention for a call instruction. + * + * This is the opposite of LLVMSetInstructionCallConv(). Reads its + * usage. + * + * @see LLVMSetInstructionCallConv() + */ +unsigned LLVMGetInstructionCallConv(LLVMValueRef Instr); + +void LLVMSetInstrParamAlignment(LLVMValueRef Instr, unsigned index, + unsigned Align); + +void LLVMAddCallSiteAttribute(LLVMValueRef C, LLVMAttributeIndex Idx, + LLVMAttributeRef A); +unsigned LLVMGetCallSiteAttributeCount(LLVMValueRef C, LLVMAttributeIndex Idx); +void LLVMGetCallSiteAttributes(LLVMValueRef C, LLVMAttributeIndex Idx, + LLVMAttributeRef *Attrs); +LLVMAttributeRef LLVMGetCallSiteEnumAttribute(LLVMValueRef C, + LLVMAttributeIndex Idx, + unsigned KindID); +LLVMAttributeRef LLVMGetCallSiteStringAttribute(LLVMValueRef C, + LLVMAttributeIndex Idx, + const char *K, unsigned KLen); +void LLVMRemoveCallSiteEnumAttribute(LLVMValueRef C, LLVMAttributeIndex Idx, + unsigned KindID); +void LLVMRemoveCallSiteStringAttribute(LLVMValueRef C, LLVMAttributeIndex Idx, + const char *K, unsigned KLen); + +/** + * Obtain the function type called by this instruction. + * + * @see llvm::CallBase::getFunctionType() + */ +LLVMTypeRef LLVMGetCalledFunctionType(LLVMValueRef C); + +/** + * Obtain the pointer to the function invoked by this instruction. + * + * This expects an LLVMValueRef that corresponds to a llvm::CallInst or + * llvm::InvokeInst. + * + * @see llvm::CallInst::getCalledValue() + * @see llvm::InvokeInst::getCalledValue() + */ +LLVMValueRef LLVMGetCalledValue(LLVMValueRef Instr); + +/** + * Obtain whether a call instruction is a tail call. + * + * This only works on llvm::CallInst instructions. + * + * @see llvm::CallInst::isTailCall() + */ +LLVMBool LLVMIsTailCall(LLVMValueRef CallInst); + +/** + * Set whether a call instruction is a tail call. + * + * This only works on llvm::CallInst instructions. + * + * @see llvm::CallInst::setTailCall() + */ +void LLVMSetTailCall(LLVMValueRef CallInst, LLVMBool IsTailCall); + +/** + * Return the normal destination basic block. + * + * This only works on llvm::InvokeInst instructions. + * + * @see llvm::InvokeInst::getNormalDest() + */ +LLVMBasicBlockRef LLVMGetNormalDest(LLVMValueRef InvokeInst); + +/** + * Return the unwind destination basic block. + * + * Works on llvm::InvokeInst, llvm::CleanupReturnInst, and + * llvm::CatchSwitchInst instructions. + * + * @see llvm::InvokeInst::getUnwindDest() + * @see llvm::CleanupReturnInst::getUnwindDest() + * @see llvm::CatchSwitchInst::getUnwindDest() + */ +LLVMBasicBlockRef LLVMGetUnwindDest(LLVMValueRef InvokeInst); + +/** + * Set the normal destination basic block. + * + * This only works on llvm::InvokeInst instructions. + * + * @see llvm::InvokeInst::setNormalDest() + */ +void LLVMSetNormalDest(LLVMValueRef InvokeInst, LLVMBasicBlockRef B); + +/** + * Set the unwind destination basic block. + * + * Works on llvm::InvokeInst, llvm::CleanupReturnInst, and + * llvm::CatchSwitchInst instructions. + * + * @see llvm::InvokeInst::setUnwindDest() + * @see llvm::CleanupReturnInst::setUnwindDest() + * @see llvm::CatchSwitchInst::setUnwindDest() + */ +void LLVMSetUnwindDest(LLVMValueRef InvokeInst, LLVMBasicBlockRef B); + +/** + * @} + */ + +/** + * @defgroup LLVMCCoreValueInstructionTerminator Terminators + * + * Functions in this group only apply to instructions for which + * LLVMIsATerminatorInst returns true. + * + * @{ + */ + +/** + * Return the number of successors that this terminator has. + * + * @see llvm::Instruction::getNumSuccessors + */ +unsigned LLVMGetNumSuccessors(LLVMValueRef Term); + +/** + * Return the specified successor. + * + * @see llvm::Instruction::getSuccessor + */ +LLVMBasicBlockRef LLVMGetSuccessor(LLVMValueRef Term, unsigned i); + +/** + * Update the specified successor to point at the provided block. + * + * @see llvm::Instruction::setSuccessor + */ +void LLVMSetSuccessor(LLVMValueRef Term, unsigned i, LLVMBasicBlockRef block); + +/** + * Return if a branch is conditional. + * + * This only works on llvm::BranchInst instructions. + * + * @see llvm::BranchInst::isConditional + */ +LLVMBool LLVMIsConditional(LLVMValueRef Branch); + +/** + * Return the condition of a branch instruction. + * + * This only works on llvm::BranchInst instructions. + * + * @see llvm::BranchInst::getCondition + */ +LLVMValueRef LLVMGetCondition(LLVMValueRef Branch); + +/** + * Set the condition of a branch instruction. + * + * This only works on llvm::BranchInst instructions. + * + * @see llvm::BranchInst::setCondition + */ +void LLVMSetCondition(LLVMValueRef Branch, LLVMValueRef Cond); + +/** + * Obtain the default destination basic block of a switch instruction. + * + * This only works on llvm::SwitchInst instructions. + * + * @see llvm::SwitchInst::getDefaultDest() + */ +LLVMBasicBlockRef LLVMGetSwitchDefaultDest(LLVMValueRef SwitchInstr); + +/** + * @} + */ + +/** + * @defgroup LLVMCCoreValueInstructionAlloca Allocas + * + * Functions in this group only apply to instructions that map to + * llvm::AllocaInst instances. + * + * @{ + */ + +/** + * Obtain the type that is being allocated by the alloca instruction. + */ +LLVMTypeRef LLVMGetAllocatedType(LLVMValueRef Alloca); + +/** + * @} + */ + +/** + * @defgroup LLVMCCoreValueInstructionGetElementPointer GEPs + * + * Functions in this group only apply to instructions that map to + * llvm::GetElementPtrInst instances. + * + * @{ + */ + +/** + * Check whether the given GEP instruction is inbounds. + */ +LLVMBool LLVMIsInBounds(LLVMValueRef GEP); + +/** + * Set the given GEP instruction to be inbounds or not. + */ +void LLVMSetIsInBounds(LLVMValueRef GEP, LLVMBool InBounds); + +/** + * @} + */ + +/** + * @defgroup LLVMCCoreValueInstructionPHINode PHI Nodes + * + * Functions in this group only apply to instructions that map to + * llvm::PHINode instances. + * + * @{ + */ + +/** + * Add an incoming value to the end of a PHI list. + */ +void LLVMAddIncoming(LLVMValueRef PhiNode, LLVMValueRef *IncomingValues, + LLVMBasicBlockRef *IncomingBlocks, unsigned Count); + +/** + * Obtain the number of incoming basic blocks to a PHI node. + */ +unsigned LLVMCountIncoming(LLVMValueRef PhiNode); + +/** + * Obtain an incoming value to a PHI node as an LLVMValueRef. + */ +LLVMValueRef LLVMGetIncomingValue(LLVMValueRef PhiNode, unsigned Index); + +/** + * Obtain an incoming value to a PHI node as an LLVMBasicBlockRef. + */ +LLVMBasicBlockRef LLVMGetIncomingBlock(LLVMValueRef PhiNode, unsigned Index); + +/** + * @} + */ + +/** + * @defgroup LLVMCCoreValueInstructionExtractValue ExtractValue + * @defgroup LLVMCCoreValueInstructionInsertValue InsertValue + * + * Functions in this group only apply to instructions that map to + * llvm::ExtractValue and llvm::InsertValue instances. + * + * @{ + */ + +/** + * Obtain the number of indices. + * NB: This also works on GEP. + */ +unsigned LLVMGetNumIndices(LLVMValueRef Inst); + +/** + * Obtain the indices as an array. + */ +const unsigned *LLVMGetIndices(LLVMValueRef Inst); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @defgroup LLVMCCoreInstructionBuilder Instruction Builders + * + * An instruction builder represents a point within a basic block and is + * the exclusive means of building instructions using the C interface. + * + * @{ + */ + +LLVMBuilderRef LLVMCreateBuilderInContext(LLVMContextRef C); +LLVMBuilderRef LLVMCreateBuilder(void); +void LLVMPositionBuilder(LLVMBuilderRef Builder, LLVMBasicBlockRef Block, + LLVMValueRef Instr); +void LLVMPositionBuilderBefore(LLVMBuilderRef Builder, LLVMValueRef Instr); +void LLVMPositionBuilderAtEnd(LLVMBuilderRef Builder, LLVMBasicBlockRef Block); +LLVMBasicBlockRef LLVMGetInsertBlock(LLVMBuilderRef Builder); +void LLVMClearInsertionPosition(LLVMBuilderRef Builder); +void LLVMInsertIntoBuilder(LLVMBuilderRef Builder, LLVMValueRef Instr); +void LLVMInsertIntoBuilderWithName(LLVMBuilderRef Builder, LLVMValueRef Instr, + const char *Name); +void LLVMDisposeBuilder(LLVMBuilderRef Builder); + +/* Metadata */ + +/** + * Get location information used by debugging information. + * + * @see llvm::IRBuilder::getCurrentDebugLocation() + */ +LLVMMetadataRef LLVMGetCurrentDebugLocation2(LLVMBuilderRef Builder); + +/** + * Set location information used by debugging information. + * + * To clear the location metadata of the given instruction, pass NULL to \p Loc. + * + * @see llvm::IRBuilder::SetCurrentDebugLocation() + */ +void LLVMSetCurrentDebugLocation2(LLVMBuilderRef Builder, LLVMMetadataRef Loc); + +/** + * Attempts to set the debug location for the given instruction using the + * current debug location for the given builder. If the builder has no current + * debug location, this function is a no-op. + * + * @see llvm::IRBuilder::SetInstDebugLocation() + */ +void LLVMSetInstDebugLocation(LLVMBuilderRef Builder, LLVMValueRef Inst); + +/** + * Get the dafult floating-point math metadata for a given builder. + * + * @see llvm::IRBuilder::getDefaultFPMathTag() + */ +LLVMMetadataRef LLVMBuilderGetDefaultFPMathTag(LLVMBuilderRef Builder); + +/** + * Set the default floating-point math metadata for the given builder. + * + * To clear the metadata, pass NULL to \p FPMathTag. + * + * @see llvm::IRBuilder::setDefaultFPMathTag() + */ +void LLVMBuilderSetDefaultFPMathTag(LLVMBuilderRef Builder, + LLVMMetadataRef FPMathTag); + +/** + * Deprecated: Passing the NULL location will crash. + * Use LLVMGetCurrentDebugLocation2 instead. + */ +void LLVMSetCurrentDebugLocation(LLVMBuilderRef Builder, LLVMValueRef L); +/** + * Deprecated: Returning the NULL location will crash. + * Use LLVMGetCurrentDebugLocation2 instead. + */ +LLVMValueRef LLVMGetCurrentDebugLocation(LLVMBuilderRef Builder); + +/* Terminators */ +LLVMValueRef LLVMBuildRetVoid(LLVMBuilderRef); +LLVMValueRef LLVMBuildRet(LLVMBuilderRef, LLVMValueRef V); +LLVMValueRef LLVMBuildAggregateRet(LLVMBuilderRef, LLVMValueRef *RetVals, + unsigned N); +LLVMValueRef LLVMBuildBr(LLVMBuilderRef, LLVMBasicBlockRef Dest); +LLVMValueRef LLVMBuildCondBr(LLVMBuilderRef, LLVMValueRef If, + LLVMBasicBlockRef Then, LLVMBasicBlockRef Else); +LLVMValueRef LLVMBuildSwitch(LLVMBuilderRef, LLVMValueRef V, + LLVMBasicBlockRef Else, unsigned NumCases); +LLVMValueRef LLVMBuildIndirectBr(LLVMBuilderRef B, LLVMValueRef Addr, + unsigned NumDests); +// LLVMBuildInvoke is deprecated in favor of LLVMBuildInvoke2, in preparation +// for opaque pointer types. +LLVMValueRef LLVMBuildInvoke(LLVMBuilderRef, LLVMValueRef Fn, + LLVMValueRef *Args, unsigned NumArgs, + LLVMBasicBlockRef Then, LLVMBasicBlockRef Catch, + const char *Name); +LLVMValueRef LLVMBuildInvoke2(LLVMBuilderRef, LLVMTypeRef Ty, LLVMValueRef Fn, + LLVMValueRef *Args, unsigned NumArgs, + LLVMBasicBlockRef Then, LLVMBasicBlockRef Catch, + const char *Name); +LLVMValueRef LLVMBuildUnreachable(LLVMBuilderRef); + +/* Exception Handling */ +LLVMValueRef LLVMBuildResume(LLVMBuilderRef B, LLVMValueRef Exn); +LLVMValueRef LLVMBuildLandingPad(LLVMBuilderRef B, LLVMTypeRef Ty, + LLVMValueRef PersFn, unsigned NumClauses, + const char *Name); +LLVMValueRef LLVMBuildCleanupRet(LLVMBuilderRef B, LLVMValueRef CatchPad, + LLVMBasicBlockRef BB); +LLVMValueRef LLVMBuildCatchRet(LLVMBuilderRef B, LLVMValueRef CatchPad, + LLVMBasicBlockRef BB); +LLVMValueRef LLVMBuildCatchPad(LLVMBuilderRef B, LLVMValueRef ParentPad, + LLVMValueRef *Args, unsigned NumArgs, + const char *Name); +LLVMValueRef LLVMBuildCleanupPad(LLVMBuilderRef B, LLVMValueRef ParentPad, + LLVMValueRef *Args, unsigned NumArgs, + const char *Name); +LLVMValueRef LLVMBuildCatchSwitch(LLVMBuilderRef B, LLVMValueRef ParentPad, + LLVMBasicBlockRef UnwindBB, + unsigned NumHandlers, const char *Name); + +/* Add a case to the switch instruction */ +void LLVMAddCase(LLVMValueRef Switch, LLVMValueRef OnVal, + LLVMBasicBlockRef Dest); + +/* Add a destination to the indirectbr instruction */ +void LLVMAddDestination(LLVMValueRef IndirectBr, LLVMBasicBlockRef Dest); + +/* Get the number of clauses on the landingpad instruction */ +unsigned LLVMGetNumClauses(LLVMValueRef LandingPad); + +/* Get the value of the clause at idnex Idx on the landingpad instruction */ +LLVMValueRef LLVMGetClause(LLVMValueRef LandingPad, unsigned Idx); + +/* Add a catch or filter clause to the landingpad instruction */ +void LLVMAddClause(LLVMValueRef LandingPad, LLVMValueRef ClauseVal); + +/* Get the 'cleanup' flag in the landingpad instruction */ +LLVMBool LLVMIsCleanup(LLVMValueRef LandingPad); + +/* Set the 'cleanup' flag in the landingpad instruction */ +void LLVMSetCleanup(LLVMValueRef LandingPad, LLVMBool Val); + +/* Add a destination to the catchswitch instruction */ +void LLVMAddHandler(LLVMValueRef CatchSwitch, LLVMBasicBlockRef Dest); + +/* Get the number of handlers on the catchswitch instruction */ +unsigned LLVMGetNumHandlers(LLVMValueRef CatchSwitch); + +/** + * Obtain the basic blocks acting as handlers for a catchswitch instruction. + * + * The Handlers parameter should point to a pre-allocated array of + * LLVMBasicBlockRefs at least LLVMGetNumHandlers() large. On return, the + * first LLVMGetNumHandlers() entries in the array will be populated + * with LLVMBasicBlockRef instances. + * + * @param CatchSwitch The catchswitch instruction to operate on. + * @param Handlers Memory address of an array to be filled with basic blocks. + */ +void LLVMGetHandlers(LLVMValueRef CatchSwitch, LLVMBasicBlockRef *Handlers); + +/* Funclets */ + +/* Get the number of funcletpad arguments. */ +LLVMValueRef LLVMGetArgOperand(LLVMValueRef Funclet, unsigned i); + +/* Set a funcletpad argument at the given index. */ +void LLVMSetArgOperand(LLVMValueRef Funclet, unsigned i, LLVMValueRef value); + +/** + * Get the parent catchswitch instruction of a catchpad instruction. + * + * This only works on llvm::CatchPadInst instructions. + * + * @see llvm::CatchPadInst::getCatchSwitch() + */ +LLVMValueRef LLVMGetParentCatchSwitch(LLVMValueRef CatchPad); + +/** + * Set the parent catchswitch instruction of a catchpad instruction. + * + * This only works on llvm::CatchPadInst instructions. + * + * @see llvm::CatchPadInst::setCatchSwitch() + */ +void LLVMSetParentCatchSwitch(LLVMValueRef CatchPad, LLVMValueRef CatchSwitch); + +/* Arithmetic */ +LLVMValueRef LLVMBuildAdd(LLVMBuilderRef, LLVMValueRef LHS, LLVMValueRef RHS, + const char *Name); +LLVMValueRef LLVMBuildNSWAdd(LLVMBuilderRef, LLVMValueRef LHS, LLVMValueRef RHS, + const char *Name); +LLVMValueRef LLVMBuildNUWAdd(LLVMBuilderRef, LLVMValueRef LHS, LLVMValueRef RHS, + const char *Name); +LLVMValueRef LLVMBuildFAdd(LLVMBuilderRef, LLVMValueRef LHS, LLVMValueRef RHS, + const char *Name); +LLVMValueRef LLVMBuildSub(LLVMBuilderRef, LLVMValueRef LHS, LLVMValueRef RHS, + const char *Name); +LLVMValueRef LLVMBuildNSWSub(LLVMBuilderRef, LLVMValueRef LHS, LLVMValueRef RHS, + const char *Name); +LLVMValueRef LLVMBuildNUWSub(LLVMBuilderRef, LLVMValueRef LHS, LLVMValueRef RHS, + const char *Name); +LLVMValueRef LLVMBuildFSub(LLVMBuilderRef, LLVMValueRef LHS, LLVMValueRef RHS, + const char *Name); +LLVMValueRef LLVMBuildMul(LLVMBuilderRef, LLVMValueRef LHS, LLVMValueRef RHS, + const char *Name); +LLVMValueRef LLVMBuildNSWMul(LLVMBuilderRef, LLVMValueRef LHS, LLVMValueRef RHS, + const char *Name); +LLVMValueRef LLVMBuildNUWMul(LLVMBuilderRef, LLVMValueRef LHS, LLVMValueRef RHS, + const char *Name); +LLVMValueRef LLVMBuildFMul(LLVMBuilderRef, LLVMValueRef LHS, LLVMValueRef RHS, + const char *Name); +LLVMValueRef LLVMBuildUDiv(LLVMBuilderRef, LLVMValueRef LHS, LLVMValueRef RHS, + const char *Name); +LLVMValueRef LLVMBuildExactUDiv(LLVMBuilderRef, LLVMValueRef LHS, LLVMValueRef RHS, + const char *Name); +LLVMValueRef LLVMBuildSDiv(LLVMBuilderRef, LLVMValueRef LHS, LLVMValueRef RHS, + const char *Name); +LLVMValueRef LLVMBuildExactSDiv(LLVMBuilderRef, LLVMValueRef LHS, LLVMValueRef RHS, + const char *Name); +LLVMValueRef LLVMBuildFDiv(LLVMBuilderRef, LLVMValueRef LHS, LLVMValueRef RHS, + const char *Name); +LLVMValueRef LLVMBuildURem(LLVMBuilderRef, LLVMValueRef LHS, LLVMValueRef RHS, + const char *Name); +LLVMValueRef LLVMBuildSRem(LLVMBuilderRef, LLVMValueRef LHS, LLVMValueRef RHS, + const char *Name); +LLVMValueRef LLVMBuildFRem(LLVMBuilderRef, LLVMValueRef LHS, LLVMValueRef RHS, + const char *Name); +LLVMValueRef LLVMBuildShl(LLVMBuilderRef, LLVMValueRef LHS, LLVMValueRef RHS, + const char *Name); +LLVMValueRef LLVMBuildLShr(LLVMBuilderRef, LLVMValueRef LHS, LLVMValueRef RHS, + const char *Name); +LLVMValueRef LLVMBuildAShr(LLVMBuilderRef, LLVMValueRef LHS, LLVMValueRef RHS, + const char *Name); +LLVMValueRef LLVMBuildAnd(LLVMBuilderRef, LLVMValueRef LHS, LLVMValueRef RHS, + const char *Name); +LLVMValueRef LLVMBuildOr(LLVMBuilderRef, LLVMValueRef LHS, LLVMValueRef RHS, + const char *Name); +LLVMValueRef LLVMBuildXor(LLVMBuilderRef, LLVMValueRef LHS, LLVMValueRef RHS, + const char *Name); +LLVMValueRef LLVMBuildBinOp(LLVMBuilderRef B, LLVMOpcode Op, + LLVMValueRef LHS, LLVMValueRef RHS, + const char *Name); +LLVMValueRef LLVMBuildNeg(LLVMBuilderRef, LLVMValueRef V, const char *Name); +LLVMValueRef LLVMBuildNSWNeg(LLVMBuilderRef B, LLVMValueRef V, + const char *Name); +LLVMValueRef LLVMBuildNUWNeg(LLVMBuilderRef B, LLVMValueRef V, + const char *Name); +LLVMValueRef LLVMBuildFNeg(LLVMBuilderRef, LLVMValueRef V, const char *Name); +LLVMValueRef LLVMBuildNot(LLVMBuilderRef, LLVMValueRef V, const char *Name); + +/* Memory */ +LLVMValueRef LLVMBuildMalloc(LLVMBuilderRef, LLVMTypeRef Ty, const char *Name); +LLVMValueRef LLVMBuildArrayMalloc(LLVMBuilderRef, LLVMTypeRef Ty, + LLVMValueRef Val, const char *Name); + +/** + * Creates and inserts a memset to the specified pointer and the + * specified value. + * + * @see llvm::IRRBuilder::CreateMemSet() + */ +LLVMValueRef LLVMBuildMemSet(LLVMBuilderRef B, LLVMValueRef Ptr, + LLVMValueRef Val, LLVMValueRef Len, + unsigned Align); +/** + * Creates and inserts a memcpy between the specified pointers. + * + * @see llvm::IRRBuilder::CreateMemCpy() + */ +LLVMValueRef LLVMBuildMemCpy(LLVMBuilderRef B, + LLVMValueRef Dst, unsigned DstAlign, + LLVMValueRef Src, unsigned SrcAlign, + LLVMValueRef Size); +/** + * Creates and inserts a memmove between the specified pointers. + * + * @see llvm::IRRBuilder::CreateMemMove() + */ +LLVMValueRef LLVMBuildMemMove(LLVMBuilderRef B, + LLVMValueRef Dst, unsigned DstAlign, + LLVMValueRef Src, unsigned SrcAlign, + LLVMValueRef Size); + +LLVMValueRef LLVMBuildAlloca(LLVMBuilderRef, LLVMTypeRef Ty, const char *Name); +LLVMValueRef LLVMBuildArrayAlloca(LLVMBuilderRef, LLVMTypeRef Ty, + LLVMValueRef Val, const char *Name); +LLVMValueRef LLVMBuildFree(LLVMBuilderRef, LLVMValueRef PointerVal); +// LLVMBuildLoad is deprecated in favor of LLVMBuildLoad2, in preparation for +// opaque pointer types. +LLVMValueRef LLVMBuildLoad(LLVMBuilderRef, LLVMValueRef PointerVal, + const char *Name); +LLVMValueRef LLVMBuildLoad2(LLVMBuilderRef, LLVMTypeRef Ty, + LLVMValueRef PointerVal, const char *Name); +LLVMValueRef LLVMBuildStore(LLVMBuilderRef, LLVMValueRef Val, LLVMValueRef Ptr); +// LLVMBuildGEP, LLVMBuildInBoundsGEP, and LLVMBuildStructGEP are deprecated in +// favor of LLVMBuild*GEP2, in preparation for opaque pointer types. +LLVMValueRef LLVMBuildGEP(LLVMBuilderRef B, LLVMValueRef Pointer, + LLVMValueRef *Indices, unsigned NumIndices, + const char *Name); +LLVMValueRef LLVMBuildInBoundsGEP(LLVMBuilderRef B, LLVMValueRef Pointer, + LLVMValueRef *Indices, unsigned NumIndices, + const char *Name); +LLVMValueRef LLVMBuildStructGEP(LLVMBuilderRef B, LLVMValueRef Pointer, + unsigned Idx, const char *Name); +LLVMValueRef LLVMBuildGEP2(LLVMBuilderRef B, LLVMTypeRef Ty, + LLVMValueRef Pointer, LLVMValueRef *Indices, + unsigned NumIndices, const char *Name); +LLVMValueRef LLVMBuildInBoundsGEP2(LLVMBuilderRef B, LLVMTypeRef Ty, + LLVMValueRef Pointer, LLVMValueRef *Indices, + unsigned NumIndices, const char *Name); +LLVMValueRef LLVMBuildStructGEP2(LLVMBuilderRef B, LLVMTypeRef Ty, + LLVMValueRef Pointer, unsigned Idx, + const char *Name); +LLVMValueRef LLVMBuildGlobalString(LLVMBuilderRef B, const char *Str, + const char *Name); +LLVMValueRef LLVMBuildGlobalStringPtr(LLVMBuilderRef B, const char *Str, + const char *Name); +LLVMBool LLVMGetVolatile(LLVMValueRef MemoryAccessInst); +void LLVMSetVolatile(LLVMValueRef MemoryAccessInst, LLVMBool IsVolatile); +LLVMAtomicOrdering LLVMGetOrdering(LLVMValueRef MemoryAccessInst); +void LLVMSetOrdering(LLVMValueRef MemoryAccessInst, LLVMAtomicOrdering Ordering); + +/* Casts */ +LLVMValueRef LLVMBuildTrunc(LLVMBuilderRef, LLVMValueRef Val, + LLVMTypeRef DestTy, const char *Name); +LLVMValueRef LLVMBuildZExt(LLVMBuilderRef, LLVMValueRef Val, + LLVMTypeRef DestTy, const char *Name); +LLVMValueRef LLVMBuildSExt(LLVMBuilderRef, LLVMValueRef Val, + LLVMTypeRef DestTy, const char *Name); +LLVMValueRef LLVMBuildFPToUI(LLVMBuilderRef, LLVMValueRef Val, + LLVMTypeRef DestTy, const char *Name); +LLVMValueRef LLVMBuildFPToSI(LLVMBuilderRef, LLVMValueRef Val, + LLVMTypeRef DestTy, const char *Name); +LLVMValueRef LLVMBuildUIToFP(LLVMBuilderRef, LLVMValueRef Val, + LLVMTypeRef DestTy, const char *Name); +LLVMValueRef LLVMBuildSIToFP(LLVMBuilderRef, LLVMValueRef Val, + LLVMTypeRef DestTy, const char *Name); +LLVMValueRef LLVMBuildFPTrunc(LLVMBuilderRef, LLVMValueRef Val, + LLVMTypeRef DestTy, const char *Name); +LLVMValueRef LLVMBuildFPExt(LLVMBuilderRef, LLVMValueRef Val, + LLVMTypeRef DestTy, const char *Name); +LLVMValueRef LLVMBuildPtrToInt(LLVMBuilderRef, LLVMValueRef Val, + LLVMTypeRef DestTy, const char *Name); +LLVMValueRef LLVMBuildIntToPtr(LLVMBuilderRef, LLVMValueRef Val, + LLVMTypeRef DestTy, const char *Name); +LLVMValueRef LLVMBuildBitCast(LLVMBuilderRef, LLVMValueRef Val, + LLVMTypeRef DestTy, const char *Name); +LLVMValueRef LLVMBuildAddrSpaceCast(LLVMBuilderRef, LLVMValueRef Val, + LLVMTypeRef DestTy, const char *Name); +LLVMValueRef LLVMBuildZExtOrBitCast(LLVMBuilderRef, LLVMValueRef Val, + LLVMTypeRef DestTy, const char *Name); +LLVMValueRef LLVMBuildSExtOrBitCast(LLVMBuilderRef, LLVMValueRef Val, + LLVMTypeRef DestTy, const char *Name); +LLVMValueRef LLVMBuildTruncOrBitCast(LLVMBuilderRef, LLVMValueRef Val, + LLVMTypeRef DestTy, const char *Name); +LLVMValueRef LLVMBuildCast(LLVMBuilderRef B, LLVMOpcode Op, LLVMValueRef Val, + LLVMTypeRef DestTy, const char *Name); +LLVMValueRef LLVMBuildPointerCast(LLVMBuilderRef, LLVMValueRef Val, + LLVMTypeRef DestTy, const char *Name); +LLVMValueRef LLVMBuildIntCast2(LLVMBuilderRef, LLVMValueRef Val, + LLVMTypeRef DestTy, LLVMBool IsSigned, + const char *Name); +LLVMValueRef LLVMBuildFPCast(LLVMBuilderRef, LLVMValueRef Val, + LLVMTypeRef DestTy, const char *Name); + +/** Deprecated: This cast is always signed. Use LLVMBuildIntCast2 instead. */ +LLVMValueRef LLVMBuildIntCast(LLVMBuilderRef, LLVMValueRef Val, /*Signed cast!*/ + LLVMTypeRef DestTy, const char *Name); + +/* Comparisons */ +LLVMValueRef LLVMBuildICmp(LLVMBuilderRef, LLVMIntPredicate Op, + LLVMValueRef LHS, LLVMValueRef RHS, + const char *Name); +LLVMValueRef LLVMBuildFCmp(LLVMBuilderRef, LLVMRealPredicate Op, + LLVMValueRef LHS, LLVMValueRef RHS, + const char *Name); + +/* Miscellaneous instructions */ +LLVMValueRef LLVMBuildPhi(LLVMBuilderRef, LLVMTypeRef Ty, const char *Name); +// LLVMBuildCall is deprecated in favor of LLVMBuildCall2, in preparation for +// opaque pointer types. +LLVMValueRef LLVMBuildCall(LLVMBuilderRef, LLVMValueRef Fn, + LLVMValueRef *Args, unsigned NumArgs, + const char *Name); +LLVMValueRef LLVMBuildCall2(LLVMBuilderRef, LLVMTypeRef, LLVMValueRef Fn, + LLVMValueRef *Args, unsigned NumArgs, + const char *Name); +LLVMValueRef LLVMBuildSelect(LLVMBuilderRef, LLVMValueRef If, + LLVMValueRef Then, LLVMValueRef Else, + const char *Name); +LLVMValueRef LLVMBuildVAArg(LLVMBuilderRef, LLVMValueRef List, LLVMTypeRef Ty, + const char *Name); +LLVMValueRef LLVMBuildExtractElement(LLVMBuilderRef, LLVMValueRef VecVal, + LLVMValueRef Index, const char *Name); +LLVMValueRef LLVMBuildInsertElement(LLVMBuilderRef, LLVMValueRef VecVal, + LLVMValueRef EltVal, LLVMValueRef Index, + const char *Name); +LLVMValueRef LLVMBuildShuffleVector(LLVMBuilderRef, LLVMValueRef V1, + LLVMValueRef V2, LLVMValueRef Mask, + const char *Name); +LLVMValueRef LLVMBuildExtractValue(LLVMBuilderRef, LLVMValueRef AggVal, + unsigned Index, const char *Name); +LLVMValueRef LLVMBuildInsertValue(LLVMBuilderRef, LLVMValueRef AggVal, + LLVMValueRef EltVal, unsigned Index, + const char *Name); + +LLVMValueRef LLVMBuildIsNull(LLVMBuilderRef, LLVMValueRef Val, + const char *Name); +LLVMValueRef LLVMBuildIsNotNull(LLVMBuilderRef, LLVMValueRef Val, + const char *Name); +LLVMValueRef LLVMBuildPtrDiff(LLVMBuilderRef, LLVMValueRef LHS, + LLVMValueRef RHS, const char *Name); +LLVMValueRef LLVMBuildFence(LLVMBuilderRef B, LLVMAtomicOrdering ordering, + LLVMBool singleThread, const char *Name); +LLVMValueRef LLVMBuildAtomicRMW(LLVMBuilderRef B, LLVMAtomicRMWBinOp op, + LLVMValueRef PTR, LLVMValueRef Val, + LLVMAtomicOrdering ordering, + LLVMBool singleThread); +LLVMValueRef LLVMBuildAtomicCmpXchg(LLVMBuilderRef B, LLVMValueRef Ptr, + LLVMValueRef Cmp, LLVMValueRef New, + LLVMAtomicOrdering SuccessOrdering, + LLVMAtomicOrdering FailureOrdering, + LLVMBool SingleThread); + +LLVMBool LLVMIsAtomicSingleThread(LLVMValueRef AtomicInst); +void LLVMSetAtomicSingleThread(LLVMValueRef AtomicInst, LLVMBool SingleThread); + +LLVMAtomicOrdering LLVMGetCmpXchgSuccessOrdering(LLVMValueRef CmpXchgInst); +void LLVMSetCmpXchgSuccessOrdering(LLVMValueRef CmpXchgInst, + LLVMAtomicOrdering Ordering); +LLVMAtomicOrdering LLVMGetCmpXchgFailureOrdering(LLVMValueRef CmpXchgInst); +void LLVMSetCmpXchgFailureOrdering(LLVMValueRef CmpXchgInst, + LLVMAtomicOrdering Ordering); + +/** + * @} + */ + +/** + * @defgroup LLVMCCoreModuleProvider Module Providers + * + * @{ + */ + +/** + * Changes the type of M so it can be passed to FunctionPassManagers and the + * JIT. They take ModuleProviders for historical reasons. + */ +LLVMModuleProviderRef +LLVMCreateModuleProviderForExistingModule(LLVMModuleRef M); + +/** + * Destroys the module M. + */ +void LLVMDisposeModuleProvider(LLVMModuleProviderRef M); + +/** + * @} + */ + +/** + * @defgroup LLVMCCoreMemoryBuffers Memory Buffers + * + * @{ + */ + +LLVMBool LLVMCreateMemoryBufferWithContentsOfFile(const char *Path, + LLVMMemoryBufferRef *OutMemBuf, + char **OutMessage); +LLVMBool LLVMCreateMemoryBufferWithSTDIN(LLVMMemoryBufferRef *OutMemBuf, + char **OutMessage); +LLVMMemoryBufferRef LLVMCreateMemoryBufferWithMemoryRange(const char *InputData, + size_t InputDataLength, + const char *BufferName, + LLVMBool RequiresNullTerminator); +LLVMMemoryBufferRef LLVMCreateMemoryBufferWithMemoryRangeCopy(const char *InputData, + size_t InputDataLength, + const char *BufferName); +const char *LLVMGetBufferStart(LLVMMemoryBufferRef MemBuf); +size_t LLVMGetBufferSize(LLVMMemoryBufferRef MemBuf); +void LLVMDisposeMemoryBuffer(LLVMMemoryBufferRef MemBuf); + +/** + * @} + */ + +/** + * @defgroup LLVMCCorePassRegistry Pass Registry + * + * @{ + */ + +/** Return the global pass registry, for use with initialization functions. + @see llvm::PassRegistry::getPassRegistry */ +LLVMPassRegistryRef LLVMGetGlobalPassRegistry(void); + +/** + * @} + */ + +/** + * @defgroup LLVMCCorePassManagers Pass Managers + * + * @{ + */ + +/** Constructs a new whole-module pass pipeline. This type of pipeline is + suitable for link-time optimization and whole-module transformations. + @see llvm::PassManager::PassManager */ +LLVMPassManagerRef LLVMCreatePassManager(void); + +/** Constructs a new function-by-function pass pipeline over the module + provider. It does not take ownership of the module provider. This type of + pipeline is suitable for code generation and JIT compilation tasks. + @see llvm::FunctionPassManager::FunctionPassManager */ +LLVMPassManagerRef LLVMCreateFunctionPassManagerForModule(LLVMModuleRef M); + +/** Deprecated: Use LLVMCreateFunctionPassManagerForModule instead. */ +LLVMPassManagerRef LLVMCreateFunctionPassManager(LLVMModuleProviderRef MP); + +/** Initializes, executes on the provided module, and finalizes all of the + passes scheduled in the pass manager. Returns 1 if any of the passes + modified the module, 0 otherwise. + @see llvm::PassManager::run(Module&) */ +LLVMBool LLVMRunPassManager(LLVMPassManagerRef PM, LLVMModuleRef M); + +/** Initializes all of the function passes scheduled in the function pass + manager. Returns 1 if any of the passes modified the module, 0 otherwise. + @see llvm::FunctionPassManager::doInitialization */ +LLVMBool LLVMInitializeFunctionPassManager(LLVMPassManagerRef FPM); + +/** Executes all of the function passes scheduled in the function pass manager + on the provided function. Returns 1 if any of the passes modified the + function, false otherwise. + @see llvm::FunctionPassManager::run(Function&) */ +LLVMBool LLVMRunFunctionPassManager(LLVMPassManagerRef FPM, LLVMValueRef F); + +/** Finalizes all of the function passes scheduled in the function pass + manager. Returns 1 if any of the passes modified the module, 0 otherwise. + @see llvm::FunctionPassManager::doFinalization */ +LLVMBool LLVMFinalizeFunctionPassManager(LLVMPassManagerRef FPM); + +/** Frees the memory of a pass pipeline. For function pipelines, does not free + the module provider. + @see llvm::PassManagerBase::~PassManagerBase. */ +void LLVMDisposePassManager(LLVMPassManagerRef PM); + +/** + * @} + */ + +/** + * @defgroup LLVMCCoreThreading Threading + * + * Handle the structures needed to make LLVM safe for multithreading. + * + * @{ + */ + +/** Deprecated: Multi-threading can only be enabled/disabled with the compile + time define LLVM_ENABLE_THREADS. This function always returns + LLVMIsMultithreaded(). */ +LLVMBool LLVMStartMultithreaded(void); + +/** Deprecated: Multi-threading can only be enabled/disabled with the compile + time define LLVM_ENABLE_THREADS. */ +void LLVMStopMultithreaded(void); + +/** Check whether LLVM is executing in thread-safe mode or not. + @see llvm::llvm_is_multithreaded */ +LLVMBool LLVMIsMultithreaded(void); + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* LLVM_C_CORE_H */ diff --git a/src/llvm-c/DataTypes.h b/src/llvm-c/DataTypes.h new file mode 100644 index 000000000..893b22b49 --- /dev/null +++ b/src/llvm-c/DataTypes.h @@ -0,0 +1,90 @@ +/*===-- include/llvm-c/DataTypes.h - Define fixed size types ------*- C -*-===*\ +|* *| +|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *| +|* Exceptions. *| +|* See https://llvm.org/LICENSE.txt for license information. *| +|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This file contains definitions to figure out the size of _HOST_ data types.*| +|* This file is important because different host OS's define different macros,*| +|* which makes portability tough. This file exports the following *| +|* definitions: *| +|* *| +|* [u]int(32|64)_t : typedefs for signed and unsigned 32/64 bit system types*| +|* [U]INT(8|16|32|64)_(MIN|MAX) : Constants for the min and max values. *| +|* *| +|* No library is required when using these functions. *| +|* *| +|*===----------------------------------------------------------------------===*/ + +/* Please leave this file C-compatible. */ + +#ifndef LLVM_C_DATATYPES_H +#define LLVM_C_DATATYPES_H + +#ifdef __cplusplus +#include +#else +#include +#endif + +#include +#include + +#ifndef _MSC_VER + +#if !defined(UINT32_MAX) +# error "The standard header is not C++11 compliant. Must #define "\ + "__STDC_LIMIT_MACROS before #including llvm-c/DataTypes.h" +#endif + +#if !defined(UINT32_C) +# error "The standard header is not C++11 compliant. Must #define "\ + "__STDC_CONSTANT_MACROS before #including llvm-c/DataTypes.h" +#endif + +/* Note that includes , if this is a C99 system. */ +#include + +#ifdef _AIX +// GCC is strict about defining large constants: they must have LL modifier. +#undef INT64_MAX +#undef INT64_MIN +#endif + +#else /* _MSC_VER */ +#ifdef __cplusplus +#include +#include +#else +#include +#include +#endif +#include + +#if defined(_WIN64) +typedef signed __int64 ssize_t; +#else +typedef signed int ssize_t; +#endif /* _WIN64 */ + +#endif /* _MSC_VER */ + +/* Set defaults for constants which we cannot find. */ +#if !defined(INT64_MAX) +# define INT64_MAX 9223372036854775807LL +#endif +#if !defined(INT64_MIN) +# define INT64_MIN ((-INT64_MAX)-1) +#endif +#if !defined(UINT64_MAX) +# define UINT64_MAX 0xffffffffffffffffULL +#endif + +#ifndef HUGE_VALF +#define HUGE_VALF (float)HUGE_VAL +#endif + +#endif /* LLVM_C_DATATYPES_H */ diff --git a/src/llvm-c/DebugInfo.h b/src/llvm-c/DebugInfo.h new file mode 100644 index 000000000..33c8110a8 --- /dev/null +++ b/src/llvm-c/DebugInfo.h @@ -0,0 +1,1315 @@ +//===------------ DebugInfo.h - LLVM C API Debug Info API -----------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// This file declares the C API endpoints for generating DWARF Debug Info +/// +/// Note: This interface is experimental. It is *NOT* stable, and may be +/// changed without warning. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_C_DEBUGINFO_H +#define LLVM_C_DEBUGINFO_H + +#include "llvm-c/Core.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Debug info flags. + */ +typedef enum { + LLVMDIFlagZero = 0, + LLVMDIFlagPrivate = 1, + LLVMDIFlagProtected = 2, + LLVMDIFlagPublic = 3, + LLVMDIFlagFwdDecl = 1 << 2, + LLVMDIFlagAppleBlock = 1 << 3, + LLVMDIFlagBlockByrefStruct = 1 << 4, + LLVMDIFlagVirtual = 1 << 5, + LLVMDIFlagArtificial = 1 << 6, + LLVMDIFlagExplicit = 1 << 7, + LLVMDIFlagPrototyped = 1 << 8, + LLVMDIFlagObjcClassComplete = 1 << 9, + LLVMDIFlagObjectPointer = 1 << 10, + LLVMDIFlagVector = 1 << 11, + LLVMDIFlagStaticMember = 1 << 12, + LLVMDIFlagLValueReference = 1 << 13, + LLVMDIFlagRValueReference = 1 << 14, + LLVMDIFlagReserved = 1 << 15, + LLVMDIFlagSingleInheritance = 1 << 16, + LLVMDIFlagMultipleInheritance = 2 << 16, + LLVMDIFlagVirtualInheritance = 3 << 16, + LLVMDIFlagIntroducedVirtual = 1 << 18, + LLVMDIFlagBitField = 1 << 19, + LLVMDIFlagNoReturn = 1 << 20, + LLVMDIFlagTypePassByValue = 1 << 22, + LLVMDIFlagTypePassByReference = 1 << 23, + LLVMDIFlagEnumClass = 1 << 24, + LLVMDIFlagFixedEnum = LLVMDIFlagEnumClass, // Deprecated. + LLVMDIFlagThunk = 1 << 25, + LLVMDIFlagNonTrivial = 1 << 26, + LLVMDIFlagBigEndian = 1 << 27, + LLVMDIFlagLittleEndian = 1 << 28, + LLVMDIFlagIndirectVirtualBase = (1 << 2) | (1 << 5), + LLVMDIFlagAccessibility = LLVMDIFlagPrivate | LLVMDIFlagProtected | + LLVMDIFlagPublic, + LLVMDIFlagPtrToMemberRep = LLVMDIFlagSingleInheritance | + LLVMDIFlagMultipleInheritance | + LLVMDIFlagVirtualInheritance +} LLVMDIFlags; + +/** + * Source languages known by DWARF. + */ +typedef enum { + LLVMDWARFSourceLanguageC89, + LLVMDWARFSourceLanguageC, + LLVMDWARFSourceLanguageAda83, + LLVMDWARFSourceLanguageC_plus_plus, + LLVMDWARFSourceLanguageCobol74, + LLVMDWARFSourceLanguageCobol85, + LLVMDWARFSourceLanguageFortran77, + LLVMDWARFSourceLanguageFortran90, + LLVMDWARFSourceLanguagePascal83, + LLVMDWARFSourceLanguageModula2, + // New in DWARF v3: + LLVMDWARFSourceLanguageJava, + LLVMDWARFSourceLanguageC99, + LLVMDWARFSourceLanguageAda95, + LLVMDWARFSourceLanguageFortran95, + LLVMDWARFSourceLanguagePLI, + LLVMDWARFSourceLanguageObjC, + LLVMDWARFSourceLanguageObjC_plus_plus, + LLVMDWARFSourceLanguageUPC, + LLVMDWARFSourceLanguageD, + // New in DWARF v4: + LLVMDWARFSourceLanguagePython, + // New in DWARF v5: + LLVMDWARFSourceLanguageOpenCL, + LLVMDWARFSourceLanguageGo, + LLVMDWARFSourceLanguageModula3, + LLVMDWARFSourceLanguageHaskell, + LLVMDWARFSourceLanguageC_plus_plus_03, + LLVMDWARFSourceLanguageC_plus_plus_11, + LLVMDWARFSourceLanguageOCaml, + LLVMDWARFSourceLanguageRust, + LLVMDWARFSourceLanguageC11, + LLVMDWARFSourceLanguageSwift, + LLVMDWARFSourceLanguageJulia, + LLVMDWARFSourceLanguageDylan, + LLVMDWARFSourceLanguageC_plus_plus_14, + LLVMDWARFSourceLanguageFortran03, + LLVMDWARFSourceLanguageFortran08, + LLVMDWARFSourceLanguageRenderScript, + LLVMDWARFSourceLanguageBLISS, + // Vendor extensions: + LLVMDWARFSourceLanguageMips_Assembler, + LLVMDWARFSourceLanguageGOOGLE_RenderScript, + LLVMDWARFSourceLanguageBORLAND_Delphi +} LLVMDWARFSourceLanguage; + +/** + * The amount of debug information to emit. + */ +typedef enum { + LLVMDWARFEmissionNone = 0, + LLVMDWARFEmissionFull, + LLVMDWARFEmissionLineTablesOnly +} LLVMDWARFEmissionKind; + +/** + * The kind of metadata nodes. + */ +enum { + LLVMMDStringMetadataKind, + LLVMConstantAsMetadataMetadataKind, + LLVMLocalAsMetadataMetadataKind, + LLVMDistinctMDOperandPlaceholderMetadataKind, + LLVMMDTupleMetadataKind, + LLVMDILocationMetadataKind, + LLVMDIExpressionMetadataKind, + LLVMDIGlobalVariableExpressionMetadataKind, + LLVMGenericDINodeMetadataKind, + LLVMDISubrangeMetadataKind, + LLVMDIEnumeratorMetadataKind, + LLVMDIBasicTypeMetadataKind, + LLVMDIDerivedTypeMetadataKind, + LLVMDICompositeTypeMetadataKind, + LLVMDISubroutineTypeMetadataKind, + LLVMDIFileMetadataKind, + LLVMDICompileUnitMetadataKind, + LLVMDISubprogramMetadataKind, + LLVMDILexicalBlockMetadataKind, + LLVMDILexicalBlockFileMetadataKind, + LLVMDINamespaceMetadataKind, + LLVMDIModuleMetadataKind, + LLVMDITemplateTypeParameterMetadataKind, + LLVMDITemplateValueParameterMetadataKind, + LLVMDIGlobalVariableMetadataKind, + LLVMDILocalVariableMetadataKind, + LLVMDILabelMetadataKind, + LLVMDIObjCPropertyMetadataKind, + LLVMDIImportedEntityMetadataKind, + LLVMDIMacroMetadataKind, + LLVMDIMacroFileMetadataKind, + LLVMDICommonBlockMetadataKind +}; +typedef unsigned LLVMMetadataKind; + +/** + * An LLVM DWARF type encoding. + */ +typedef unsigned LLVMDWARFTypeEncoding; + +/** + * The current debug metadata version number. + */ +unsigned LLVMDebugMetadataVersion(void); + +/** + * The version of debug metadata that's present in the provided \c Module. + */ +unsigned LLVMGetModuleDebugMetadataVersion(LLVMModuleRef Module); + +/** + * Strip debug info in the module if it exists. + * To do this, we remove all calls to the debugger intrinsics and any named + * metadata for debugging. We also remove debug locations for instructions. + * Return true if module is modified. + */ +LLVMBool LLVMStripModuleDebugInfo(LLVMModuleRef Module); + +/** + * Construct a builder for a module, and do not allow for unresolved nodes + * attached to the module. + */ +LLVMDIBuilderRef LLVMCreateDIBuilderDisallowUnresolved(LLVMModuleRef M); + +/** + * Construct a builder for a module and collect unresolved nodes attached + * to the module in order to resolve cycles during a call to + * \c LLVMDIBuilderFinalize. + */ +LLVMDIBuilderRef LLVMCreateDIBuilder(LLVMModuleRef M); + +/** + * Deallocates the \c DIBuilder and everything it owns. + * @note You must call \c LLVMDIBuilderFinalize before this + */ +void LLVMDisposeDIBuilder(LLVMDIBuilderRef Builder); + +/** + * Construct any deferred debug info descriptors. + */ +void LLVMDIBuilderFinalize(LLVMDIBuilderRef Builder); + +/** + * A CompileUnit provides an anchor for all debugging + * information generated during this instance of compilation. + * \param Lang Source programming language, eg. + * \c LLVMDWARFSourceLanguageC99 + * \param FileRef File info. + * \param Producer Identify the producer of debugging information + * and code. Usually this is a compiler + * version string. + * \param ProducerLen The length of the C string passed to \c Producer. + * \param isOptimized A boolean flag which indicates whether optimization + * is enabled or not. + * \param Flags This string lists command line options. This + * string is directly embedded in debug info + * output which may be used by a tool + * analyzing generated debugging information. + * \param FlagsLen The length of the C string passed to \c Flags. + * \param RuntimeVer This indicates runtime version for languages like + * Objective-C. + * \param SplitName The name of the file that we'll split debug info + * out into. + * \param SplitNameLen The length of the C string passed to \c SplitName. + * \param Kind The kind of debug information to generate. + * \param DWOId The DWOId if this is a split skeleton compile unit. + * \param SplitDebugInlining Whether to emit inline debug info. + * \param DebugInfoForProfiling Whether to emit extra debug info for + * profile collection. + */ +LLVMMetadataRef LLVMDIBuilderCreateCompileUnit( + LLVMDIBuilderRef Builder, LLVMDWARFSourceLanguage Lang, + LLVMMetadataRef FileRef, const char *Producer, size_t ProducerLen, + LLVMBool isOptimized, const char *Flags, size_t FlagsLen, + unsigned RuntimeVer, const char *SplitName, size_t SplitNameLen, + LLVMDWARFEmissionKind Kind, unsigned DWOId, LLVMBool SplitDebugInlining, + LLVMBool DebugInfoForProfiling); + +/** + * Create a file descriptor to hold debugging information for a file. + * \param Builder The \c DIBuilder. + * \param Filename File name. + * \param FilenameLen The length of the C string passed to \c Filename. + * \param Directory Directory. + * \param DirectoryLen The length of the C string passed to \c Directory. + */ +LLVMMetadataRef +LLVMDIBuilderCreateFile(LLVMDIBuilderRef Builder, const char *Filename, + size_t FilenameLen, const char *Directory, + size_t DirectoryLen); + +/** + * Creates a new descriptor for a module with the specified parent scope. + * \param Builder The \c DIBuilder. + * \param ParentScope The parent scope containing this module declaration. + * \param Name Module name. + * \param NameLen The length of the C string passed to \c Name. + * \param ConfigMacros A space-separated shell-quoted list of -D macro + definitions as they would appear on a command line. + * \param ConfigMacrosLen The length of the C string passed to \c ConfigMacros. + * \param IncludePath The path to the module map file. + * \param IncludePathLen The length of the C string passed to \c IncludePath. + * \param ISysRoot The Clang system root (value of -isysroot). + * \param ISysRootLen The length of the C string passed to \c ISysRoot. + */ +LLVMMetadataRef +LLVMDIBuilderCreateModule(LLVMDIBuilderRef Builder, LLVMMetadataRef ParentScope, + const char *Name, size_t NameLen, + const char *ConfigMacros, size_t ConfigMacrosLen, + const char *IncludePath, size_t IncludePathLen, + const char *ISysRoot, size_t ISysRootLen); + +/** + * Creates a new descriptor for a namespace with the specified parent scope. + * \param Builder The \c DIBuilder. + * \param ParentScope The parent scope containing this module declaration. + * \param Name NameSpace name. + * \param NameLen The length of the C string passed to \c Name. + * \param ExportSymbols Whether or not the namespace exports symbols, e.g. + * this is true of C++ inline namespaces. + */ +LLVMMetadataRef +LLVMDIBuilderCreateNameSpace(LLVMDIBuilderRef Builder, + LLVMMetadataRef ParentScope, + const char *Name, size_t NameLen, + LLVMBool ExportSymbols); + +/** + * Create a new descriptor for the specified subprogram. + * \param Builder The \c DIBuilder. + * \param Scope Function scope. + * \param Name Function name. + * \param NameLen Length of enumeration name. + * \param LinkageName Mangled function name. + * \param LinkageNameLen Length of linkage name. + * \param File File where this variable is defined. + * \param LineNo Line number. + * \param Ty Function type. + * \param IsLocalToUnit True if this function is not externally visible. + * \param IsDefinition True if this is a function definition. + * \param ScopeLine Set to the beginning of the scope this starts + * \param Flags E.g.: \c LLVMDIFlagLValueReference. These flags are + * used to emit dwarf attributes. + * \param IsOptimized True if optimization is ON. + */ +LLVMMetadataRef LLVMDIBuilderCreateFunction( + LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, + size_t NameLen, const char *LinkageName, size_t LinkageNameLen, + LLVMMetadataRef File, unsigned LineNo, LLVMMetadataRef Ty, + LLVMBool IsLocalToUnit, LLVMBool IsDefinition, + unsigned ScopeLine, LLVMDIFlags Flags, LLVMBool IsOptimized); + +/** + * Create a descriptor for a lexical block with the specified parent context. + * \param Builder The \c DIBuilder. + * \param Scope Parent lexical block. + * \param File Source file. + * \param Line The line in the source file. + * \param Column The column in the source file. + */ +LLVMMetadataRef LLVMDIBuilderCreateLexicalBlock( + LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, + LLVMMetadataRef File, unsigned Line, unsigned Column); + +/** + * Create a descriptor for a lexical block with a new file attached. + * \param Builder The \c DIBuilder. + * \param Scope Lexical block. + * \param File Source file. + * \param Discriminator DWARF path discriminator value. + */ +LLVMMetadataRef +LLVMDIBuilderCreateLexicalBlockFile(LLVMDIBuilderRef Builder, + LLVMMetadataRef Scope, + LLVMMetadataRef File, + unsigned Discriminator); + +/** + * Create a descriptor for an imported namespace. Suitable for e.g. C++ + * using declarations. + * \param Builder The \c DIBuilder. + * \param Scope The scope this module is imported into + * \param File File where the declaration is located. + * \param Line Line number of the declaration. + */ +LLVMMetadataRef +LLVMDIBuilderCreateImportedModuleFromNamespace(LLVMDIBuilderRef Builder, + LLVMMetadataRef Scope, + LLVMMetadataRef NS, + LLVMMetadataRef File, + unsigned Line); + +/** + * Create a descriptor for an imported module that aliases another + * imported entity descriptor. + * \param Builder The \c DIBuilder. + * \param Scope The scope this module is imported into + * \param ImportedEntity Previous imported entity to alias. + * \param File File where the declaration is located. + * \param Line Line number of the declaration. + */ +LLVMMetadataRef +LLVMDIBuilderCreateImportedModuleFromAlias(LLVMDIBuilderRef Builder, + LLVMMetadataRef Scope, + LLVMMetadataRef ImportedEntity, + LLVMMetadataRef File, + unsigned Line); + +/** + * Create a descriptor for an imported module. + * \param Builder The \c DIBuilder. + * \param Scope The scope this module is imported into + * \param M The module being imported here + * \param File File where the declaration is located. + * \param Line Line number of the declaration. + */ +LLVMMetadataRef +LLVMDIBuilderCreateImportedModuleFromModule(LLVMDIBuilderRef Builder, + LLVMMetadataRef Scope, + LLVMMetadataRef M, + LLVMMetadataRef File, + unsigned Line); + +/** + * Create a descriptor for an imported function, type, or variable. Suitable + * for e.g. FORTRAN-style USE declarations. + * \param Builder The DIBuilder. + * \param Scope The scope this module is imported into. + * \param Decl The declaration (or definition) of a function, type, + or variable. + * \param File File where the declaration is located. + * \param Line Line number of the declaration. + * \param Name A name that uniquely identifies this imported declaration. + * \param NameLen The length of the C string passed to \c Name. + */ +LLVMMetadataRef +LLVMDIBuilderCreateImportedDeclaration(LLVMDIBuilderRef Builder, + LLVMMetadataRef Scope, + LLVMMetadataRef Decl, + LLVMMetadataRef File, + unsigned Line, + const char *Name, size_t NameLen); + +/** + * Creates a new DebugLocation that describes a source location. + * \param Line The line in the source file. + * \param Column The column in the source file. + * \param Scope The scope in which the location resides. + * \param InlinedAt The scope where this location was inlined, if at all. + * (optional). + * \note If the item to which this location is attached cannot be + * attributed to a source line, pass 0 for the line and column. + */ +LLVMMetadataRef +LLVMDIBuilderCreateDebugLocation(LLVMContextRef Ctx, unsigned Line, + unsigned Column, LLVMMetadataRef Scope, + LLVMMetadataRef InlinedAt); + +/** + * Get the line number of this debug location. + * \param Location The debug location. + * + * @see DILocation::getLine() + */ +unsigned LLVMDILocationGetLine(LLVMMetadataRef Location); + +/** + * Get the column number of this debug location. + * \param Location The debug location. + * + * @see DILocation::getColumn() + */ +unsigned LLVMDILocationGetColumn(LLVMMetadataRef Location); + +/** + * Get the local scope associated with this debug location. + * \param Location The debug location. + * + * @see DILocation::getScope() + */ +LLVMMetadataRef LLVMDILocationGetScope(LLVMMetadataRef Location); + +/** + * Get the "inline at" location associated with this debug location. + * \param Location The debug location. + * + * @see DILocation::getInlinedAt() + */ +LLVMMetadataRef LLVMDILocationGetInlinedAt(LLVMMetadataRef Location); + +/** + * Get the metadata of the file associated with a given scope. + * \param Scope The scope object. + * + * @see DIScope::getFile() + */ +LLVMMetadataRef LLVMDIScopeGetFile(LLVMMetadataRef Scope); + +/** + * Get the directory of a given file. + * \param File The file object. + * \param Len The length of the returned string. + * + * @see DIFile::getDirectory() + */ +const char *LLVMDIFileGetDirectory(LLVMMetadataRef File, unsigned *Len); + +/** + * Get the name of a given file. + * \param File The file object. + * \param Len The length of the returned string. + * + * @see DIFile::getFilename() + */ +const char *LLVMDIFileGetFilename(LLVMMetadataRef File, unsigned *Len); + +/** + * Get the source of a given file. + * \param File The file object. + * \param Len The length of the returned string. + * + * @see DIFile::getSource() + */ +const char *LLVMDIFileGetSource(LLVMMetadataRef File, unsigned *Len); + +/** + * Create a type array. + * \param Builder The DIBuilder. + * \param Data The type elements. + * \param NumElements Number of type elements. + */ +LLVMMetadataRef LLVMDIBuilderGetOrCreateTypeArray(LLVMDIBuilderRef Builder, + LLVMMetadataRef *Data, + size_t NumElements); + +/** + * Create subroutine type. + * \param Builder The DIBuilder. + * \param File The file in which the subroutine resides. + * \param ParameterTypes An array of subroutine parameter types. This + * includes return type at 0th index. + * \param NumParameterTypes The number of parameter types in \c ParameterTypes + * \param Flags E.g.: \c LLVMDIFlagLValueReference. + * These flags are used to emit dwarf attributes. + */ +LLVMMetadataRef +LLVMDIBuilderCreateSubroutineType(LLVMDIBuilderRef Builder, + LLVMMetadataRef File, + LLVMMetadataRef *ParameterTypes, + unsigned NumParameterTypes, + LLVMDIFlags Flags); + +/** + * Create debugging information entry for an enumerator. + * @param Builder The DIBuilder. + * @param Name Enumerator name. + * @param NameLen Length of enumerator name. + * @param Value Enumerator value. + * @param IsUnsigned True if the value is unsigned. + */ +LLVMMetadataRef LLVMDIBuilderCreateEnumerator(LLVMDIBuilderRef Builder, + const char *Name, size_t NameLen, + int64_t Value, + LLVMBool IsUnsigned); + +/** + * Create debugging information entry for an enumeration. + * \param Builder The DIBuilder. + * \param Scope Scope in which this enumeration is defined. + * \param Name Enumeration name. + * \param NameLen Length of enumeration name. + * \param File File where this member is defined. + * \param LineNumber Line number. + * \param SizeInBits Member size. + * \param AlignInBits Member alignment. + * \param Elements Enumeration elements. + * \param NumElements Number of enumeration elements. + * \param ClassTy Underlying type of a C++11/ObjC fixed enum. + */ +LLVMMetadataRef LLVMDIBuilderCreateEnumerationType( + LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, + size_t NameLen, LLVMMetadataRef File, unsigned LineNumber, + uint64_t SizeInBits, uint32_t AlignInBits, LLVMMetadataRef *Elements, + unsigned NumElements, LLVMMetadataRef ClassTy); + +/** + * Create debugging information entry for a union. + * \param Builder The DIBuilder. + * \param Scope Scope in which this union is defined. + * \param Name Union name. + * \param NameLen Length of union name. + * \param File File where this member is defined. + * \param LineNumber Line number. + * \param SizeInBits Member size. + * \param AlignInBits Member alignment. + * \param Flags Flags to encode member attribute, e.g. private + * \param Elements Union elements. + * \param NumElements Number of union elements. + * \param RunTimeLang Optional parameter, Objective-C runtime version. + * \param UniqueId A unique identifier for the union. + * \param UniqueIdLen Length of unique identifier. + */ +LLVMMetadataRef LLVMDIBuilderCreateUnionType( + LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, + size_t NameLen, LLVMMetadataRef File, unsigned LineNumber, + uint64_t SizeInBits, uint32_t AlignInBits, LLVMDIFlags Flags, + LLVMMetadataRef *Elements, unsigned NumElements, unsigned RunTimeLang, + const char *UniqueId, size_t UniqueIdLen); + + +/** + * Create debugging information entry for an array. + * \param Builder The DIBuilder. + * \param Size Array size. + * \param AlignInBits Alignment. + * \param Ty Element type. + * \param Subscripts Subscripts. + * \param NumSubscripts Number of subscripts. + */ +LLVMMetadataRef +LLVMDIBuilderCreateArrayType(LLVMDIBuilderRef Builder, uint64_t Size, + uint32_t AlignInBits, LLVMMetadataRef Ty, + LLVMMetadataRef *Subscripts, + unsigned NumSubscripts); + +/** + * Create debugging information entry for a vector type. + * \param Builder The DIBuilder. + * \param Size Vector size. + * \param AlignInBits Alignment. + * \param Ty Element type. + * \param Subscripts Subscripts. + * \param NumSubscripts Number of subscripts. + */ +LLVMMetadataRef +LLVMDIBuilderCreateVectorType(LLVMDIBuilderRef Builder, uint64_t Size, + uint32_t AlignInBits, LLVMMetadataRef Ty, + LLVMMetadataRef *Subscripts, + unsigned NumSubscripts); + +/** + * Create a DWARF unspecified type. + * \param Builder The DIBuilder. + * \param Name The unspecified type's name. + * \param NameLen Length of type name. + */ +LLVMMetadataRef +LLVMDIBuilderCreateUnspecifiedType(LLVMDIBuilderRef Builder, const char *Name, + size_t NameLen); + +/** + * Create debugging information entry for a basic + * type. + * \param Builder The DIBuilder. + * \param Name Type name. + * \param NameLen Length of type name. + * \param SizeInBits Size of the type. + * \param Encoding DWARF encoding code, e.g. \c LLVMDWARFTypeEncoding_float. + * \param Flags Flags to encode optional attribute like endianity + */ +LLVMMetadataRef +LLVMDIBuilderCreateBasicType(LLVMDIBuilderRef Builder, const char *Name, + size_t NameLen, uint64_t SizeInBits, + LLVMDWARFTypeEncoding Encoding, + LLVMDIFlags Flags); + +/** + * Create debugging information entry for a pointer. + * \param Builder The DIBuilder. + * \param PointeeTy Type pointed by this pointer. + * \param SizeInBits Size. + * \param AlignInBits Alignment. (optional, pass 0 to ignore) + * \param AddressSpace DWARF address space. (optional, pass 0 to ignore) + * \param Name Pointer type name. (optional) + * \param NameLen Length of pointer type name. (optional) + */ +LLVMMetadataRef LLVMDIBuilderCreatePointerType( + LLVMDIBuilderRef Builder, LLVMMetadataRef PointeeTy, + uint64_t SizeInBits, uint32_t AlignInBits, unsigned AddressSpace, + const char *Name, size_t NameLen); + +/** + * Create debugging information entry for a struct. + * \param Builder The DIBuilder. + * \param Scope Scope in which this struct is defined. + * \param Name Struct name. + * \param NameLen Struct name length. + * \param File File where this member is defined. + * \param LineNumber Line number. + * \param SizeInBits Member size. + * \param AlignInBits Member alignment. + * \param Flags Flags to encode member attribute, e.g. private + * \param Elements Struct elements. + * \param NumElements Number of struct elements. + * \param RunTimeLang Optional parameter, Objective-C runtime version. + * \param VTableHolder The object containing the vtable for the struct. + * \param UniqueId A unique identifier for the struct. + * \param UniqueIdLen Length of the unique identifier for the struct. + */ +LLVMMetadataRef LLVMDIBuilderCreateStructType( + LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, + size_t NameLen, LLVMMetadataRef File, unsigned LineNumber, + uint64_t SizeInBits, uint32_t AlignInBits, LLVMDIFlags Flags, + LLVMMetadataRef DerivedFrom, LLVMMetadataRef *Elements, + unsigned NumElements, unsigned RunTimeLang, LLVMMetadataRef VTableHolder, + const char *UniqueId, size_t UniqueIdLen); + +/** + * Create debugging information entry for a member. + * \param Builder The DIBuilder. + * \param Scope Member scope. + * \param Name Member name. + * \param NameLen Length of member name. + * \param File File where this member is defined. + * \param LineNo Line number. + * \param SizeInBits Member size. + * \param AlignInBits Member alignment. + * \param OffsetInBits Member offset. + * \param Flags Flags to encode member attribute, e.g. private + * \param Ty Parent type. + */ +LLVMMetadataRef LLVMDIBuilderCreateMemberType( + LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, + size_t NameLen, LLVMMetadataRef File, unsigned LineNo, + uint64_t SizeInBits, uint32_t AlignInBits, uint64_t OffsetInBits, + LLVMDIFlags Flags, LLVMMetadataRef Ty); + +/** + * Create debugging information entry for a + * C++ static data member. + * \param Builder The DIBuilder. + * \param Scope Member scope. + * \param Name Member name. + * \param NameLen Length of member name. + * \param File File where this member is declared. + * \param LineNumber Line number. + * \param Type Type of the static member. + * \param Flags Flags to encode member attribute, e.g. private. + * \param ConstantVal Const initializer of the member. + * \param AlignInBits Member alignment. + */ +LLVMMetadataRef +LLVMDIBuilderCreateStaticMemberType( + LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, + size_t NameLen, LLVMMetadataRef File, unsigned LineNumber, + LLVMMetadataRef Type, LLVMDIFlags Flags, LLVMValueRef ConstantVal, + uint32_t AlignInBits); + +/** + * Create debugging information entry for a pointer to member. + * \param Builder The DIBuilder. + * \param PointeeType Type pointed to by this pointer. + * \param ClassType Type for which this pointer points to members of. + * \param SizeInBits Size. + * \param AlignInBits Alignment. + * \param Flags Flags. + */ +LLVMMetadataRef +LLVMDIBuilderCreateMemberPointerType(LLVMDIBuilderRef Builder, + LLVMMetadataRef PointeeType, + LLVMMetadataRef ClassType, + uint64_t SizeInBits, + uint32_t AlignInBits, + LLVMDIFlags Flags); +/** + * Create debugging information entry for Objective-C instance variable. + * \param Builder The DIBuilder. + * \param Name Member name. + * \param NameLen The length of the C string passed to \c Name. + * \param File File where this member is defined. + * \param LineNo Line number. + * \param SizeInBits Member size. + * \param AlignInBits Member alignment. + * \param OffsetInBits Member offset. + * \param Flags Flags to encode member attribute, e.g. private + * \param Ty Parent type. + * \param PropertyNode Property associated with this ivar. + */ +LLVMMetadataRef +LLVMDIBuilderCreateObjCIVar(LLVMDIBuilderRef Builder, + const char *Name, size_t NameLen, + LLVMMetadataRef File, unsigned LineNo, + uint64_t SizeInBits, uint32_t AlignInBits, + uint64_t OffsetInBits, LLVMDIFlags Flags, + LLVMMetadataRef Ty, LLVMMetadataRef PropertyNode); + +/** + * Create debugging information entry for Objective-C property. + * \param Builder The DIBuilder. + * \param Name Property name. + * \param NameLen The length of the C string passed to \c Name. + * \param File File where this property is defined. + * \param LineNo Line number. + * \param GetterName Name of the Objective C property getter selector. + * \param GetterNameLen The length of the C string passed to \c GetterName. + * \param SetterName Name of the Objective C property setter selector. + * \param SetterNameLen The length of the C string passed to \c SetterName. + * \param PropertyAttributes Objective C property attributes. + * \param Ty Type. + */ +LLVMMetadataRef +LLVMDIBuilderCreateObjCProperty(LLVMDIBuilderRef Builder, + const char *Name, size_t NameLen, + LLVMMetadataRef File, unsigned LineNo, + const char *GetterName, size_t GetterNameLen, + const char *SetterName, size_t SetterNameLen, + unsigned PropertyAttributes, + LLVMMetadataRef Ty); + +/** + * Create a uniqued DIType* clone with FlagObjectPointer and FlagArtificial set. + * \param Builder The DIBuilder. + * \param Type The underlying type to which this pointer points. + */ +LLVMMetadataRef +LLVMDIBuilderCreateObjectPointerType(LLVMDIBuilderRef Builder, + LLVMMetadataRef Type); + +/** + * Create debugging information entry for a qualified + * type, e.g. 'const int'. + * \param Builder The DIBuilder. + * \param Tag Tag identifying type, + * e.g. LLVMDWARFTypeQualifier_volatile_type + * \param Type Base Type. + */ +LLVMMetadataRef +LLVMDIBuilderCreateQualifiedType(LLVMDIBuilderRef Builder, unsigned Tag, + LLVMMetadataRef Type); + +/** + * Create debugging information entry for a c++ + * style reference or rvalue reference type. + * \param Builder The DIBuilder. + * \param Tag Tag identifying type, + * \param Type Base Type. + */ +LLVMMetadataRef +LLVMDIBuilderCreateReferenceType(LLVMDIBuilderRef Builder, unsigned Tag, + LLVMMetadataRef Type); + +/** + * Create C++11 nullptr type. + * \param Builder The DIBuilder. + */ +LLVMMetadataRef +LLVMDIBuilderCreateNullPtrType(LLVMDIBuilderRef Builder); + +/** + * Create debugging information entry for a typedef. + * \param Builder The DIBuilder. + * \param Type Original type. + * \param Name Typedef name. + * \param File File where this type is defined. + * \param LineNo Line number. + * \param Scope The surrounding context for the typedef. + */ +LLVMMetadataRef +LLVMDIBuilderCreateTypedef(LLVMDIBuilderRef Builder, LLVMMetadataRef Type, + const char *Name, size_t NameLen, + LLVMMetadataRef File, unsigned LineNo, + LLVMMetadataRef Scope); + +/** + * Create debugging information entry to establish inheritance relationship + * between two types. + * \param Builder The DIBuilder. + * \param Ty Original type. + * \param BaseTy Base type. Ty is inherits from base. + * \param BaseOffset Base offset. + * \param VBPtrOffset Virtual base pointer offset. + * \param Flags Flags to describe inheritance attribute, e.g. private + */ +LLVMMetadataRef +LLVMDIBuilderCreateInheritance(LLVMDIBuilderRef Builder, + LLVMMetadataRef Ty, LLVMMetadataRef BaseTy, + uint64_t BaseOffset, uint32_t VBPtrOffset, + LLVMDIFlags Flags); + +/** + * Create a permanent forward-declared type. + * \param Builder The DIBuilder. + * \param Tag A unique tag for this type. + * \param Name Type name. + * \param NameLen Length of type name. + * \param Scope Type scope. + * \param File File where this type is defined. + * \param Line Line number where this type is defined. + * \param RuntimeLang Indicates runtime version for languages like + * Objective-C. + * \param SizeInBits Member size. + * \param AlignInBits Member alignment. + * \param UniqueIdentifier A unique identifier for the type. + * \param UniqueIdentifierLen Length of the unique identifier. + */ +LLVMMetadataRef LLVMDIBuilderCreateForwardDecl( + LLVMDIBuilderRef Builder, unsigned Tag, const char *Name, + size_t NameLen, LLVMMetadataRef Scope, LLVMMetadataRef File, unsigned Line, + unsigned RuntimeLang, uint64_t SizeInBits, uint32_t AlignInBits, + const char *UniqueIdentifier, size_t UniqueIdentifierLen); + +/** + * Create a temporary forward-declared type. + * \param Builder The DIBuilder. + * \param Tag A unique tag for this type. + * \param Name Type name. + * \param NameLen Length of type name. + * \param Scope Type scope. + * \param File File where this type is defined. + * \param Line Line number where this type is defined. + * \param RuntimeLang Indicates runtime version for languages like + * Objective-C. + * \param SizeInBits Member size. + * \param AlignInBits Member alignment. + * \param Flags Flags. + * \param UniqueIdentifier A unique identifier for the type. + * \param UniqueIdentifierLen Length of the unique identifier. + */ +LLVMMetadataRef +LLVMDIBuilderCreateReplaceableCompositeType( + LLVMDIBuilderRef Builder, unsigned Tag, const char *Name, + size_t NameLen, LLVMMetadataRef Scope, LLVMMetadataRef File, unsigned Line, + unsigned RuntimeLang, uint64_t SizeInBits, uint32_t AlignInBits, + LLVMDIFlags Flags, const char *UniqueIdentifier, + size_t UniqueIdentifierLen); + +/** + * Create debugging information entry for a bit field member. + * \param Builder The DIBuilder. + * \param Scope Member scope. + * \param Name Member name. + * \param NameLen Length of member name. + * \param File File where this member is defined. + * \param LineNumber Line number. + * \param SizeInBits Member size. + * \param OffsetInBits Member offset. + * \param StorageOffsetInBits Member storage offset. + * \param Flags Flags to encode member attribute. + * \param Type Parent type. + */ +LLVMMetadataRef +LLVMDIBuilderCreateBitFieldMemberType(LLVMDIBuilderRef Builder, + LLVMMetadataRef Scope, + const char *Name, size_t NameLen, + LLVMMetadataRef File, unsigned LineNumber, + uint64_t SizeInBits, + uint64_t OffsetInBits, + uint64_t StorageOffsetInBits, + LLVMDIFlags Flags, LLVMMetadataRef Type); + +/** + * Create debugging information entry for a class. + * \param Scope Scope in which this class is defined. + * \param Name Class name. + * \param NameLen The length of the C string passed to \c Name. + * \param File File where this member is defined. + * \param LineNumber Line number. + * \param SizeInBits Member size. + * \param AlignInBits Member alignment. + * \param OffsetInBits Member offset. + * \param Flags Flags to encode member attribute, e.g. private. + * \param DerivedFrom Debug info of the base class of this type. + * \param Elements Class members. + * \param NumElements Number of class elements. + * \param VTableHolder Debug info of the base class that contains vtable + * for this type. This is used in + * DW_AT_containing_type. See DWARF documentation + * for more info. + * \param TemplateParamsNode Template type parameters. + * \param UniqueIdentifier A unique identifier for the type. + * \param UniqueIdentifierLen Length of the unique identifier. + */ +LLVMMetadataRef LLVMDIBuilderCreateClassType(LLVMDIBuilderRef Builder, + LLVMMetadataRef Scope, const char *Name, size_t NameLen, + LLVMMetadataRef File, unsigned LineNumber, uint64_t SizeInBits, + uint32_t AlignInBits, uint64_t OffsetInBits, LLVMDIFlags Flags, + LLVMMetadataRef DerivedFrom, + LLVMMetadataRef *Elements, unsigned NumElements, + LLVMMetadataRef VTableHolder, LLVMMetadataRef TemplateParamsNode, + const char *UniqueIdentifier, size_t UniqueIdentifierLen); + +/** + * Create a uniqued DIType* clone with FlagArtificial set. + * \param Builder The DIBuilder. + * \param Type The underlying type. + */ +LLVMMetadataRef +LLVMDIBuilderCreateArtificialType(LLVMDIBuilderRef Builder, + LLVMMetadataRef Type); + +/** + * Get the name of this DIType. + * \param DType The DIType. + * \param Length The length of the returned string. + * + * @see DIType::getName() + */ +const char *LLVMDITypeGetName(LLVMMetadataRef DType, size_t *Length); + +/** + * Get the size of this DIType in bits. + * \param DType The DIType. + * + * @see DIType::getSizeInBits() + */ +uint64_t LLVMDITypeGetSizeInBits(LLVMMetadataRef DType); + +/** + * Get the offset of this DIType in bits. + * \param DType The DIType. + * + * @see DIType::getOffsetInBits() + */ +uint64_t LLVMDITypeGetOffsetInBits(LLVMMetadataRef DType); + +/** + * Get the alignment of this DIType in bits. + * \param DType The DIType. + * + * @see DIType::getAlignInBits() + */ +uint32_t LLVMDITypeGetAlignInBits(LLVMMetadataRef DType); + +/** + * Get the source line where this DIType is declared. + * \param DType The DIType. + * + * @see DIType::getLine() + */ +unsigned LLVMDITypeGetLine(LLVMMetadataRef DType); + +/** + * Get the flags associated with this DIType. + * \param DType The DIType. + * + * @see DIType::getFlags() + */ +LLVMDIFlags LLVMDITypeGetFlags(LLVMMetadataRef DType); + +/** + * Create a descriptor for a value range. + * \param Builder The DIBuilder. + * \param LowerBound Lower bound of the subrange, e.g. 0 for C, 1 for Fortran. + * \param Count Count of elements in the subrange. + */ +LLVMMetadataRef LLVMDIBuilderGetOrCreateSubrange(LLVMDIBuilderRef Builder, + int64_t LowerBound, + int64_t Count); + +/** + * Create an array of DI Nodes. + * \param Builder The DIBuilder. + * \param Data The DI Node elements. + * \param NumElements Number of DI Node elements. + */ +LLVMMetadataRef LLVMDIBuilderGetOrCreateArray(LLVMDIBuilderRef Builder, + LLVMMetadataRef *Data, + size_t NumElements); + +/** + * Create a new descriptor for the specified variable which has a complex + * address expression for its address. + * \param Builder The DIBuilder. + * \param Addr An array of complex address operations. + * \param Length Length of the address operation array. + */ +LLVMMetadataRef LLVMDIBuilderCreateExpression(LLVMDIBuilderRef Builder, + int64_t *Addr, size_t Length); + +/** + * Create a new descriptor for the specified variable that does not have an + * address, but does have a constant value. + * \param Builder The DIBuilder. + * \param Value The constant value. + */ +LLVMMetadataRef +LLVMDIBuilderCreateConstantValueExpression(LLVMDIBuilderRef Builder, + int64_t Value); + +/** + * Create a new descriptor for the specified variable. + * \param Scope Variable scope. + * \param Name Name of the variable. + * \param NameLen The length of the C string passed to \c Name. + * \param Linkage Mangled name of the variable. + * \param LinkLen The length of the C string passed to \c Linkage. + * \param File File where this variable is defined. + * \param LineNo Line number. + * \param Ty Variable Type. + * \param LocalToUnit Boolean flag indicate whether this variable is + * externally visible or not. + * \param Expr The location of the global relative to the attached + * GlobalVariable. + * \param Decl Reference to the corresponding declaration. + * variables. + * \param AlignInBits Variable alignment(or 0 if no alignment attr was + * specified) + */ +LLVMMetadataRef LLVMDIBuilderCreateGlobalVariableExpression( + LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, + size_t NameLen, const char *Linkage, size_t LinkLen, LLVMMetadataRef File, + unsigned LineNo, LLVMMetadataRef Ty, LLVMBool LocalToUnit, + LLVMMetadataRef Expr, LLVMMetadataRef Decl, uint32_t AlignInBits); + +/** + * Retrieves the \c DIVariable associated with this global variable expression. + * \param GVE The global variable expression. + * + * @see llvm::DIGlobalVariableExpression::getVariable() + */ +LLVMMetadataRef LLVMDIGlobalVariableExpressionGetVariable(LLVMMetadataRef GVE); + +/** + * Retrieves the \c DIExpression associated with this global variable expression. + * \param GVE The global variable expression. + * + * @see llvm::DIGlobalVariableExpression::getExpression() + */ +LLVMMetadataRef LLVMDIGlobalVariableExpressionGetExpression( + LLVMMetadataRef GVE); + +/** + * Get the metadata of the file associated with a given variable. + * \param Var The variable object. + * + * @see DIVariable::getFile() + */ +LLVMMetadataRef LLVMDIVariableGetFile(LLVMMetadataRef Var); + +/** + * Get the metadata of the scope associated with a given variable. + * \param Var The variable object. + * + * @see DIVariable::getScope() + */ +LLVMMetadataRef LLVMDIVariableGetScope(LLVMMetadataRef Var); + +/** + * Get the source line where this \c DIVariable is declared. + * \param Var The DIVariable. + * + * @see DIVariable::getLine() + */ +unsigned LLVMDIVariableGetLine(LLVMMetadataRef Var); + +/** + * Create a new temporary \c MDNode. Suitable for use in constructing cyclic + * \c MDNode structures. A temporary \c MDNode is not uniqued, may be RAUW'd, + * and must be manually deleted with \c LLVMDisposeTemporaryMDNode. + * \param Ctx The context in which to construct the temporary node. + * \param Data The metadata elements. + * \param NumElements Number of metadata elements. + */ +LLVMMetadataRef LLVMTemporaryMDNode(LLVMContextRef Ctx, LLVMMetadataRef *Data, + size_t NumElements); + +/** + * Deallocate a temporary node. + * + * Calls \c replaceAllUsesWith(nullptr) before deleting, so any remaining + * references will be reset. + * \param TempNode The temporary metadata node. + */ +void LLVMDisposeTemporaryMDNode(LLVMMetadataRef TempNode); + +/** + * Replace all uses of temporary metadata. + * \param TempTargetMetadata The temporary metadata node. + * \param Replacement The replacement metadata node. + */ +void LLVMMetadataReplaceAllUsesWith(LLVMMetadataRef TempTargetMetadata, + LLVMMetadataRef Replacement); + +/** + * Create a new descriptor for the specified global variable that is temporary + * and meant to be RAUWed. + * \param Scope Variable scope. + * \param Name Name of the variable. + * \param NameLen The length of the C string passed to \c Name. + * \param Linkage Mangled name of the variable. + * \param LnkLen The length of the C string passed to \c Linkage. + * \param File File where this variable is defined. + * \param LineNo Line number. + * \param Ty Variable Type. + * \param LocalToUnit Boolean flag indicate whether this variable is + * externally visible or not. + * \param Decl Reference to the corresponding declaration. + * \param AlignInBits Variable alignment(or 0 if no alignment attr was + * specified) + */ +LLVMMetadataRef LLVMDIBuilderCreateTempGlobalVariableFwdDecl( + LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, + size_t NameLen, const char *Linkage, size_t LnkLen, LLVMMetadataRef File, + unsigned LineNo, LLVMMetadataRef Ty, LLVMBool LocalToUnit, + LLVMMetadataRef Decl, uint32_t AlignInBits); + +/** + * Insert a new llvm.dbg.declare intrinsic call before the given instruction. + * \param Builder The DIBuilder. + * \param Storage The storage of the variable to declare. + * \param VarInfo The variable's debug info descriptor. + * \param Expr A complex location expression for the variable. + * \param DebugLoc Debug info location. + * \param Instr Instruction acting as a location for the new intrinsic. + */ +LLVMValueRef LLVMDIBuilderInsertDeclareBefore( + LLVMDIBuilderRef Builder, LLVMValueRef Storage, LLVMMetadataRef VarInfo, + LLVMMetadataRef Expr, LLVMMetadataRef DebugLoc, LLVMValueRef Instr); + +/** + * Insert a new llvm.dbg.declare intrinsic call at the end of the given basic + * block. If the basic block has a terminator instruction, the intrinsic is + * inserted before that terminator instruction. + * \param Builder The DIBuilder. + * \param Storage The storage of the variable to declare. + * \param VarInfo The variable's debug info descriptor. + * \param Expr A complex location expression for the variable. + * \param DebugLoc Debug info location. + * \param Block Basic block acting as a location for the new intrinsic. + */ +LLVMValueRef LLVMDIBuilderInsertDeclareAtEnd( + LLVMDIBuilderRef Builder, LLVMValueRef Storage, LLVMMetadataRef VarInfo, + LLVMMetadataRef Expr, LLVMMetadataRef DebugLoc, LLVMBasicBlockRef Block); + +/** + * Insert a new llvm.dbg.value intrinsic call before the given instruction. + * \param Builder The DIBuilder. + * \param Val The value of the variable. + * \param VarInfo The variable's debug info descriptor. + * \param Expr A complex location expression for the variable. + * \param DebugLoc Debug info location. + * \param Instr Instruction acting as a location for the new intrinsic. + */ +LLVMValueRef LLVMDIBuilderInsertDbgValueBefore(LLVMDIBuilderRef Builder, + LLVMValueRef Val, + LLVMMetadataRef VarInfo, + LLVMMetadataRef Expr, + LLVMMetadataRef DebugLoc, + LLVMValueRef Instr); + +/** + * Insert a new llvm.dbg.value intrinsic call at the end of the given basic + * block. If the basic block has a terminator instruction, the intrinsic is + * inserted before that terminator instruction. + * \param Builder The DIBuilder. + * \param Val The value of the variable. + * \param VarInfo The variable's debug info descriptor. + * \param Expr A complex location expression for the variable. + * \param DebugLoc Debug info location. + * \param Block Basic block acting as a location for the new intrinsic. + */ +LLVMValueRef LLVMDIBuilderInsertDbgValueAtEnd(LLVMDIBuilderRef Builder, + LLVMValueRef Val, + LLVMMetadataRef VarInfo, + LLVMMetadataRef Expr, + LLVMMetadataRef DebugLoc, + LLVMBasicBlockRef Block); + +/** + * Create a new descriptor for a local auto variable. + * \param Builder The DIBuilder. + * \param Scope The local scope the variable is declared in. + * \param Name Variable name. + * \param NameLen Length of variable name. + * \param File File where this variable is defined. + * \param LineNo Line number. + * \param Ty Metadata describing the type of the variable. + * \param AlwaysPreserve If true, this descriptor will survive optimizations. + * \param Flags Flags. + * \param AlignInBits Variable alignment. + */ +LLVMMetadataRef LLVMDIBuilderCreateAutoVariable( + LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, + size_t NameLen, LLVMMetadataRef File, unsigned LineNo, LLVMMetadataRef Ty, + LLVMBool AlwaysPreserve, LLVMDIFlags Flags, uint32_t AlignInBits); + +/** + * Create a new descriptor for a function parameter variable. + * \param Builder The DIBuilder. + * \param Scope The local scope the variable is declared in. + * \param Name Variable name. + * \param NameLen Length of variable name. + * \param ArgNo Unique argument number for this variable; starts at 1. + * \param File File where this variable is defined. + * \param LineNo Line number. + * \param Ty Metadata describing the type of the variable. + * \param AlwaysPreserve If true, this descriptor will survive optimizations. + * \param Flags Flags. + */ +LLVMMetadataRef LLVMDIBuilderCreateParameterVariable( + LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, + size_t NameLen, unsigned ArgNo, LLVMMetadataRef File, unsigned LineNo, + LLVMMetadataRef Ty, LLVMBool AlwaysPreserve, LLVMDIFlags Flags); + +/** + * Get the metadata of the subprogram attached to a function. + * + * @see llvm::Function::getSubprogram() + */ +LLVMMetadataRef LLVMGetSubprogram(LLVMValueRef Func); + +/** + * Set the subprogram attached to a function. + * + * @see llvm::Function::setSubprogram() + */ +void LLVMSetSubprogram(LLVMValueRef Func, LLVMMetadataRef SP); + +/** + * Get the line associated with a given subprogram. + * \param Subprogram The subprogram object. + * + * @see DISubprogram::getLine() + */ +unsigned LLVMDISubprogramGetLine(LLVMMetadataRef Subprogram); + +/** + * Get the debug location for the given instruction. + * + * @see llvm::Instruction::getDebugLoc() + */ +LLVMMetadataRef LLVMInstructionGetDebugLoc(LLVMValueRef Inst); + +/** + * Set the debug location for the given instruction. + * + * To clear the location metadata of the given instruction, pass NULL to \p Loc. + * + * @see llvm::Instruction::setDebugLoc() + */ +void LLVMInstructionSetDebugLoc(LLVMValueRef Inst, LLVMMetadataRef Loc); + +/** + * Obtain the enumerated type of a Metadata instance. + * + * @see llvm::Metadata::getMetadataID() + */ +LLVMMetadataKind LLVMGetMetadataKind(LLVMMetadataRef Metadata); + +#ifdef __cplusplus +} /* end extern "C" */ +#endif + +#endif diff --git a/src/llvm-c/Disassembler.h b/src/llvm-c/Disassembler.h new file mode 100644 index 000000000..3adcc3c47 --- /dev/null +++ b/src/llvm-c/Disassembler.h @@ -0,0 +1,113 @@ +/*===-- llvm-c/Disassembler.h - Disassembler Public C Interface ---*- C -*-===*\ +|* *| +|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *| +|* Exceptions. *| +|* See https://llvm.org/LICENSE.txt for license information. *| +|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This header provides a public interface to a disassembler library. *| +|* LLVM provides an implementation of this interface. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_C_DISASSEMBLER_H +#define LLVM_C_DISASSEMBLER_H + +#include "llvm-c/DisassemblerTypes.h" + +/** + * @defgroup LLVMCDisassembler Disassembler + * @ingroup LLVMC + * + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif /* !defined(__cplusplus) */ + +/** + * Create a disassembler for the TripleName. Symbolic disassembly is supported + * by passing a block of information in the DisInfo parameter and specifying the + * TagType and callback functions as described above. These can all be passed + * as NULL. If successful, this returns a disassembler context. If not, it + * returns NULL. This function is equivalent to calling + * LLVMCreateDisasmCPUFeatures() with an empty CPU name and feature set. + */ +LLVMDisasmContextRef LLVMCreateDisasm(const char *TripleName, void *DisInfo, + int TagType, LLVMOpInfoCallback GetOpInfo, + LLVMSymbolLookupCallback SymbolLookUp); + +/** + * Create a disassembler for the TripleName and a specific CPU. Symbolic + * disassembly is supported by passing a block of information in the DisInfo + * parameter and specifying the TagType and callback functions as described + * above. These can all be passed * as NULL. If successful, this returns a + * disassembler context. If not, it returns NULL. This function is equivalent + * to calling LLVMCreateDisasmCPUFeatures() with an empty feature set. + */ +LLVMDisasmContextRef LLVMCreateDisasmCPU(const char *Triple, const char *CPU, + void *DisInfo, int TagType, + LLVMOpInfoCallback GetOpInfo, + LLVMSymbolLookupCallback SymbolLookUp); + +/** + * Create a disassembler for the TripleName, a specific CPU and specific feature + * string. Symbolic disassembly is supported by passing a block of information + * in the DisInfo parameter and specifying the TagType and callback functions as + * described above. These can all be passed * as NULL. If successful, this + * returns a disassembler context. If not, it returns NULL. + */ +LLVMDisasmContextRef +LLVMCreateDisasmCPUFeatures(const char *Triple, const char *CPU, + const char *Features, void *DisInfo, int TagType, + LLVMOpInfoCallback GetOpInfo, + LLVMSymbolLookupCallback SymbolLookUp); + +/** + * Set the disassembler's options. Returns 1 if it can set the Options and 0 + * otherwise. + */ +int LLVMSetDisasmOptions(LLVMDisasmContextRef DC, uint64_t Options); + +/* The option to produce marked up assembly. */ +#define LLVMDisassembler_Option_UseMarkup 1 +/* The option to print immediates as hex. */ +#define LLVMDisassembler_Option_PrintImmHex 2 +/* The option use the other assembler printer variant */ +#define LLVMDisassembler_Option_AsmPrinterVariant 4 +/* The option to set comment on instructions */ +#define LLVMDisassembler_Option_SetInstrComments 8 + /* The option to print latency information alongside instructions */ +#define LLVMDisassembler_Option_PrintLatency 16 + +/** + * Dispose of a disassembler context. + */ +void LLVMDisasmDispose(LLVMDisasmContextRef DC); + +/** + * Disassemble a single instruction using the disassembler context specified in + * the parameter DC. The bytes of the instruction are specified in the + * parameter Bytes, and contains at least BytesSize number of bytes. The + * instruction is at the address specified by the PC parameter. If a valid + * instruction can be disassembled, its string is returned indirectly in + * OutString whose size is specified in the parameter OutStringSize. This + * function returns the number of bytes in the instruction or zero if there was + * no valid instruction. + */ +size_t LLVMDisasmInstruction(LLVMDisasmContextRef DC, uint8_t *Bytes, + uint64_t BytesSize, uint64_t PC, + char *OutString, size_t OutStringSize); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* !defined(__cplusplus) */ + +#endif /* LLVM_C_DISASSEMBLER_H */ diff --git a/src/llvm-c/DisassemblerTypes.h b/src/llvm-c/DisassemblerTypes.h new file mode 100644 index 000000000..389e5ee45 --- /dev/null +++ b/src/llvm-c/DisassemblerTypes.h @@ -0,0 +1,160 @@ +/*===-- llvm-c/DisassemblerTypedefs.h -----------------------------*- C -*-===*\ +|* *| +|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *| +|* Exceptions. *| +|* See https://llvm.org/LICENSE.txt for license information. *| +|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *| +|* *| +|*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_DISASSEMBLER_TYPES_H +#define LLVM_DISASSEMBLER_TYPES_H + +#include "llvm-c/DataTypes.h" +#ifdef __cplusplus +#include +#else +#include +#endif + +/** + * An opaque reference to a disassembler context. + */ +typedef void *LLVMDisasmContextRef; + +/** + * The type for the operand information call back function. This is called to + * get the symbolic information for an operand of an instruction. Typically + * this is from the relocation information, symbol table, etc. That block of + * information is saved when the disassembler context is created and passed to + * the call back in the DisInfo parameter. The instruction containing operand + * is at the PC parameter. For some instruction sets, there can be more than + * one operand with symbolic information. To determine the symbolic operand + * information for each operand, the bytes for the specific operand in the + * instruction are specified by the Offset parameter and its byte widith is the + * size parameter. For instructions sets with fixed widths and one symbolic + * operand per instruction, the Offset parameter will be zero and Size parameter + * will be the instruction width. The information is returned in TagBuf and is + * Triple specific with its specific information defined by the value of + * TagType for that Triple. If symbolic information is returned the function + * returns 1, otherwise it returns 0. + */ +typedef int (*LLVMOpInfoCallback)(void *DisInfo, uint64_t PC, + uint64_t Offset, uint64_t Size, + int TagType, void *TagBuf); + +/** + * The initial support in LLVM MC for the most general form of a relocatable + * expression is "AddSymbol - SubtractSymbol + Offset". For some Darwin targets + * this full form is encoded in the relocation information so that AddSymbol and + * SubtractSymbol can be link edited independent of each other. Many other + * platforms only allow a relocatable expression of the form AddSymbol + Offset + * to be encoded. + * + * The LLVMOpInfoCallback() for the TagType value of 1 uses the struct + * LLVMOpInfo1. The value of the relocatable expression for the operand, + * including any PC adjustment, is passed in to the call back in the Value + * field. The symbolic information about the operand is returned using all + * the fields of the structure with the Offset of the relocatable expression + * returned in the Value field. It is possible that some symbols in the + * relocatable expression were assembly temporary symbols, for example + * "Ldata - LpicBase + constant", and only the Values of the symbols without + * symbol names are present in the relocation information. The VariantKind + * type is one of the Target specific #defines below and is used to print + * operands like "_foo@GOT", ":lower16:_foo", etc. + */ +struct LLVMOpInfoSymbol1 { + uint64_t Present; /* 1 if this symbol is present */ + const char *Name; /* symbol name if not NULL */ + uint64_t Value; /* symbol value if name is NULL */ +}; + +struct LLVMOpInfo1 { + struct LLVMOpInfoSymbol1 AddSymbol; + struct LLVMOpInfoSymbol1 SubtractSymbol; + uint64_t Value; + uint64_t VariantKind; +}; + +/** + * The operand VariantKinds for symbolic disassembly. + */ +#define LLVMDisassembler_VariantKind_None 0 /* all targets */ + +/** + * The ARM target VariantKinds. + */ +#define LLVMDisassembler_VariantKind_ARM_HI16 1 /* :upper16: */ +#define LLVMDisassembler_VariantKind_ARM_LO16 2 /* :lower16: */ + +/** + * The ARM64 target VariantKinds. + */ +#define LLVMDisassembler_VariantKind_ARM64_PAGE 1 /* @page */ +#define LLVMDisassembler_VariantKind_ARM64_PAGEOFF 2 /* @pageoff */ +#define LLVMDisassembler_VariantKind_ARM64_GOTPAGE 3 /* @gotpage */ +#define LLVMDisassembler_VariantKind_ARM64_GOTPAGEOFF 4 /* @gotpageoff */ +#define LLVMDisassembler_VariantKind_ARM64_TLVP 5 /* @tvlppage */ +#define LLVMDisassembler_VariantKind_ARM64_TLVOFF 6 /* @tvlppageoff */ + +/** + * The type for the symbol lookup function. This may be called by the + * disassembler for things like adding a comment for a PC plus a constant + * offset load instruction to use a symbol name instead of a load address value. + * It is passed the block information is saved when the disassembler context is + * created and the ReferenceValue to look up as a symbol. If no symbol is found + * for the ReferenceValue NULL is returned. The ReferenceType of the + * instruction is passed indirectly as is the PC of the instruction in + * ReferencePC. If the output reference can be determined its type is returned + * indirectly in ReferenceType along with ReferenceName if any, or that is set + * to NULL. + */ +typedef const char *(*LLVMSymbolLookupCallback)(void *DisInfo, + uint64_t ReferenceValue, + uint64_t *ReferenceType, + uint64_t ReferencePC, + const char **ReferenceName); +/** + * The reference types on input and output. + */ +/* No input reference type or no output reference type. */ +#define LLVMDisassembler_ReferenceType_InOut_None 0 + +/* The input reference is from a branch instruction. */ +#define LLVMDisassembler_ReferenceType_In_Branch 1 +/* The input reference is from a PC relative load instruction. */ +#define LLVMDisassembler_ReferenceType_In_PCrel_Load 2 + +/* The input reference is from an ARM64::ADRP instruction. */ +#define LLVMDisassembler_ReferenceType_In_ARM64_ADRP 0x100000001 +/* The input reference is from an ARM64::ADDXri instruction. */ +#define LLVMDisassembler_ReferenceType_In_ARM64_ADDXri 0x100000002 +/* The input reference is from an ARM64::LDRXui instruction. */ +#define LLVMDisassembler_ReferenceType_In_ARM64_LDRXui 0x100000003 +/* The input reference is from an ARM64::LDRXl instruction. */ +#define LLVMDisassembler_ReferenceType_In_ARM64_LDRXl 0x100000004 +/* The input reference is from an ARM64::ADR instruction. */ +#define LLVMDisassembler_ReferenceType_In_ARM64_ADR 0x100000005 + +/* The output reference is to as symbol stub. */ +#define LLVMDisassembler_ReferenceType_Out_SymbolStub 1 +/* The output reference is to a symbol address in a literal pool. */ +#define LLVMDisassembler_ReferenceType_Out_LitPool_SymAddr 2 +/* The output reference is to a cstring address in a literal pool. */ +#define LLVMDisassembler_ReferenceType_Out_LitPool_CstrAddr 3 + +/* The output reference is to a Objective-C CoreFoundation string. */ +#define LLVMDisassembler_ReferenceType_Out_Objc_CFString_Ref 4 +/* The output reference is to a Objective-C message. */ +#define LLVMDisassembler_ReferenceType_Out_Objc_Message 5 +/* The output reference is to a Objective-C message ref. */ +#define LLVMDisassembler_ReferenceType_Out_Objc_Message_Ref 6 +/* The output reference is to a Objective-C selector ref. */ +#define LLVMDisassembler_ReferenceType_Out_Objc_Selector_Ref 7 +/* The output reference is to a Objective-C class ref. */ +#define LLVMDisassembler_ReferenceType_Out_Objc_Class_Ref 8 + +/* The output reference is to a C++ symbol name. */ +#define LLVMDisassembler_ReferenceType_DeMangled_Name 9 + +#endif diff --git a/src/llvm-c/Error.h b/src/llvm-c/Error.h new file mode 100644 index 000000000..52943063c --- /dev/null +++ b/src/llvm-c/Error.h @@ -0,0 +1,69 @@ +/*===------- llvm-c/Error.h - llvm::Error class C Interface -------*- C -*-===*\ +|* *| +|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *| +|* Exceptions. *| +|* See https://llvm.org/LICENSE.txt for license information. *| +|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This file defines the C interface to LLVM's Error class. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_C_ERROR_H +#define LLVM_C_ERROR_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define LLVMErrorSuccess 0 + +/** + * Opaque reference to an error instance. Null serves as the 'success' value. + */ +typedef struct LLVMOpaqueError *LLVMErrorRef; + +/** + * Error type identifier. + */ +typedef const void *LLVMErrorTypeId; + +/** + * Returns the type id for the given error instance, which must be a failure + * value (i.e. non-null). + */ +LLVMErrorTypeId LLVMGetErrorTypeId(LLVMErrorRef Err); + +/** + * Dispose of the given error without handling it. This operation consumes the + * error, and the given LLVMErrorRef value is not usable once this call returns. + * Note: This method *only* needs to be called if the error is not being passed + * to some other consuming operation, e.g. LLVMGetErrorMessage. + */ +void LLVMConsumeError(LLVMErrorRef Err); + +/** + * Returns the given string's error message. This operation consumes the error, + * and the given LLVMErrorRef value is not usable once this call returns. + * The caller is responsible for disposing of the string by calling + * LLVMDisposeErrorMessage. + */ +char *LLVMGetErrorMessage(LLVMErrorRef Err); + +/** + * Dispose of the given error message. + */ +void LLVMDisposeErrorMessage(char *ErrMsg); + +/** + * Returns the type id for llvm StringError. + */ +LLVMErrorTypeId LLVMGetStringErrorTypeId(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/llvm-c/ErrorHandling.h b/src/llvm-c/ErrorHandling.h new file mode 100644 index 000000000..4927349d8 --- /dev/null +++ b/src/llvm-c/ErrorHandling.h @@ -0,0 +1,49 @@ +/*===-- llvm-c/ErrorHandling.h - Error Handling C Interface -------*- C -*-===*\ +|* *| +|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *| +|* Exceptions. *| +|* See https://llvm.org/LICENSE.txt for license information. *| +|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This file defines the C interface to LLVM's error handling mechanism. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_C_ERROR_HANDLING_H +#define LLVM_C_ERROR_HANDLING_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void (*LLVMFatalErrorHandler)(const char *Reason); + +/** + * Install a fatal error handler. By default, if LLVM detects a fatal error, it + * will call exit(1). This may not be appropriate in many contexts. For example, + * doing exit(1) will bypass many crash reporting/tracing system tools. This + * function allows you to install a callback that will be invoked prior to the + * call to exit(1). + */ +void LLVMInstallFatalErrorHandler(LLVMFatalErrorHandler Handler); + +/** + * Reset the fatal error handler. This resets LLVM's fatal error handling + * behavior to the default. + */ +void LLVMResetFatalErrorHandler(void); + +/** + * Enable LLVM's built-in stack trace code. This intercepts the OS's crash + * signals and prints which component of LLVM you were in at the time if the + * crash. + */ +void LLVMEnablePrettyStackTrace(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/llvm-c/ExecutionEngine.h b/src/llvm-c/ExecutionEngine.h new file mode 100644 index 000000000..ef714cd06 --- /dev/null +++ b/src/llvm-c/ExecutionEngine.h @@ -0,0 +1,200 @@ +/*===-- llvm-c/ExecutionEngine.h - ExecutionEngine Lib C Iface --*- C++ -*-===*\ +|* *| +|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *| +|* Exceptions. *| +|* See https://llvm.org/LICENSE.txt for license information. *| +|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This header declares the C interface to libLLVMExecutionEngine.o, which *| +|* implements various analyses of the LLVM IR. *| +|* *| +|* Many exotic languages can interoperate with C code but have a harder time *| +|* with C++ due to name mangling. So in addition to C, this interface enables *| +|* tools written in such languages. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_C_EXECUTIONENGINE_H +#define LLVM_C_EXECUTIONENGINE_H + +#include "llvm-c/Target.h" +#include "llvm-c/TargetMachine.h" +#include "llvm-c/Types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup LLVMCExecutionEngine Execution Engine + * @ingroup LLVMC + * + * @{ + */ + +void LLVMLinkInMCJIT(void); +void LLVMLinkInInterpreter(void); + +typedef struct LLVMOpaqueGenericValue *LLVMGenericValueRef; +typedef struct LLVMOpaqueExecutionEngine *LLVMExecutionEngineRef; +typedef struct LLVMOpaqueMCJITMemoryManager *LLVMMCJITMemoryManagerRef; + +struct LLVMMCJITCompilerOptions { + unsigned OptLevel; + LLVMCodeModel CodeModel; + LLVMBool NoFramePointerElim; + LLVMBool EnableFastISel; + LLVMMCJITMemoryManagerRef MCJMM; +}; + +/*===-- Operations on generic values --------------------------------------===*/ + +LLVMGenericValueRef LLVMCreateGenericValueOfInt(LLVMTypeRef Ty, + unsigned long long N, + LLVMBool IsSigned); + +LLVMGenericValueRef LLVMCreateGenericValueOfPointer(void *P); + +LLVMGenericValueRef LLVMCreateGenericValueOfFloat(LLVMTypeRef Ty, double N); + +unsigned LLVMGenericValueIntWidth(LLVMGenericValueRef GenValRef); + +unsigned long long LLVMGenericValueToInt(LLVMGenericValueRef GenVal, + LLVMBool IsSigned); + +void *LLVMGenericValueToPointer(LLVMGenericValueRef GenVal); + +double LLVMGenericValueToFloat(LLVMTypeRef TyRef, LLVMGenericValueRef GenVal); + +void LLVMDisposeGenericValue(LLVMGenericValueRef GenVal); + +/*===-- Operations on execution engines -----------------------------------===*/ + +LLVMBool LLVMCreateExecutionEngineForModule(LLVMExecutionEngineRef *OutEE, + LLVMModuleRef M, + char **OutError); + +LLVMBool LLVMCreateInterpreterForModule(LLVMExecutionEngineRef *OutInterp, + LLVMModuleRef M, + char **OutError); + +LLVMBool LLVMCreateJITCompilerForModule(LLVMExecutionEngineRef *OutJIT, + LLVMModuleRef M, + unsigned OptLevel, + char **OutError); + +void LLVMInitializeMCJITCompilerOptions( + struct LLVMMCJITCompilerOptions *Options, size_t SizeOfOptions); + +/** + * Create an MCJIT execution engine for a module, with the given options. It is + * the responsibility of the caller to ensure that all fields in Options up to + * the given SizeOfOptions are initialized. It is correct to pass a smaller + * value of SizeOfOptions that omits some fields. The canonical way of using + * this is: + * + * LLVMMCJITCompilerOptions options; + * LLVMInitializeMCJITCompilerOptions(&options, sizeof(options)); + * ... fill in those options you care about + * LLVMCreateMCJITCompilerForModule(&jit, mod, &options, sizeof(options), + * &error); + * + * Note that this is also correct, though possibly suboptimal: + * + * LLVMCreateMCJITCompilerForModule(&jit, mod, 0, 0, &error); + */ +LLVMBool LLVMCreateMCJITCompilerForModule( + LLVMExecutionEngineRef *OutJIT, LLVMModuleRef M, + struct LLVMMCJITCompilerOptions *Options, size_t SizeOfOptions, + char **OutError); + +void LLVMDisposeExecutionEngine(LLVMExecutionEngineRef EE); + +void LLVMRunStaticConstructors(LLVMExecutionEngineRef EE); + +void LLVMRunStaticDestructors(LLVMExecutionEngineRef EE); + +int LLVMRunFunctionAsMain(LLVMExecutionEngineRef EE, LLVMValueRef F, + unsigned ArgC, const char * const *ArgV, + const char * const *EnvP); + +LLVMGenericValueRef LLVMRunFunction(LLVMExecutionEngineRef EE, LLVMValueRef F, + unsigned NumArgs, + LLVMGenericValueRef *Args); + +void LLVMFreeMachineCodeForFunction(LLVMExecutionEngineRef EE, LLVMValueRef F); + +void LLVMAddModule(LLVMExecutionEngineRef EE, LLVMModuleRef M); + +LLVMBool LLVMRemoveModule(LLVMExecutionEngineRef EE, LLVMModuleRef M, + LLVMModuleRef *OutMod, char **OutError); + +LLVMBool LLVMFindFunction(LLVMExecutionEngineRef EE, const char *Name, + LLVMValueRef *OutFn); + +void *LLVMRecompileAndRelinkFunction(LLVMExecutionEngineRef EE, + LLVMValueRef Fn); + +LLVMTargetDataRef LLVMGetExecutionEngineTargetData(LLVMExecutionEngineRef EE); +LLVMTargetMachineRef +LLVMGetExecutionEngineTargetMachine(LLVMExecutionEngineRef EE); + +void LLVMAddGlobalMapping(LLVMExecutionEngineRef EE, LLVMValueRef Global, + void* Addr); + +void *LLVMGetPointerToGlobal(LLVMExecutionEngineRef EE, LLVMValueRef Global); + +uint64_t LLVMGetGlobalValueAddress(LLVMExecutionEngineRef EE, const char *Name); + +uint64_t LLVMGetFunctionAddress(LLVMExecutionEngineRef EE, const char *Name); + +/*===-- Operations on memory managers -------------------------------------===*/ + +typedef uint8_t *(*LLVMMemoryManagerAllocateCodeSectionCallback)( + void *Opaque, uintptr_t Size, unsigned Alignment, unsigned SectionID, + const char *SectionName); +typedef uint8_t *(*LLVMMemoryManagerAllocateDataSectionCallback)( + void *Opaque, uintptr_t Size, unsigned Alignment, unsigned SectionID, + const char *SectionName, LLVMBool IsReadOnly); +typedef LLVMBool (*LLVMMemoryManagerFinalizeMemoryCallback)( + void *Opaque, char **ErrMsg); +typedef void (*LLVMMemoryManagerDestroyCallback)(void *Opaque); + +/** + * Create a simple custom MCJIT memory manager. This memory manager can + * intercept allocations in a module-oblivious way. This will return NULL + * if any of the passed functions are NULL. + * + * @param Opaque An opaque client object to pass back to the callbacks. + * @param AllocateCodeSection Allocate a block of memory for executable code. + * @param AllocateDataSection Allocate a block of memory for data. + * @param FinalizeMemory Set page permissions and flush cache. Return 0 on + * success, 1 on error. + */ +LLVMMCJITMemoryManagerRef LLVMCreateSimpleMCJITMemoryManager( + void *Opaque, + LLVMMemoryManagerAllocateCodeSectionCallback AllocateCodeSection, + LLVMMemoryManagerAllocateDataSectionCallback AllocateDataSection, + LLVMMemoryManagerFinalizeMemoryCallback FinalizeMemory, + LLVMMemoryManagerDestroyCallback Destroy); + +void LLVMDisposeMCJITMemoryManager(LLVMMCJITMemoryManagerRef MM); + +/*===-- JIT Event Listener functions -------------------------------------===*/ + +LLVMJITEventListenerRef LLVMCreateGDBRegistrationListener(void); +LLVMJITEventListenerRef LLVMCreateIntelJITEventListener(void); +LLVMJITEventListenerRef LLVMCreateOProfileJITEventListener(void); +LLVMJITEventListenerRef LLVMCreatePerfJITEventListener(void); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* defined(__cplusplus) */ + +#endif diff --git a/src/llvm-c/IRReader.h b/src/llvm-c/IRReader.h new file mode 100644 index 000000000..4d0b696e9 --- /dev/null +++ b/src/llvm-c/IRReader.h @@ -0,0 +1,40 @@ +/*===-- llvm-c/IRReader.h - IR Reader C Interface -----------------*- C -*-===*\ +|* *| +|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *| +|* Exceptions. *| +|* See https://llvm.org/LICENSE.txt for license information. *| +|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This file defines the C interface to the IR Reader. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_C_IRREADER_H +#define LLVM_C_IRREADER_H + +#include "llvm-c/Types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Read LLVM IR from a memory buffer and convert it into an in-memory Module + * object. Returns 0 on success. + * Optionally returns a human-readable description of any errors that + * occurred during parsing IR. OutMessage must be disposed with + * LLVMDisposeMessage. + * + * @see llvm::ParseIR() + */ +LLVMBool LLVMParseIRInContext(LLVMContextRef ContextRef, + LLVMMemoryBufferRef MemBuf, LLVMModuleRef *OutM, + char **OutMessage); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/llvm-c/Initialization.h b/src/llvm-c/Initialization.h new file mode 100644 index 000000000..36c41dbd8 --- /dev/null +++ b/src/llvm-c/Initialization.h @@ -0,0 +1,56 @@ +/*===-- llvm-c/Initialization.h - Initialization C Interface ------*- C -*-===*\ +|* *| +|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *| +|* Exceptions. *| +|* See https://llvm.org/LICENSE.txt for license information. *| +|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This header declares the C interface to LLVM initialization routines, *| +|* which must be called before you can use the functionality provided by *| +|* the corresponding LLVM library. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_C_INITIALIZATION_H +#define LLVM_C_INITIALIZATION_H + +#include "llvm-c/Types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup LLVMCInitialization Initialization Routines + * @ingroup LLVMC + * + * This module contains routines used to initialize the LLVM system. + * + * @{ + */ + +void LLVMInitializeCore(LLVMPassRegistryRef R); +void LLVMInitializeTransformUtils(LLVMPassRegistryRef R); +void LLVMInitializeScalarOpts(LLVMPassRegistryRef R); +void LLVMInitializeObjCARCOpts(LLVMPassRegistryRef R); +void LLVMInitializeVectorization(LLVMPassRegistryRef R); +void LLVMInitializeInstCombine(LLVMPassRegistryRef R); +void LLVMInitializeAggressiveInstCombiner(LLVMPassRegistryRef R); +void LLVMInitializeIPO(LLVMPassRegistryRef R); +void LLVMInitializeInstrumentation(LLVMPassRegistryRef R); +void LLVMInitializeAnalysis(LLVMPassRegistryRef R); +void LLVMInitializeIPA(LLVMPassRegistryRef R); +void LLVMInitializeCodeGen(LLVMPassRegistryRef R); +void LLVMInitializeTarget(LLVMPassRegistryRef R); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/llvm-c/LinkTimeOptimizer.h b/src/llvm-c/LinkTimeOptimizer.h new file mode 100644 index 000000000..19b4f5cf7 --- /dev/null +++ b/src/llvm-c/LinkTimeOptimizer.h @@ -0,0 +1,68 @@ +//===-- llvm/LinkTimeOptimizer.h - LTO Public C Interface -------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This header provides a C API to use the LLVM link time optimization +// library. This is intended to be used by linkers which are C-only in +// their implementation for performing LTO. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_C_LINKTIMEOPTIMIZER_H +#define LLVM_C_LINKTIMEOPTIMIZER_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup LLVMCLinkTimeOptimizer Link Time Optimization + * @ingroup LLVMC + * + * @{ + */ + + /// This provides a dummy type for pointers to the LTO object. + typedef void* llvm_lto_t; + + /// This provides a C-visible enumerator to manage status codes. + /// This should map exactly onto the C++ enumerator LTOStatus. + typedef enum llvm_lto_status { + LLVM_LTO_UNKNOWN, + LLVM_LTO_OPT_SUCCESS, + LLVM_LTO_READ_SUCCESS, + LLVM_LTO_READ_FAILURE, + LLVM_LTO_WRITE_FAILURE, + LLVM_LTO_NO_TARGET, + LLVM_LTO_NO_WORK, + LLVM_LTO_MODULE_MERGE_FAILURE, + LLVM_LTO_ASM_FAILURE, + + // Added C-specific error codes + LLVM_LTO_NULL_OBJECT + } llvm_lto_status_t; + + /// This provides C interface to initialize link time optimizer. This allows + /// linker to use dlopen() interface to dynamically load LinkTimeOptimizer. + /// extern "C" helps, because dlopen() interface uses name to find the symbol. + extern llvm_lto_t llvm_create_optimizer(void); + extern void llvm_destroy_optimizer(llvm_lto_t lto); + + extern llvm_lto_status_t llvm_read_object_file + (llvm_lto_t lto, const char* input_filename); + extern llvm_lto_status_t llvm_optimize_modules + (llvm_lto_t lto, const char* output_filename); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/llvm-c/Linker.h b/src/llvm-c/Linker.h new file mode 100644 index 000000000..908513041 --- /dev/null +++ b/src/llvm-c/Linker.h @@ -0,0 +1,41 @@ +/*===-- llvm-c/Linker.h - Module Linker C Interface -------------*- C++ -*-===*\ +|* *| +|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *| +|* Exceptions. *| +|* See https://llvm.org/LICENSE.txt for license information. *| +|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This file defines the C interface to the module/file/archive linker. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_C_LINKER_H +#define LLVM_C_LINKER_H + +#include "llvm-c/Types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* This enum is provided for backwards-compatibility only. It has no effect. */ +typedef enum { + LLVMLinkerDestroySource = 0, /* This is the default behavior. */ + LLVMLinkerPreserveSource_Removed = 1 /* This option has been deprecated and + should not be used. */ +} LLVMLinkerMode; + +/* Links the source module into the destination module. The source module is + * destroyed. + * The return value is true if an error occurred, false otherwise. + * Use the diagnostic handler to get any diagnostic message. +*/ +LLVMBool LLVMLinkModules2(LLVMModuleRef Dest, LLVMModuleRef Src); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/llvm-c/Object.h b/src/llvm-c/Object.h new file mode 100644 index 000000000..1f6501c8e --- /dev/null +++ b/src/llvm-c/Object.h @@ -0,0 +1,233 @@ +/*===-- llvm-c/Object.h - Object Lib C Iface --------------------*- C++ -*-===*/ +/* */ +/* Part of the LLVM Project, under the Apache License v2.0 with LLVM */ +/* Exceptions. */ +/* See https://llvm.org/LICENSE.txt for license information. */ +/* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception */ +/* */ +/*===----------------------------------------------------------------------===*/ +/* */ +/* This header declares the C interface to libLLVMObject.a, which */ +/* implements object file reading and writing. */ +/* */ +/* Many exotic languages can interoperate with C code but have a harder time */ +/* with C++ due to name mangling. So in addition to C, this interface enables */ +/* tools written in such languages. */ +/* */ +/*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_C_OBJECT_H +#define LLVM_C_OBJECT_H + +#include "llvm-c/Types.h" +#include "Config/llvm-config.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup LLVMCObject Object file reading and writing + * @ingroup LLVMC + * + * @{ + */ + +// Opaque type wrappers +typedef struct LLVMOpaqueSectionIterator *LLVMSectionIteratorRef; +typedef struct LLVMOpaqueSymbolIterator *LLVMSymbolIteratorRef; +typedef struct LLVMOpaqueRelocationIterator *LLVMRelocationIteratorRef; + +typedef enum { + LLVMBinaryTypeArchive, /**< Archive file. */ + LLVMBinaryTypeMachOUniversalBinary, /**< Mach-O Universal Binary file. */ + LLVMBinaryTypeCOFFImportFile, /**< COFF Import file. */ + LLVMBinaryTypeIR, /**< LLVM IR. */ + LLVMBinaryTypeWinRes, /**< Windows resource (.res) file. */ + LLVMBinaryTypeCOFF, /**< COFF Object file. */ + LLVMBinaryTypeELF32L, /**< ELF 32-bit, little endian. */ + LLVMBinaryTypeELF32B, /**< ELF 32-bit, big endian. */ + LLVMBinaryTypeELF64L, /**< ELF 64-bit, little endian. */ + LLVMBinaryTypeELF64B, /**< ELF 64-bit, big endian. */ + LLVMBinaryTypeMachO32L, /**< MachO 32-bit, little endian. */ + LLVMBinaryTypeMachO32B, /**< MachO 32-bit, big endian. */ + LLVMBinaryTypeMachO64L, /**< MachO 64-bit, little endian. */ + LLVMBinaryTypeMachO64B, /**< MachO 64-bit, big endian. */ + LLVMBinaryTypeWasm, /**< Web Assembly. */ +} LLVMBinaryType; + +/** + * Create a binary file from the given memory buffer. + * + * The exact type of the binary file will be inferred automatically, and the + * appropriate implementation selected. The context may be NULL except if + * the resulting file is an LLVM IR file. + * + * The memory buffer is not consumed by this function. It is the responsibilty + * of the caller to free it with \c LLVMDisposeMemoryBuffer. + * + * If NULL is returned, the \p ErrorMessage parameter is populated with the + * error's description. It is then the caller's responsibility to free this + * message by calling \c LLVMDisposeMessage. + * + * @see llvm::object::createBinary + */ +LLVMBinaryRef LLVMCreateBinary(LLVMMemoryBufferRef MemBuf, + LLVMContextRef Context, + char **ErrorMessage); + +/** + * Dispose of a binary file. + * + * The binary file does not own its backing buffer. It is the responsibilty + * of the caller to free it with \c LLVMDisposeMemoryBuffer. + */ +void LLVMDisposeBinary(LLVMBinaryRef BR); + +/** + * Retrieves a copy of the memory buffer associated with this object file. + * + * The returned buffer is merely a shallow copy and does not own the actual + * backing buffer of the binary. Nevertheless, it is the responsibility of the + * caller to free it with \c LLVMDisposeMemoryBuffer. + * + * @see llvm::object::getMemoryBufferRef + */ +LLVMMemoryBufferRef LLVMBinaryCopyMemoryBuffer(LLVMBinaryRef BR); + +/** + * Retrieve the specific type of a binary. + * + * @see llvm::object::Binary::getType + */ +LLVMBinaryType LLVMBinaryGetType(LLVMBinaryRef BR); + +/* + * For a Mach-O universal binary file, retrieves the object file corresponding + * to the given architecture if it is present as a slice. + * + * If NULL is returned, the \p ErrorMessage parameter is populated with the + * error's description. It is then the caller's responsibility to free this + * message by calling \c LLVMDisposeMessage. + * + * It is the responsiblity of the caller to free the returned object file by + * calling \c LLVMDisposeBinary. + */ +LLVMBinaryRef LLVMMachOUniversalBinaryCopyObjectForArch(LLVMBinaryRef BR, + const char *Arch, + size_t ArchLen, + char **ErrorMessage); + +/** + * Retrieve a copy of the section iterator for this object file. + * + * If there are no sections, the result is NULL. + * + * The returned iterator is merely a shallow copy. Nevertheless, it is + * the responsibility of the caller to free it with + * \c LLVMDisposeSectionIterator. + * + * @see llvm::object::sections() + */ +LLVMSectionIteratorRef LLVMObjectFileCopySectionIterator(LLVMBinaryRef BR); + +/** + * Returns whether the given section iterator is at the end. + * + * @see llvm::object::section_end + */ +LLVMBool LLVMObjectFileIsSectionIteratorAtEnd(LLVMBinaryRef BR, + LLVMSectionIteratorRef SI); + +/** + * Retrieve a copy of the symbol iterator for this object file. + * + * If there are no symbols, the result is NULL. + * + * The returned iterator is merely a shallow copy. Nevertheless, it is + * the responsibility of the caller to free it with + * \c LLVMDisposeSymbolIterator. + * + * @see llvm::object::symbols() + */ +LLVMSymbolIteratorRef LLVMObjectFileCopySymbolIterator(LLVMBinaryRef BR); + +/** + * Returns whether the given symbol iterator is at the end. + * + * @see llvm::object::symbol_end + */ +LLVMBool LLVMObjectFileIsSymbolIteratorAtEnd(LLVMBinaryRef BR, + LLVMSymbolIteratorRef SI); + +void LLVMDisposeSectionIterator(LLVMSectionIteratorRef SI); + +void LLVMMoveToNextSection(LLVMSectionIteratorRef SI); +void LLVMMoveToContainingSection(LLVMSectionIteratorRef Sect, + LLVMSymbolIteratorRef Sym); + +// ObjectFile Symbol iterators +void LLVMDisposeSymbolIterator(LLVMSymbolIteratorRef SI); +void LLVMMoveToNextSymbol(LLVMSymbolIteratorRef SI); + +// SectionRef accessors +const char *LLVMGetSectionName(LLVMSectionIteratorRef SI); +uint64_t LLVMGetSectionSize(LLVMSectionIteratorRef SI); +const char *LLVMGetSectionContents(LLVMSectionIteratorRef SI); +uint64_t LLVMGetSectionAddress(LLVMSectionIteratorRef SI); +LLVMBool LLVMGetSectionContainsSymbol(LLVMSectionIteratorRef SI, + LLVMSymbolIteratorRef Sym); + +// Section Relocation iterators +LLVMRelocationIteratorRef LLVMGetRelocations(LLVMSectionIteratorRef Section); +void LLVMDisposeRelocationIterator(LLVMRelocationIteratorRef RI); +LLVMBool LLVMIsRelocationIteratorAtEnd(LLVMSectionIteratorRef Section, + LLVMRelocationIteratorRef RI); +void LLVMMoveToNextRelocation(LLVMRelocationIteratorRef RI); + + +// SymbolRef accessors +const char *LLVMGetSymbolName(LLVMSymbolIteratorRef SI); +uint64_t LLVMGetSymbolAddress(LLVMSymbolIteratorRef SI); +uint64_t LLVMGetSymbolSize(LLVMSymbolIteratorRef SI); + +// RelocationRef accessors +uint64_t LLVMGetRelocationOffset(LLVMRelocationIteratorRef RI); +LLVMSymbolIteratorRef LLVMGetRelocationSymbol(LLVMRelocationIteratorRef RI); +uint64_t LLVMGetRelocationType(LLVMRelocationIteratorRef RI); +// NOTE: Caller takes ownership of returned string of the two +// following functions. +const char *LLVMGetRelocationTypeName(LLVMRelocationIteratorRef RI); +const char *LLVMGetRelocationValueString(LLVMRelocationIteratorRef RI); + +/** Deprecated: Use LLVMBinaryRef instead. */ +typedef struct LLVMOpaqueObjectFile *LLVMObjectFileRef; + +/** Deprecated: Use LLVMCreateBinary instead. */ +LLVMObjectFileRef LLVMCreateObjectFile(LLVMMemoryBufferRef MemBuf); + +/** Deprecated: Use LLVMDisposeBinary instead. */ +void LLVMDisposeObjectFile(LLVMObjectFileRef ObjectFile); + +/** Deprecated: Use LLVMObjectFileCopySectionIterator instead. */ +LLVMSectionIteratorRef LLVMGetSections(LLVMObjectFileRef ObjectFile); + +/** Deprecated: Use LLVMObjectFileIsSectionIteratorAtEnd instead. */ +LLVMBool LLVMIsSectionIteratorAtEnd(LLVMObjectFileRef ObjectFile, + LLVMSectionIteratorRef SI); + +/** Deprecated: Use LLVMObjectFileCopySymbolIterator instead. */ +LLVMSymbolIteratorRef LLVMGetSymbols(LLVMObjectFileRef ObjectFile); + +/** Deprecated: Use LLVMObjectFileIsSymbolIteratorAtEnd instead. */ +LLVMBool LLVMIsSymbolIteratorAtEnd(LLVMObjectFileRef ObjectFile, + LLVMSymbolIteratorRef SI); +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* defined(__cplusplus) */ + +#endif diff --git a/src/llvm-c/OrcBindings.h b/src/llvm-c/OrcBindings.h new file mode 100644 index 000000000..9e92371b5 --- /dev/null +++ b/src/llvm-c/OrcBindings.h @@ -0,0 +1,172 @@ +/*===----------- llvm-c/OrcBindings.h - Orc Lib C Iface ---------*- C++ -*-===*\ +|* *| +|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *| +|* Exceptions. *| +|* See https://llvm.org/LICENSE.txt for license information. *| +|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This header declares the C interface to libLLVMOrcJIT.a, which implements *| +|* JIT compilation of LLVM IR. *| +|* *| +|* Many exotic languages can interoperate with C code but have a harder time *| +|* with C++ due to name mangling. So in addition to C, this interface enables *| +|* tools written in such languages. *| +|* *| +|* Note: This interface is experimental. It is *NOT* stable, and may be *| +|* changed without warning. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_C_ORCBINDINGS_H +#define LLVM_C_ORCBINDINGS_H + +#include "llvm-c/Error.h" +#include "llvm-c/Object.h" +#include "llvm-c/TargetMachine.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct LLVMOrcOpaqueJITStack *LLVMOrcJITStackRef; +typedef uint64_t LLVMOrcModuleHandle; +typedef uint64_t LLVMOrcTargetAddress; +typedef uint64_t (*LLVMOrcSymbolResolverFn)(const char *Name, void *LookupCtx); +typedef uint64_t (*LLVMOrcLazyCompileCallbackFn)(LLVMOrcJITStackRef JITStack, + void *CallbackCtx); + +/** + * Create an ORC JIT stack. + * + * The client owns the resulting stack, and must call OrcDisposeInstance(...) + * to destroy it and free its memory. The JIT stack will take ownership of the + * TargetMachine, which will be destroyed when the stack is destroyed. The + * client should not attempt to dispose of the Target Machine, or it will result + * in a double-free. + */ +LLVMOrcJITStackRef LLVMOrcCreateInstance(LLVMTargetMachineRef TM); + +/** + * Get the error message for the most recent error (if any). + * + * This message is owned by the ORC JIT Stack and will be freed when the stack + * is disposed of by LLVMOrcDisposeInstance. + */ +const char *LLVMOrcGetErrorMsg(LLVMOrcJITStackRef JITStack); + +/** + * Mangle the given symbol. + * Memory will be allocated for MangledSymbol to hold the result. The client + */ +void LLVMOrcGetMangledSymbol(LLVMOrcJITStackRef JITStack, char **MangledSymbol, + const char *Symbol); + +/** + * Dispose of a mangled symbol. + */ +void LLVMOrcDisposeMangledSymbol(char *MangledSymbol); + +/** + * Create a lazy compile callback. + */ +LLVMErrorRef LLVMOrcCreateLazyCompileCallback( + LLVMOrcJITStackRef JITStack, LLVMOrcTargetAddress *RetAddr, + LLVMOrcLazyCompileCallbackFn Callback, void *CallbackCtx); + +/** + * Create a named indirect call stub. + */ +LLVMErrorRef LLVMOrcCreateIndirectStub(LLVMOrcJITStackRef JITStack, + const char *StubName, + LLVMOrcTargetAddress InitAddr); + +/** + * Set the pointer for the given indirect stub. + */ +LLVMErrorRef LLVMOrcSetIndirectStubPointer(LLVMOrcJITStackRef JITStack, + const char *StubName, + LLVMOrcTargetAddress NewAddr); + +/** + * Add module to be eagerly compiled. + */ +LLVMErrorRef LLVMOrcAddEagerlyCompiledIR(LLVMOrcJITStackRef JITStack, + LLVMOrcModuleHandle *RetHandle, + LLVMModuleRef Mod, + LLVMOrcSymbolResolverFn SymbolResolver, + void *SymbolResolverCtx); + +/** + * Add module to be lazily compiled one function at a time. + */ +LLVMErrorRef LLVMOrcAddLazilyCompiledIR(LLVMOrcJITStackRef JITStack, + LLVMOrcModuleHandle *RetHandle, + LLVMModuleRef Mod, + LLVMOrcSymbolResolverFn SymbolResolver, + void *SymbolResolverCtx); + +/** + * Add an object file. + * + * This method takes ownership of the given memory buffer and attempts to add + * it to the JIT as an object file. + * Clients should *not* dispose of the 'Obj' argument: the JIT will manage it + * from this call onwards. + */ +LLVMErrorRef LLVMOrcAddObjectFile(LLVMOrcJITStackRef JITStack, + LLVMOrcModuleHandle *RetHandle, + LLVMMemoryBufferRef Obj, + LLVMOrcSymbolResolverFn SymbolResolver, + void *SymbolResolverCtx); + +/** + * Remove a module set from the JIT. + * + * This works for all modules that can be added via OrcAdd*, including object + * files. + */ +LLVMErrorRef LLVMOrcRemoveModule(LLVMOrcJITStackRef JITStack, + LLVMOrcModuleHandle H); + +/** + * Get symbol address from JIT instance. + */ +LLVMErrorRef LLVMOrcGetSymbolAddress(LLVMOrcJITStackRef JITStack, + LLVMOrcTargetAddress *RetAddr, + const char *SymbolName); + +/** + * Get symbol address from JIT instance, searching only the specified + * handle. + */ +LLVMErrorRef LLVMOrcGetSymbolAddressIn(LLVMOrcJITStackRef JITStack, + LLVMOrcTargetAddress *RetAddr, + LLVMOrcModuleHandle H, + const char *SymbolName); + +/** + * Dispose of an ORC JIT stack. + */ +LLVMErrorRef LLVMOrcDisposeInstance(LLVMOrcJITStackRef JITStack); + +/** + * Register a JIT Event Listener. + * + * A NULL listener is ignored. + */ +void LLVMOrcRegisterJITEventListener(LLVMOrcJITStackRef JITStack, LLVMJITEventListenerRef L); + +/** + * Unegister a JIT Event Listener. + * + * A NULL listener is ignored. + */ +void LLVMOrcUnregisterJITEventListener(LLVMOrcJITStackRef JITStack, LLVMJITEventListenerRef L); + +#ifdef __cplusplus +} +#endif /* extern "C" */ + +#endif /* LLVM_C_ORCBINDINGS_H */ diff --git a/src/llvm-c/Remarks.h b/src/llvm-c/Remarks.h new file mode 100644 index 000000000..88eb5120c --- /dev/null +++ b/src/llvm-c/Remarks.h @@ -0,0 +1,329 @@ +/*===-- llvm-c/Remarks.h - Remarks Public C Interface -------------*- C -*-===*\ +|* *| +|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *| +|* Exceptions. *| +|* See https://llvm.org/LICENSE.txt for license information. *| +|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This header provides a public interface to a remark diagnostics library. *| +|* LLVM provides an implementation of this interface. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_C_REMARKS_H +#define LLVM_C_REMARKS_H + +#include "llvm-c/Types.h" +#ifdef __cplusplus +#include +extern "C" { +#else +#include +#endif /* !defined(__cplusplus) */ + +/** + * @defgroup LLVMCREMARKS Remarks + * @ingroup LLVMC + * + * @{ + */ + +#define REMARKS_API_VERSION 0 + +/** + * The type of the emitted remark. + */ +enum LLVMRemarkType { + LLVMRemarkTypeUnknown, + LLVMRemarkTypePassed, + LLVMRemarkTypeMissed, + LLVMRemarkTypeAnalysis, + LLVMRemarkTypeAnalysisFPCommute, + LLVMRemarkTypeAnalysisAliasing, + LLVMRemarkTypeFailure +}; + +/** + * String containing a buffer and a length. The buffer is not guaranteed to be + * zero-terminated. + * + * \since REMARKS_API_VERSION=0 + */ +typedef struct LLVMRemarkOpaqueString *LLVMRemarkStringRef; + +/** + * Returns the buffer holding the string. + * + * \since REMARKS_API_VERSION=0 + */ +extern const char *LLVMRemarkStringGetData(LLVMRemarkStringRef String); + +/** + * Returns the size of the string. + * + * \since REMARKS_API_VERSION=0 + */ +extern uint32_t LLVMRemarkStringGetLen(LLVMRemarkStringRef String); + +/** + * DebugLoc containing File, Line and Column. + * + * \since REMARKS_API_VERSION=0 + */ +typedef struct LLVMRemarkOpaqueDebugLoc *LLVMRemarkDebugLocRef; + +/** + * Return the path to the source file for a debug location. + * + * \since REMARKS_API_VERSION=0 + */ +extern LLVMRemarkStringRef +LLVMRemarkDebugLocGetSourceFilePath(LLVMRemarkDebugLocRef DL); + +/** + * Return the line in the source file for a debug location. + * + * \since REMARKS_API_VERSION=0 + */ +extern uint32_t LLVMRemarkDebugLocGetSourceLine(LLVMRemarkDebugLocRef DL); + +/** + * Return the column in the source file for a debug location. + * + * \since REMARKS_API_VERSION=0 + */ +extern uint32_t LLVMRemarkDebugLocGetSourceColumn(LLVMRemarkDebugLocRef DL); + +/** + * Element of the "Args" list. The key might give more information about what + * the semantics of the value are, e.g. "Callee" will tell you that the value + * is a symbol that names a function. + * + * \since REMARKS_API_VERSION=0 + */ +typedef struct LLVMRemarkOpaqueArg *LLVMRemarkArgRef; + +/** + * Returns the key of an argument. The key defines what the value is, and the + * same key can appear multiple times in the list of arguments. + * + * \since REMARKS_API_VERSION=0 + */ +extern LLVMRemarkStringRef LLVMRemarkArgGetKey(LLVMRemarkArgRef Arg); + +/** + * Returns the value of an argument. This is a string that can contain newlines. + * + * \since REMARKS_API_VERSION=0 + */ +extern LLVMRemarkStringRef LLVMRemarkArgGetValue(LLVMRemarkArgRef Arg); + +/** + * Returns the debug location that is attached to the value of this argument. + * + * If there is no debug location, the return value will be `NULL`. + * + * \since REMARKS_API_VERSION=0 + */ +extern LLVMRemarkDebugLocRef LLVMRemarkArgGetDebugLoc(LLVMRemarkArgRef Arg); + +/** + * A remark emitted by the compiler. + * + * \since REMARKS_API_VERSION=0 + */ +typedef struct LLVMRemarkOpaqueEntry *LLVMRemarkEntryRef; + +/** + * Free the resources used by the remark entry. + * + * \since REMARKS_API_VERSION=0 + */ +extern void LLVMRemarkEntryDispose(LLVMRemarkEntryRef Remark); + +/** + * The type of the remark. For example, it can allow users to only keep the + * missed optimizations from the compiler. + * + * \since REMARKS_API_VERSION=0 + */ +extern enum LLVMRemarkType LLVMRemarkEntryGetType(LLVMRemarkEntryRef Remark); + +/** + * Get the name of the pass that emitted this remark. + * + * \since REMARKS_API_VERSION=0 + */ +extern LLVMRemarkStringRef +LLVMRemarkEntryGetPassName(LLVMRemarkEntryRef Remark); + +/** + * Get an identifier of the remark. + * + * \since REMARKS_API_VERSION=0 + */ +extern LLVMRemarkStringRef +LLVMRemarkEntryGetRemarkName(LLVMRemarkEntryRef Remark); + +/** + * Get the name of the function being processed when the remark was emitted. + * + * \since REMARKS_API_VERSION=0 + */ +extern LLVMRemarkStringRef +LLVMRemarkEntryGetFunctionName(LLVMRemarkEntryRef Remark); + +/** + * Returns the debug location that is attached to this remark. + * + * If there is no debug location, the return value will be `NULL`. + * + * \since REMARKS_API_VERSION=0 + */ +extern LLVMRemarkDebugLocRef +LLVMRemarkEntryGetDebugLoc(LLVMRemarkEntryRef Remark); + +/** + * Return the hotness of the remark. + * + * A hotness of `0` means this value is not set. + * + * \since REMARKS_API_VERSION=0 + */ +extern uint64_t LLVMRemarkEntryGetHotness(LLVMRemarkEntryRef Remark); + +/** + * The number of arguments the remark holds. + * + * \since REMARKS_API_VERSION=0 + */ +extern uint32_t LLVMRemarkEntryGetNumArgs(LLVMRemarkEntryRef Remark); + +/** + * Get a new iterator to iterate over a remark's argument. + * + * If there are no arguments in \p Remark, the return value will be `NULL`. + * + * The lifetime of the returned value is bound to the lifetime of \p Remark. + * + * \since REMARKS_API_VERSION=0 + */ +extern LLVMRemarkArgRef LLVMRemarkEntryGetFirstArg(LLVMRemarkEntryRef Remark); + +/** + * Get the next argument in \p Remark from the position of \p It. + * + * Returns `NULL` if there are no more arguments available. + * + * The lifetime of the returned value is bound to the lifetime of \p Remark. + * + * \since REMARKS_API_VERSION=0 + */ +extern LLVMRemarkArgRef LLVMRemarkEntryGetNextArg(LLVMRemarkArgRef It, + LLVMRemarkEntryRef Remark); + +typedef struct LLVMRemarkOpaqueParser *LLVMRemarkParserRef; + +/** + * Creates a remark parser that can be used to parse the buffer located in \p + * Buf of size \p Size bytes. + * + * \p Buf cannot be `NULL`. + * + * This function should be paired with LLVMRemarkParserDispose() to avoid + * leaking resources. + * + * \since REMARKS_API_VERSION=0 + */ +extern LLVMRemarkParserRef LLVMRemarkParserCreateYAML(const void *Buf, + uint64_t Size); + +/** + * Returns the next remark in the file. + * + * The value pointed to by the return value needs to be disposed using a call to + * LLVMRemarkEntryDispose(). + * + * All the entries in the returned value that are of LLVMRemarkStringRef type + * will become invalidated once a call to LLVMRemarkParserDispose is made. + * + * If the parser reaches the end of the buffer, the return value will be `NULL`. + * + * In the case of an error, the return value will be `NULL`, and: + * + * 1) LLVMRemarkParserHasError() will return `1`. + * + * 2) LLVMRemarkParserGetErrorMessage() will return a descriptive error + * message. + * + * An error may occur if: + * + * 1) An argument is invalid. + * + * 2) There is a parsing error. This can occur on things like malformed YAML. + * + * 3) There is a Remark semantic error. This can occur on well-formed files with + * missing or extra fields. + * + * Here is a quick example of the usage: + * + * ``` + * LLVMRemarkParserRef Parser = LLVMRemarkParserCreateYAML(Buf, Size); + * LLVMRemarkEntryRef Remark = NULL; + * while ((Remark = LLVMRemarkParserGetNext(Parser))) { + * // use Remark + * LLVMRemarkEntryDispose(Remark); // Release memory. + * } + * bool HasError = LLVMRemarkParserHasError(Parser); + * LLVMRemarkParserDispose(Parser); + * ``` + * + * \since REMARKS_API_VERSION=0 + */ +extern LLVMRemarkEntryRef LLVMRemarkParserGetNext(LLVMRemarkParserRef Parser); + +/** + * Returns `1` if the parser encountered an error while parsing the buffer. + * + * \since REMARKS_API_VERSION=0 + */ +extern LLVMBool LLVMRemarkParserHasError(LLVMRemarkParserRef Parser); + +/** + * Returns a null-terminated string containing an error message. + * + * In case of no error, the result is `NULL`. + * + * The memory of the string is bound to the lifetime of \p Parser. If + * LLVMRemarkParserDispose() is called, the memory of the string will be + * released. + * + * \since REMARKS_API_VERSION=0 + */ +extern const char *LLVMRemarkParserGetErrorMessage(LLVMRemarkParserRef Parser); + +/** + * Releases all the resources used by \p Parser. + * + * \since REMARKS_API_VERSION=0 + */ +extern void LLVMRemarkParserDispose(LLVMRemarkParserRef Parser); + +/** + * Returns the version of the remarks library. + * + * \since REMARKS_API_VERSION=0 + */ +extern uint32_t LLVMRemarkVersion(void); + +/** + * @} // endgoup LLVMCREMARKS + */ + +#ifdef __cplusplus +} +#endif /* !defined(__cplusplus) */ + +#endif /* LLVM_C_REMARKS_H */ diff --git a/src/llvm-c/Support.h b/src/llvm-c/Support.h new file mode 100644 index 000000000..097f78424 --- /dev/null +++ b/src/llvm-c/Support.h @@ -0,0 +1,65 @@ +/*===-- llvm-c/Support.h - Support C Interface --------------------*- C -*-===*\ +|* *| +|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *| +|* Exceptions. *| +|* See https://llvm.org/LICENSE.txt for license information. *| +|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This file defines the C interface to the LLVM support library. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_C_SUPPORT_H +#define LLVM_C_SUPPORT_H + +#include "llvm-c/DataTypes.h" +#include "llvm-c/Types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * This function permanently loads the dynamic library at the given path. + * It is safe to call this function multiple times for the same library. + * + * @see sys::DynamicLibrary::LoadLibraryPermanently() + */ +LLVMBool LLVMLoadLibraryPermanently(const char* Filename); + +/** + * This function parses the given arguments using the LLVM command line parser. + * Note that the only stable thing about this function is its signature; you + * cannot rely on any particular set of command line arguments being interpreted + * the same way across LLVM versions. + * + * @see llvm::cl::ParseCommandLineOptions() + */ +void LLVMParseCommandLineOptions(int argc, const char *const *argv, + const char *Overview); + +/** + * This function will search through all previously loaded dynamic + * libraries for the symbol \p symbolName. If it is found, the address of + * that symbol is returned. If not, null is returned. + * + * @see sys::DynamicLibrary::SearchForAddressOfSymbol() + */ +void *LLVMSearchForAddressOfSymbol(const char *symbolName); + +/** + * This functions permanently adds the symbol \p symbolName with the + * value \p symbolValue. These symbols are searched before any + * libraries. + * + * @see sys::DynamicLibrary::AddSymbol() + */ +void LLVMAddSymbol(const char *symbolName, void *symbolValue); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/llvm-c/Target.h b/src/llvm-c/Target.h new file mode 100644 index 000000000..e0d0c0b29 --- /dev/null +++ b/src/llvm-c/Target.h @@ -0,0 +1,295 @@ +/*===-- llvm-c/Target.h - Target Lib C Iface --------------------*- C++ -*-===*/ +/* */ +/* Part of the LLVM Project, under the Apache License v2.0 with LLVM */ +/* Exceptions. */ +/* See https://llvm.org/LICENSE.txt for license information. */ +/* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception */ +/* */ +/*===----------------------------------------------------------------------===*/ +/* */ +/* This header declares the C interface to libLLVMTarget.a, which */ +/* implements target information. */ +/* */ +/* Many exotic languages can interoperate with C code but have a harder time */ +/* with C++ due to name mangling. So in addition to C, this interface enables */ +/* tools written in such languages. */ +/* */ +/*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_C_TARGET_H +#define LLVM_C_TARGET_H + +#include "Types.h" +#include "Config/llvm-config.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup LLVMCTarget Target information + * @ingroup LLVMC + * + * @{ + */ + +enum LLVMByteOrdering { LLVMBigEndian, LLVMLittleEndian }; + +typedef struct LLVMOpaqueTargetData *LLVMTargetDataRef; +typedef struct LLVMOpaqueTargetLibraryInfotData *LLVMTargetLibraryInfoRef; + +/* Declare all of the target-initialization functions that are available. */ +#define LLVM_TARGET(TargetName) \ + void LLVMInitialize##TargetName##TargetInfo(void); +#include "Config/Targets.def" +#undef LLVM_TARGET /* Explicit undef to make SWIG happier */ + +#define LLVM_TARGET(TargetName) void LLVMInitialize##TargetName##Target(void); +#include "Config/Targets.def" +#undef LLVM_TARGET /* Explicit undef to make SWIG happier */ + +#define LLVM_TARGET(TargetName) \ + void LLVMInitialize##TargetName##TargetMC(void); +#include "Config/Targets.def" +#undef LLVM_TARGET /* Explicit undef to make SWIG happier */ + +/* Declare all of the available assembly printer initialization functions. */ +#define LLVM_ASM_PRINTER(TargetName) \ + void LLVMInitialize##TargetName##AsmPrinter(void); +#include "Config/AsmPrinters.def" +#undef LLVM_ASM_PRINTER /* Explicit undef to make SWIG happier */ + +/* Declare all of the available assembly parser initialization functions. */ +#define LLVM_ASM_PARSER(TargetName) \ + void LLVMInitialize##TargetName##AsmParser(void); +#include "Config/AsmParsers.def" +#undef LLVM_ASM_PARSER /* Explicit undef to make SWIG happier */ + +/* Declare all of the available disassembler initialization functions. */ +#define LLVM_DISASSEMBLER(TargetName) \ + void LLVMInitialize##TargetName##Disassembler(void); +#include "Config/Disassemblers.def" +#undef LLVM_DISASSEMBLER /* Explicit undef to make SWIG happier */ + +/** LLVMInitializeAllTargetInfos - The main program should call this function if + it wants access to all available targets that LLVM is configured to + support. */ +static inline void LLVMInitializeAllTargetInfos(void) { +#define LLVM_TARGET(TargetName) LLVMInitialize##TargetName##TargetInfo(); +#include "Config/Targets.def" +#undef LLVM_TARGET /* Explicit undef to make SWIG happier */ +} + +/** LLVMInitializeAllTargets - The main program should call this function if it + wants to link in all available targets that LLVM is configured to + support. */ +static inline void LLVMInitializeAllTargets(void) { +#define LLVM_TARGET(TargetName) LLVMInitialize##TargetName##Target(); +#include "Config/Targets.def" +#undef LLVM_TARGET /* Explicit undef to make SWIG happier */ +} + +/** LLVMInitializeAllTargetMCs - The main program should call this function if + it wants access to all available target MC that LLVM is configured to + support. */ +static inline void LLVMInitializeAllTargetMCs(void) { +#define LLVM_TARGET(TargetName) LLVMInitialize##TargetName##TargetMC(); +#include "Config/Targets.def" +#undef LLVM_TARGET /* Explicit undef to make SWIG happier */ +} + +/** LLVMInitializeAllAsmPrinters - The main program should call this function if + it wants all asm printers that LLVM is configured to support, to make them + available via the TargetRegistry. */ +static inline void LLVMInitializeAllAsmPrinters(void) { +#define LLVM_ASM_PRINTER(TargetName) LLVMInitialize##TargetName##AsmPrinter(); +#include "Config/AsmPrinters.def" +#undef LLVM_ASM_PRINTER /* Explicit undef to make SWIG happier */ +} + +/** LLVMInitializeAllAsmParsers - The main program should call this function if + it wants all asm parsers that LLVM is configured to support, to make them + available via the TargetRegistry. */ +static inline void LLVMInitializeAllAsmParsers(void) { +#define LLVM_ASM_PARSER(TargetName) LLVMInitialize##TargetName##AsmParser(); +#include "Config/AsmParsers.def" +#undef LLVM_ASM_PARSER /* Explicit undef to make SWIG happier */ +} + +/** LLVMInitializeAllDisassemblers - The main program should call this function + if it wants all disassemblers that LLVM is configured to support, to make + them available via the TargetRegistry. */ +static inline void LLVMInitializeAllDisassemblers(void) { +#define LLVM_DISASSEMBLER(TargetName) \ + LLVMInitialize##TargetName##Disassembler(); +#include "Config/Disassemblers.def" +#undef LLVM_DISASSEMBLER /* Explicit undef to make SWIG happier */ +} + +/** LLVMInitializeNativeTarget - The main program should call this function to + initialize the native target corresponding to the host. This is useful + for JIT applications to ensure that the target gets linked in correctly. */ +static inline LLVMBool LLVMInitializeNativeTarget(void) { + /* If we have a native target, initialize it to ensure it is linked in. */ +#ifdef LLVM_NATIVE_TARGET + LLVM_NATIVE_TARGETINFO(); + LLVM_NATIVE_TARGET(); + LLVM_NATIVE_TARGETMC(); + return 0; +#else + return 1; +#endif +} + +/** LLVMInitializeNativeTargetAsmParser - The main program should call this + function to initialize the parser for the native target corresponding to the + host. */ +static inline LLVMBool LLVMInitializeNativeAsmParser(void) { +#ifdef LLVM_NATIVE_ASMPARSER + LLVM_NATIVE_ASMPARSER(); + return 0; +#else + return 1; +#endif +} + +/** LLVMInitializeNativeTargetAsmPrinter - The main program should call this + function to initialize the printer for the native target corresponding to + the host. */ +static inline LLVMBool LLVMInitializeNativeAsmPrinter(void) { +#ifdef LLVM_NATIVE_ASMPRINTER + LLVM_NATIVE_ASMPRINTER(); + return 0; +#else + return 1; +#endif +} + +/** LLVMInitializeNativeTargetDisassembler - The main program should call this + function to initialize the disassembler for the native target corresponding + to the host. */ +static inline LLVMBool LLVMInitializeNativeDisassembler(void) { +#ifdef LLVM_NATIVE_DISASSEMBLER + LLVM_NATIVE_DISASSEMBLER(); + return 0; +#else + return 1; +#endif +} + +/*===-- Target Data -------------------------------------------------------===*/ + +/** + * Obtain the data layout for a module. + * + * @see Module::getDataLayout() + */ +LLVMTargetDataRef LLVMGetModuleDataLayout(LLVMModuleRef M); + +/** + * Set the data layout for a module. + * + * @see Module::setDataLayout() + */ +void LLVMSetModuleDataLayout(LLVMModuleRef M, LLVMTargetDataRef DL); + +/** Creates target data from a target layout string. + See the constructor llvm::DataLayout::DataLayout. */ +LLVMTargetDataRef LLVMCreateTargetData(const char *StringRep); + +/** Deallocates a TargetData. + See the destructor llvm::DataLayout::~DataLayout. */ +void LLVMDisposeTargetData(LLVMTargetDataRef TD); + +/** Adds target library information to a pass manager. This does not take + ownership of the target library info. + See the method llvm::PassManagerBase::add. */ +void LLVMAddTargetLibraryInfo(LLVMTargetLibraryInfoRef TLI, + LLVMPassManagerRef PM); + +/** Converts target data to a target layout string. The string must be disposed + with LLVMDisposeMessage. + See the constructor llvm::DataLayout::DataLayout. */ +char *LLVMCopyStringRepOfTargetData(LLVMTargetDataRef TD); + +/** Returns the byte order of a target, either LLVMBigEndian or + LLVMLittleEndian. + See the method llvm::DataLayout::isLittleEndian. */ +enum LLVMByteOrdering LLVMByteOrder(LLVMTargetDataRef TD); + +/** Returns the pointer size in bytes for a target. + See the method llvm::DataLayout::getPointerSize. */ +unsigned LLVMPointerSize(LLVMTargetDataRef TD); + +/** Returns the pointer size in bytes for a target for a specified + address space. + See the method llvm::DataLayout::getPointerSize. */ +unsigned LLVMPointerSizeForAS(LLVMTargetDataRef TD, unsigned AS); + +/** Returns the integer type that is the same size as a pointer on a target. + See the method llvm::DataLayout::getIntPtrType. */ +LLVMTypeRef LLVMIntPtrType(LLVMTargetDataRef TD); + +/** Returns the integer type that is the same size as a pointer on a target. + This version allows the address space to be specified. + See the method llvm::DataLayout::getIntPtrType. */ +LLVMTypeRef LLVMIntPtrTypeForAS(LLVMTargetDataRef TD, unsigned AS); + +/** Returns the integer type that is the same size as a pointer on a target. + See the method llvm::DataLayout::getIntPtrType. */ +LLVMTypeRef LLVMIntPtrTypeInContext(LLVMContextRef C, LLVMTargetDataRef TD); + +/** Returns the integer type that is the same size as a pointer on a target. + This version allows the address space to be specified. + See the method llvm::DataLayout::getIntPtrType. */ +LLVMTypeRef LLVMIntPtrTypeForASInContext(LLVMContextRef C, LLVMTargetDataRef TD, + unsigned AS); + +/** Computes the size of a type in bytes for a target. + See the method llvm::DataLayout::getTypeSizeInBits. */ +unsigned long long LLVMSizeOfTypeInBits(LLVMTargetDataRef TD, LLVMTypeRef Ty); + +/** Computes the storage size of a type in bytes for a target. + See the method llvm::DataLayout::getTypeStoreSize. */ +unsigned long long LLVMStoreSizeOfType(LLVMTargetDataRef TD, LLVMTypeRef Ty); + +/** Computes the ABI size of a type in bytes for a target. + See the method llvm::DataLayout::getTypeAllocSize. */ +unsigned long long LLVMABISizeOfType(LLVMTargetDataRef TD, LLVMTypeRef Ty); + +/** Computes the ABI alignment of a type in bytes for a target. + See the method llvm::DataLayout::getTypeABISize. */ +unsigned LLVMABIAlignmentOfType(LLVMTargetDataRef TD, LLVMTypeRef Ty); + +/** Computes the call frame alignment of a type in bytes for a target. + See the method llvm::DataLayout::getTypeABISize. */ +unsigned LLVMCallFrameAlignmentOfType(LLVMTargetDataRef TD, LLVMTypeRef Ty); + +/** Computes the preferred alignment of a type in bytes for a target. + See the method llvm::DataLayout::getTypeABISize. */ +unsigned LLVMPreferredAlignmentOfType(LLVMTargetDataRef TD, LLVMTypeRef Ty); + +/** Computes the preferred alignment of a global variable in bytes for a target. + See the method llvm::DataLayout::getPreferredAlignment. */ +unsigned LLVMPreferredAlignmentOfGlobal(LLVMTargetDataRef TD, + LLVMValueRef GlobalVar); + +/** Computes the structure element that contains the byte offset for a target. + See the method llvm::StructLayout::getElementContainingOffset. */ +unsigned LLVMElementAtOffset(LLVMTargetDataRef TD, LLVMTypeRef StructTy, + unsigned long long Offset); + +/** Computes the byte offset of the indexed struct element for a target. + See the method llvm::StructLayout::getElementContainingOffset. */ +unsigned long long LLVMOffsetOfElement(LLVMTargetDataRef TD, + LLVMTypeRef StructTy, unsigned Element); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* defined(__cplusplus) */ + +#endif diff --git a/src/llvm-c/TargetMachine.h b/src/llvm-c/TargetMachine.h new file mode 100644 index 000000000..28d7c0968 --- /dev/null +++ b/src/llvm-c/TargetMachine.h @@ -0,0 +1,163 @@ +/*===-- llvm-c/TargetMachine.h - Target Machine Library C Interface - C++ -*-=*\ +|* *| +|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *| +|* Exceptions. *| +|* See https://llvm.org/LICENSE.txt for license information. *| +|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This header declares the C interface to the Target and TargetMachine *| +|* classes, which can be used to generate assembly or object files. *| +|* *| +|* Many exotic languages can interoperate with C code but have a harder time *| +|* with C++ due to name mangling. So in addition to C, this interface enables *| +|* tools written in such languages. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_C_TARGETMACHINE_H +#define LLVM_C_TARGETMACHINE_H + +#include "llvm-c/Target.h" +#include "llvm-c/Types.h" + +#ifdef __cplusplus +extern "C" { +#endif +typedef struct LLVMOpaqueTargetMachine *LLVMTargetMachineRef; +typedef struct LLVMTarget *LLVMTargetRef; + +typedef enum { + LLVMCodeGenLevelNone, + LLVMCodeGenLevelLess, + LLVMCodeGenLevelDefault, + LLVMCodeGenLevelAggressive +} LLVMCodeGenOptLevel; + +typedef enum { + LLVMRelocDefault, + LLVMRelocStatic, + LLVMRelocPIC, + LLVMRelocDynamicNoPic, + LLVMRelocROPI, + LLVMRelocRWPI, + LLVMRelocROPI_RWPI +} LLVMRelocMode; + +typedef enum { + LLVMCodeModelDefault, + LLVMCodeModelJITDefault, + LLVMCodeModelTiny, + LLVMCodeModelSmall, + LLVMCodeModelKernel, + LLVMCodeModelMedium, + LLVMCodeModelLarge +} LLVMCodeModel; + +typedef enum { + LLVMAssemblyFile, + LLVMObjectFile +} LLVMCodeGenFileType; + +/** Returns the first llvm::Target in the registered targets list. */ +LLVMTargetRef LLVMGetFirstTarget(void); +/** Returns the next llvm::Target given a previous one (or null if there's none) */ +LLVMTargetRef LLVMGetNextTarget(LLVMTargetRef T); + +/*===-- Target ------------------------------------------------------------===*/ +/** Finds the target corresponding to the given name and stores it in \p T. + Returns 0 on success. */ +LLVMTargetRef LLVMGetTargetFromName(const char *Name); + +/** Finds the target corresponding to the given triple and stores it in \p T. + Returns 0 on success. Optionally returns any error in ErrorMessage. + Use LLVMDisposeMessage to dispose the message. */ +LLVMBool LLVMGetTargetFromTriple(const char* Triple, LLVMTargetRef *T, + char **ErrorMessage); + +/** Returns the name of a target. See llvm::Target::getName */ +const char *LLVMGetTargetName(LLVMTargetRef T); + +/** Returns the description of a target. See llvm::Target::getDescription */ +const char *LLVMGetTargetDescription(LLVMTargetRef T); + +/** Returns if the target has a JIT */ +LLVMBool LLVMTargetHasJIT(LLVMTargetRef T); + +/** Returns if the target has a TargetMachine associated */ +LLVMBool LLVMTargetHasTargetMachine(LLVMTargetRef T); + +/** Returns if the target as an ASM backend (required for emitting output) */ +LLVMBool LLVMTargetHasAsmBackend(LLVMTargetRef T); + +/*===-- Target Machine ----------------------------------------------------===*/ +/** Creates a new llvm::TargetMachine. See llvm::Target::createTargetMachine */ +LLVMTargetMachineRef LLVMCreateTargetMachine(LLVMTargetRef T, + const char *Triple, const char *CPU, const char *Features, + LLVMCodeGenOptLevel Level, LLVMRelocMode Reloc, LLVMCodeModel CodeModel); + +/** Dispose the LLVMTargetMachineRef instance generated by + LLVMCreateTargetMachine. */ +void LLVMDisposeTargetMachine(LLVMTargetMachineRef T); + +/** Returns the Target used in a TargetMachine */ +LLVMTargetRef LLVMGetTargetMachineTarget(LLVMTargetMachineRef T); + +/** Returns the triple used creating this target machine. See + llvm::TargetMachine::getTriple. The result needs to be disposed with + LLVMDisposeMessage. */ +char *LLVMGetTargetMachineTriple(LLVMTargetMachineRef T); + +/** Returns the cpu used creating this target machine. See + llvm::TargetMachine::getCPU. The result needs to be disposed with + LLVMDisposeMessage. */ +char *LLVMGetTargetMachineCPU(LLVMTargetMachineRef T); + +/** Returns the feature string used creating this target machine. See + llvm::TargetMachine::getFeatureString. The result needs to be disposed with + LLVMDisposeMessage. */ +char *LLVMGetTargetMachineFeatureString(LLVMTargetMachineRef T); + +/** Create a DataLayout based on the targetMachine. */ +LLVMTargetDataRef LLVMCreateTargetDataLayout(LLVMTargetMachineRef T); + +/** Set the target machine's ASM verbosity. */ +void LLVMSetTargetMachineAsmVerbosity(LLVMTargetMachineRef T, + LLVMBool VerboseAsm); + +/** Emits an asm or object file for the given module to the filename. This + wraps several c++ only classes (among them a file stream). Returns any + error in ErrorMessage. Use LLVMDisposeMessage to dispose the message. */ +LLVMBool LLVMTargetMachineEmitToFile(LLVMTargetMachineRef T, LLVMModuleRef M, + char *Filename, LLVMCodeGenFileType codegen, char **ErrorMessage); + +/** Compile the LLVM IR stored in \p M and store the result in \p OutMemBuf. */ +LLVMBool LLVMTargetMachineEmitToMemoryBuffer(LLVMTargetMachineRef T, LLVMModuleRef M, + LLVMCodeGenFileType codegen, char** ErrorMessage, LLVMMemoryBufferRef *OutMemBuf); + +/*===-- Triple ------------------------------------------------------------===*/ +/** Get a triple for the host machine as a string. The result needs to be + disposed with LLVMDisposeMessage. */ +char* LLVMGetDefaultTargetTriple(void); + +/** Normalize a target triple. The result needs to be disposed with + LLVMDisposeMessage. */ +char* LLVMNormalizeTargetTriple(const char* triple); + +/** Get the host CPU as a string. The result needs to be disposed with + LLVMDisposeMessage. */ +char* LLVMGetHostCPUName(void); + +/** Get the host CPU's features as a string. The result needs to be disposed + with LLVMDisposeMessage. */ +char* LLVMGetHostCPUFeatures(void); + +/** Adds the target-specific analysis passes to the pass manager. */ +void LLVMAddAnalysisPasses(LLVMTargetMachineRef T, LLVMPassManagerRef PM); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/llvm-c/Transforms/AggressiveInstCombine.h b/src/llvm-c/Transforms/AggressiveInstCombine.h new file mode 100644 index 000000000..c0b0141c3 --- /dev/null +++ b/src/llvm-c/Transforms/AggressiveInstCombine.h @@ -0,0 +1,43 @@ +/*===-- AggressiveInstCombine.h ---------------------------------*- C++ -*-===*\ +|* *| +|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *| +|* Exceptions. *| +|* See https://llvm.org/LICENSE.txt for license information. *| +|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This header declares the C interface to libLLVMAggressiveInstCombine.a, *| +|* which combines instructions to form fewer, simple IR instructions. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_C_TRANSFORMS_AGGRESSIVEINSTCOMBINE_H +#define LLVM_C_TRANSFORMS_AGGRESSIVEINSTCOMBINE_H + +#include "llvm-c/Types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup LLVMCTransformsAggressiveInstCombine Aggressive Instruction Combining transformations + * @ingroup LLVMCTransforms + * + * @{ + */ + +/** See llvm::createAggressiveInstCombinerPass function. */ +void LLVMAddAggressiveInstCombinerPass(LLVMPassManagerRef PM); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* defined(__cplusplus) */ + +#endif + diff --git a/src/llvm-c/Transforms/Coroutines.h b/src/llvm-c/Transforms/Coroutines.h new file mode 100644 index 000000000..227e7cf0a --- /dev/null +++ b/src/llvm-c/Transforms/Coroutines.h @@ -0,0 +1,55 @@ +/*===-- Coroutines.h - Coroutines Library C Interface -----------*- C++ -*-===*\ +|* *| +|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *| +|* Exceptions. *| +|* See https://llvm.org/LICENSE.txt for license information. *| +|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This header declares the C interface to libLLVMCoroutines.a, which *| +|* implements various scalar transformations of the LLVM IR. *| +|* *| +|* Many exotic languages can interoperate with C code but have a harder time *| +|* with C++ due to name mangling. So in addition to C, this interface enables *| +|* tools written in such languages. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_C_TRANSFORMS_COROUTINES_H +#define LLVM_C_TRANSFORMS_COROUTINES_H + +#include "llvm-c/Types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup LLVMCTransformsCoroutines Coroutine transformations + * @ingroup LLVMCTransforms + * + * @{ + */ + +/** See llvm::createCoroEarlyPass function. */ +void LLVMAddCoroEarlyPass(LLVMPassManagerRef PM); + +/** See llvm::createCoroSplitPass function. */ +void LLVMAddCoroSplitPass(LLVMPassManagerRef PM); + +/** See llvm::createCoroElidePass function. */ +void LLVMAddCoroElidePass(LLVMPassManagerRef PM); + +/** See llvm::createCoroCleanupPass function. */ +void LLVMAddCoroCleanupPass(LLVMPassManagerRef PM); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* defined(__cplusplus) */ + +#endif diff --git a/src/llvm-c/Transforms/IPO.h b/src/llvm-c/Transforms/IPO.h new file mode 100644 index 000000000..7a82ed464 --- /dev/null +++ b/src/llvm-c/Transforms/IPO.h @@ -0,0 +1,84 @@ +/*===-- IPO.h - Interprocedural Transformations C Interface -----*- C++ -*-===*\ +|* *| +|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *| +|* Exceptions. *| +|* See https://llvm.org/LICENSE.txt for license information. *| +|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This header declares the C interface to libLLVMIPO.a, which implements *| +|* various interprocedural transformations of the LLVM IR. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_C_TRANSFORMS_IPO_H +#define LLVM_C_TRANSFORMS_IPO_H + +#include "llvm-c/Types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup LLVMCTransformsIPO Interprocedural transformations + * @ingroup LLVMCTransforms + * + * @{ + */ + +/** See llvm::createArgumentPromotionPass function. */ +void LLVMAddArgumentPromotionPass(LLVMPassManagerRef PM); + +/** See llvm::createConstantMergePass function. */ +void LLVMAddConstantMergePass(LLVMPassManagerRef PM); + +/** See llvm::createCalledValuePropagationPass function. */ +void LLVMAddCalledValuePropagationPass(LLVMPassManagerRef PM); + +/** See llvm::createDeadArgEliminationPass function. */ +void LLVMAddDeadArgEliminationPass(LLVMPassManagerRef PM); + +/** See llvm::createFunctionAttrsPass function. */ +void LLVMAddFunctionAttrsPass(LLVMPassManagerRef PM); + +/** See llvm::createFunctionInliningPass function. */ +void LLVMAddFunctionInliningPass(LLVMPassManagerRef PM); + +/** See llvm::createAlwaysInlinerPass function. */ +void LLVMAddAlwaysInlinerPass(LLVMPassManagerRef PM); + +/** See llvm::createGlobalDCEPass function. */ +void LLVMAddGlobalDCEPass(LLVMPassManagerRef PM); + +/** See llvm::createGlobalOptimizerPass function. */ +void LLVMAddGlobalOptimizerPass(LLVMPassManagerRef PM); + +/** See llvm::createIPConstantPropagationPass function. */ +void LLVMAddIPConstantPropagationPass(LLVMPassManagerRef PM); + +/** See llvm::createPruneEHPass function. */ +void LLVMAddPruneEHPass(LLVMPassManagerRef PM); + +/** See llvm::createIPSCCPPass function. */ +void LLVMAddIPSCCPPass(LLVMPassManagerRef PM); + +/** See llvm::createInternalizePass function. */ +void LLVMAddInternalizePass(LLVMPassManagerRef, unsigned AllButMain); + +/** See llvm::createStripDeadPrototypesPass function. */ +void LLVMAddStripDeadPrototypesPass(LLVMPassManagerRef PM); + +/** See llvm::createStripSymbolsPass function. */ +void LLVMAddStripSymbolsPass(LLVMPassManagerRef PM); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* defined(__cplusplus) */ + +#endif diff --git a/src/llvm-c/Transforms/InstCombine.h b/src/llvm-c/Transforms/InstCombine.h new file mode 100644 index 000000000..166f278d9 --- /dev/null +++ b/src/llvm-c/Transforms/InstCombine.h @@ -0,0 +1,43 @@ +/*===-- Scalar.h - Scalar Transformation Library C Interface ----*- C++ -*-===*\ +|* *| +|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *| +|* Exceptions. *| +|* See https://llvm.org/LICENSE.txt for license information. *| +|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This header declares the C interface to libLLVMInstCombine.a, which *| +|* combines instructions to form fewer, simple IR instructions. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_C_TRANSFORMS_INSTCOMBINE_H +#define LLVM_C_TRANSFORMS_INSTCOMBINE_H + +#include "llvm-c/Types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup LLVMCTransformsInstCombine Instruction Combining transformations + * @ingroup LLVMCTransforms + * + * @{ + */ + +/** See llvm::createInstructionCombiningPass function. */ +void LLVMAddInstructionCombiningPass(LLVMPassManagerRef PM); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* defined(__cplusplus) */ + +#endif + diff --git a/src/llvm-c/Transforms/PassManagerBuilder.h b/src/llvm-c/Transforms/PassManagerBuilder.h new file mode 100644 index 000000000..d164c00d4 --- /dev/null +++ b/src/llvm-c/Transforms/PassManagerBuilder.h @@ -0,0 +1,90 @@ +/*===-- llvm-c/Transform/PassManagerBuilder.h - PMB C Interface ---*- C -*-===*\ +|* *| +|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *| +|* Exceptions. *| +|* See https://llvm.org/LICENSE.txt for license information. *| +|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This header declares the C interface to the PassManagerBuilder class. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_C_TRANSFORMS_PASSMANAGERBUILDER_H +#define LLVM_C_TRANSFORMS_PASSMANAGERBUILDER_H + +#include "llvm-c/Types.h" + +typedef struct LLVMOpaquePassManagerBuilder *LLVMPassManagerBuilderRef; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup LLVMCTransformsPassManagerBuilder Pass manager builder + * @ingroup LLVMCTransforms + * + * @{ + */ + +/** See llvm::PassManagerBuilder. */ +LLVMPassManagerBuilderRef LLVMPassManagerBuilderCreate(void); +void LLVMPassManagerBuilderDispose(LLVMPassManagerBuilderRef PMB); + +/** See llvm::PassManagerBuilder::OptLevel. */ +void +LLVMPassManagerBuilderSetOptLevel(LLVMPassManagerBuilderRef PMB, + unsigned OptLevel); + +/** See llvm::PassManagerBuilder::SizeLevel. */ +void +LLVMPassManagerBuilderSetSizeLevel(LLVMPassManagerBuilderRef PMB, + unsigned SizeLevel); + +/** See llvm::PassManagerBuilder::DisableUnitAtATime. */ +void +LLVMPassManagerBuilderSetDisableUnitAtATime(LLVMPassManagerBuilderRef PMB, + LLVMBool Value); + +/** See llvm::PassManagerBuilder::DisableUnrollLoops. */ +void +LLVMPassManagerBuilderSetDisableUnrollLoops(LLVMPassManagerBuilderRef PMB, + LLVMBool Value); + +/** See llvm::PassManagerBuilder::DisableSimplifyLibCalls */ +void +LLVMPassManagerBuilderSetDisableSimplifyLibCalls(LLVMPassManagerBuilderRef PMB, + LLVMBool Value); + +/** See llvm::PassManagerBuilder::Inliner. */ +void +LLVMPassManagerBuilderUseInlinerWithThreshold(LLVMPassManagerBuilderRef PMB, + unsigned Threshold); + +/** See llvm::PassManagerBuilder::populateFunctionPassManager. */ +void +LLVMPassManagerBuilderPopulateFunctionPassManager(LLVMPassManagerBuilderRef PMB, + LLVMPassManagerRef PM); + +/** See llvm::PassManagerBuilder::populateModulePassManager. */ +void +LLVMPassManagerBuilderPopulateModulePassManager(LLVMPassManagerBuilderRef PMB, + LLVMPassManagerRef PM); + +/** See llvm::PassManagerBuilder::populateLTOPassManager. */ +void LLVMPassManagerBuilderPopulateLTOPassManager(LLVMPassManagerBuilderRef PMB, + LLVMPassManagerRef PM, + LLVMBool Internalize, + LLVMBool RunInliner); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/llvm-c/Transforms/Scalar.h b/src/llvm-c/Transforms/Scalar.h new file mode 100644 index 000000000..031cf98b2 --- /dev/null +++ b/src/llvm-c/Transforms/Scalar.h @@ -0,0 +1,167 @@ +/*===-- Scalar.h - Scalar Transformation Library C Interface ----*- C++ -*-===*\ +|* *| +|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *| +|* Exceptions. *| +|* See https://llvm.org/LICENSE.txt for license information. *| +|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This header declares the C interface to libLLVMScalarOpts.a, which *| +|* implements various scalar transformations of the LLVM IR. *| +|* *| +|* Many exotic languages can interoperate with C code but have a harder time *| +|* with C++ due to name mangling. So in addition to C, this interface enables *| +|* tools written in such languages. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_C_TRANSFORMS_SCALAR_H +#define LLVM_C_TRANSFORMS_SCALAR_H + +#include "llvm-c/Types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup LLVMCTransformsScalar Scalar transformations + * @ingroup LLVMCTransforms + * + * @{ + */ + +/** See llvm::createAggressiveDCEPass function. */ +void LLVMAddAggressiveDCEPass(LLVMPassManagerRef PM); + +/** See llvm::createBitTrackingDCEPass function. */ +void LLVMAddBitTrackingDCEPass(LLVMPassManagerRef PM); + +/** See llvm::createAlignmentFromAssumptionsPass function. */ +void LLVMAddAlignmentFromAssumptionsPass(LLVMPassManagerRef PM); + +/** See llvm::createCFGSimplificationPass function. */ +void LLVMAddCFGSimplificationPass(LLVMPassManagerRef PM); + +/** See llvm::createDeadStoreEliminationPass function. */ +void LLVMAddDeadStoreEliminationPass(LLVMPassManagerRef PM); + +/** See llvm::createScalarizerPass function. */ +void LLVMAddScalarizerPass(LLVMPassManagerRef PM); + +/** See llvm::createMergedLoadStoreMotionPass function. */ +void LLVMAddMergedLoadStoreMotionPass(LLVMPassManagerRef PM); + +/** See llvm::createGVNPass function. */ +void LLVMAddGVNPass(LLVMPassManagerRef PM); + +/** See llvm::createGVNPass function. */ +void LLVMAddNewGVNPass(LLVMPassManagerRef PM); + +/** See llvm::createIndVarSimplifyPass function. */ +void LLVMAddIndVarSimplifyPass(LLVMPassManagerRef PM); + +/** See llvm::createInstructionCombiningPass function. */ +void LLVMAddInstructionCombiningPass(LLVMPassManagerRef PM); + +/** See llvm::createJumpThreadingPass function. */ +void LLVMAddJumpThreadingPass(LLVMPassManagerRef PM); + +/** See llvm::createLICMPass function. */ +void LLVMAddLICMPass(LLVMPassManagerRef PM); + +/** See llvm::createLoopDeletionPass function. */ +void LLVMAddLoopDeletionPass(LLVMPassManagerRef PM); + +/** See llvm::createLoopIdiomPass function */ +void LLVMAddLoopIdiomPass(LLVMPassManagerRef PM); + +/** See llvm::createLoopRotatePass function. */ +void LLVMAddLoopRotatePass(LLVMPassManagerRef PM); + +/** See llvm::createLoopRerollPass function. */ +void LLVMAddLoopRerollPass(LLVMPassManagerRef PM); + +/** See llvm::createLoopUnrollPass function. */ +void LLVMAddLoopUnrollPass(LLVMPassManagerRef PM); + +/** See llvm::createLoopUnrollAndJamPass function. */ +void LLVMAddLoopUnrollAndJamPass(LLVMPassManagerRef PM); + +/** See llvm::createLoopUnswitchPass function. */ +void LLVMAddLoopUnswitchPass(LLVMPassManagerRef PM); + +/** See llvm::createLowerAtomicPass function. */ +void LLVMAddLowerAtomicPass(LLVMPassManagerRef PM); + +/** See llvm::createMemCpyOptPass function. */ +void LLVMAddMemCpyOptPass(LLVMPassManagerRef PM); + +/** See llvm::createPartiallyInlineLibCallsPass function. */ +void LLVMAddPartiallyInlineLibCallsPass(LLVMPassManagerRef PM); + +/** See llvm::createReassociatePass function. */ +void LLVMAddReassociatePass(LLVMPassManagerRef PM); + +/** See llvm::createSCCPPass function. */ +void LLVMAddSCCPPass(LLVMPassManagerRef PM); + +/** See llvm::createSROAPass function. */ +void LLVMAddScalarReplAggregatesPass(LLVMPassManagerRef PM); + +/** See llvm::createSROAPass function. */ +void LLVMAddScalarReplAggregatesPassSSA(LLVMPassManagerRef PM); + +/** See llvm::createSROAPass function. */ +void LLVMAddScalarReplAggregatesPassWithThreshold(LLVMPassManagerRef PM, + int Threshold); + +/** See llvm::createSimplifyLibCallsPass function. */ +void LLVMAddSimplifyLibCallsPass(LLVMPassManagerRef PM); + +/** See llvm::createTailCallEliminationPass function. */ +void LLVMAddTailCallEliminationPass(LLVMPassManagerRef PM); + +/** See llvm::createConstantPropagationPass function. */ +void LLVMAddConstantPropagationPass(LLVMPassManagerRef PM); + +/** See llvm::demotePromoteMemoryToRegisterPass function. */ +void LLVMAddDemoteMemoryToRegisterPass(LLVMPassManagerRef PM); + +/** See llvm::createVerifierPass function. */ +void LLVMAddVerifierPass(LLVMPassManagerRef PM); + +/** See llvm::createCorrelatedValuePropagationPass function */ +void LLVMAddCorrelatedValuePropagationPass(LLVMPassManagerRef PM); + +/** See llvm::createEarlyCSEPass function */ +void LLVMAddEarlyCSEPass(LLVMPassManagerRef PM); + +/** See llvm::createEarlyCSEPass function */ +void LLVMAddEarlyCSEMemSSAPass(LLVMPassManagerRef PM); + +/** See llvm::createLowerExpectIntrinsicPass function */ +void LLVMAddLowerExpectIntrinsicPass(LLVMPassManagerRef PM); + +/** See llvm::createTypeBasedAliasAnalysisPass function */ +void LLVMAddTypeBasedAliasAnalysisPass(LLVMPassManagerRef PM); + +/** See llvm::createScopedNoAliasAAPass function */ +void LLVMAddScopedNoAliasAAPass(LLVMPassManagerRef PM); + +/** See llvm::createBasicAliasAnalysisPass function */ +void LLVMAddBasicAliasAnalysisPass(LLVMPassManagerRef PM); + +/** See llvm::createUnifyFunctionExitNodesPass function */ +void LLVMAddUnifyFunctionExitNodesPass(LLVMPassManagerRef PM); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* defined(__cplusplus) */ + +#endif diff --git a/src/llvm-c/Transforms/Utils.h b/src/llvm-c/Transforms/Utils.h new file mode 100644 index 000000000..63594abfa --- /dev/null +++ b/src/llvm-c/Transforms/Utils.h @@ -0,0 +1,53 @@ +/*===-- Utils.h - Transformation Utils Library C Interface ------*- C++ -*-===*\ +|* *| +|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *| +|* Exceptions. *| +|* See https://llvm.org/LICENSE.txt for license information. *| +|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This header declares the C interface to libLLVMTransformUtils.a, which *| +|* implements various transformation utilities of the LLVM IR. *| +|* *| +|* Many exotic languages can interoperate with C code but have a harder time *| +|* with C++ due to name mangling. So in addition to C, this interface enables *| +|* tools written in such languages. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_C_TRANSFORMS_UTILS_H +#define LLVM_C_TRANSFORMS_UTILS_H + +#include "llvm-c/Types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup LLVMCTransformsUtils Transformation Utilities + * @ingroup LLVMCTransforms + * + * @{ + */ + +/** See llvm::createLowerSwitchPass function. */ +void LLVMAddLowerSwitchPass(LLVMPassManagerRef PM); + +/** See llvm::createPromoteMemoryToRegisterPass function. */ +void LLVMAddPromoteMemoryToRegisterPass(LLVMPassManagerRef PM); + +/** See llvm::createAddDiscriminatorsPass function. */ +void LLVMAddAddDiscriminatorsPass(LLVMPassManagerRef PM); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* defined(__cplusplus) */ + +#endif + diff --git a/src/llvm-c/Transforms/Vectorize.h b/src/llvm-c/Transforms/Vectorize.h new file mode 100644 index 000000000..e383481fe --- /dev/null +++ b/src/llvm-c/Transforms/Vectorize.h @@ -0,0 +1,50 @@ +/*===---------------------------Vectorize.h --------------------- -*- C -*-===*\ +|*===----------- Vectorization Transformation Library C Interface ---------===*| +|* *| +|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *| +|* Exceptions. *| +|* See https://llvm.org/LICENSE.txt for license information. *| +|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This header declares the C interface to libLLVMVectorize.a, which *| +|* implements various vectorization transformations of the LLVM IR. *| +|* *| +|* Many exotic languages can interoperate with C code but have a harder time *| +|* with C++ due to name mangling. So in addition to C, this interface enables *| +|* tools written in such languages. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_C_TRANSFORMS_VECTORIZE_H +#define LLVM_C_TRANSFORMS_VECTORIZE_H + +#include "llvm-c/Types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup LLVMCTransformsVectorize Vectorization transformations + * @ingroup LLVMCTransforms + * + * @{ + */ + +/** See llvm::createLoopVectorizePass function. */ +void LLVMAddLoopVectorizePass(LLVMPassManagerRef PM); + +/** See llvm::createSLPVectorizerPass function. */ +void LLVMAddSLPVectorizePass(LLVMPassManagerRef PM); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* defined(__cplusplus) */ + +#endif diff --git a/src/llvm-c/Types.h b/src/llvm-c/Types.h new file mode 100644 index 000000000..612c7d3ef --- /dev/null +++ b/src/llvm-c/Types.h @@ -0,0 +1,179 @@ +/*===-- llvm-c/Support.h - C Interface Types declarations ---------*- C -*-===*\ +|* *| +|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *| +|* Exceptions. *| +|* See https://llvm.org/LICENSE.txt for license information. *| +|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This file defines types used by the C interface to LLVM. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_C_TYPES_H +#define LLVM_C_TYPES_H + +#include "llvm-c/DataTypes.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup LLVMCSupportTypes Types and Enumerations + * + * @{ + */ + +typedef int LLVMBool; + +/* Opaque types. */ + +/** + * LLVM uses a polymorphic type hierarchy which C cannot represent, therefore + * parameters must be passed as base types. Despite the declared types, most + * of the functions provided operate only on branches of the type hierarchy. + * The declared parameter names are descriptive and specify which type is + * required. Additionally, each type hierarchy is documented along with the + * functions that operate upon it. For more detail, refer to LLVM's C++ code. + * If in doubt, refer to Core.cpp, which performs parameter downcasts in the + * form unwrap(Param). + */ + +/** + * Used to pass regions of memory through LLVM interfaces. + * + * @see llvm::MemoryBuffer + */ +typedef struct LLVMOpaqueMemoryBuffer *LLVMMemoryBufferRef; + +/** + * The top-level container for all LLVM global data. See the LLVMContext class. + */ +typedef struct LLVMOpaqueContext *LLVMContextRef; + +/** + * The top-level container for all other LLVM Intermediate Representation (IR) + * objects. + * + * @see llvm::Module + */ +typedef struct LLVMOpaqueModule *LLVMModuleRef; + +/** + * Each value in the LLVM IR has a type, an LLVMTypeRef. + * + * @see llvm::Type + */ +typedef struct LLVMOpaqueType *LLVMTypeRef; + +/** + * Represents an individual value in LLVM IR. + * + * This models llvm::Value. + */ +typedef struct LLVMOpaqueValue *LLVMValueRef; + +/** + * Represents a basic block of instructions in LLVM IR. + * + * This models llvm::BasicBlock. + */ +typedef struct LLVMOpaqueBasicBlock *LLVMBasicBlockRef; + +/** + * Represents an LLVM Metadata. + * + * This models llvm::Metadata. + */ +typedef struct LLVMOpaqueMetadata *LLVMMetadataRef; + +/** + * Represents an LLVM Named Metadata Node. + * + * This models llvm::NamedMDNode. + */ +typedef struct LLVMOpaqueNamedMDNode *LLVMNamedMDNodeRef; + +/** + * Represents an entry in a Global Object's metadata attachments. + * + * This models std::pair + */ +typedef struct LLVMOpaqueValueMetadataEntry LLVMValueMetadataEntry; + +/** + * Represents an LLVM basic block builder. + * + * This models llvm::IRBuilder. + */ +typedef struct LLVMOpaqueBuilder *LLVMBuilderRef; + +/** + * Represents an LLVM debug info builder. + * + * This models llvm::DIBuilder. + */ +typedef struct LLVMOpaqueDIBuilder *LLVMDIBuilderRef; + +/** + * Interface used to provide a module to JIT or interpreter. + * This is now just a synonym for llvm::Module, but we have to keep using the + * different type to keep binary compatibility. + */ +typedef struct LLVMOpaqueModuleProvider *LLVMModuleProviderRef; + +/** @see llvm::PassManagerBase */ +typedef struct LLVMOpaquePassManager *LLVMPassManagerRef; + +/** @see llvm::PassRegistry */ +typedef struct LLVMOpaquePassRegistry *LLVMPassRegistryRef; + +/** + * Used to get the users and usees of a Value. + * + * @see llvm::Use */ +typedef struct LLVMOpaqueUse *LLVMUseRef; + +/** + * Used to represent an attributes. + * + * @see llvm::Attribute + */ +typedef struct LLVMOpaqueAttributeRef *LLVMAttributeRef; + +/** + * @see llvm::DiagnosticInfo + */ +typedef struct LLVMOpaqueDiagnosticInfo *LLVMDiagnosticInfoRef; + +/** + * @see llvm::Comdat + */ +typedef struct LLVMComdat *LLVMComdatRef; + +/** + * @see llvm::Module::ModuleFlagEntry + */ +typedef struct LLVMOpaqueModuleFlagEntry LLVMModuleFlagEntry; + +/** + * @see llvm::JITEventListener + */ +typedef struct LLVMOpaqueJITEventListener *LLVMJITEventListenerRef; + +/** + * @see llvm::object::Binary + */ +typedef struct LLVMOpaqueBinary *LLVMBinaryRef; + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/llvm-c/lto.h b/src/llvm-c/lto.h new file mode 100644 index 000000000..2467722b1 --- /dev/null +++ b/src/llvm-c/lto.h @@ -0,0 +1,899 @@ +/*===-- llvm-c/lto.h - LTO Public C Interface ---------------------*- C -*-===*\ +|* *| +|* Part of the LLVM Project, under the Apache License v2.0 with LLVM *| +|* Exceptions. *| +|* See https://llvm.org/LICENSE.txt for license information. *| +|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This header provides public interface to an abstract link time optimization*| +|* library. LLVM provides an implementation of this interface for use with *| +|* llvm bitcode files. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_C_LTO_H +#define LLVM_C_LTO_H + +#ifdef __cplusplus +#include +#else +#include +#endif +#include + +#ifndef __cplusplus +#if !defined(_MSC_VER) +#include +typedef bool lto_bool_t; +#else +/* MSVC in particular does not have anything like _Bool or bool in C, but we can + at least make sure the type is the same size. The implementation side will + use C++ bool. */ +typedef unsigned char lto_bool_t; +#endif +#else +typedef bool lto_bool_t; +#endif + +/** + * @defgroup LLVMCLTO LTO + * @ingroup LLVMC + * + * @{ + */ + +#define LTO_API_VERSION 24 + +/** + * \since prior to LTO_API_VERSION=3 + */ +typedef enum { + LTO_SYMBOL_ALIGNMENT_MASK = 0x0000001F, /* log2 of alignment */ + LTO_SYMBOL_PERMISSIONS_MASK = 0x000000E0, + LTO_SYMBOL_PERMISSIONS_CODE = 0x000000A0, + LTO_SYMBOL_PERMISSIONS_DATA = 0x000000C0, + LTO_SYMBOL_PERMISSIONS_RODATA = 0x00000080, + LTO_SYMBOL_DEFINITION_MASK = 0x00000700, + LTO_SYMBOL_DEFINITION_REGULAR = 0x00000100, + LTO_SYMBOL_DEFINITION_TENTATIVE = 0x00000200, + LTO_SYMBOL_DEFINITION_WEAK = 0x00000300, + LTO_SYMBOL_DEFINITION_UNDEFINED = 0x00000400, + LTO_SYMBOL_DEFINITION_WEAKUNDEF = 0x00000500, + LTO_SYMBOL_SCOPE_MASK = 0x00003800, + LTO_SYMBOL_SCOPE_INTERNAL = 0x00000800, + LTO_SYMBOL_SCOPE_HIDDEN = 0x00001000, + LTO_SYMBOL_SCOPE_PROTECTED = 0x00002000, + LTO_SYMBOL_SCOPE_DEFAULT = 0x00001800, + LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN = 0x00002800, + LTO_SYMBOL_COMDAT = 0x00004000, + LTO_SYMBOL_ALIAS = 0x00008000 +} lto_symbol_attributes; + +/** + * \since prior to LTO_API_VERSION=3 + */ +typedef enum { + LTO_DEBUG_MODEL_NONE = 0, + LTO_DEBUG_MODEL_DWARF = 1 +} lto_debug_model; + +/** + * \since prior to LTO_API_VERSION=3 + */ +typedef enum { + LTO_CODEGEN_PIC_MODEL_STATIC = 0, + LTO_CODEGEN_PIC_MODEL_DYNAMIC = 1, + LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC = 2, + LTO_CODEGEN_PIC_MODEL_DEFAULT = 3 +} lto_codegen_model; + +/** opaque reference to a loaded object module */ +typedef struct LLVMOpaqueLTOModule *lto_module_t; + +/** opaque reference to a code generator */ +typedef struct LLVMOpaqueLTOCodeGenerator *lto_code_gen_t; + +/** opaque reference to a thin code generator */ +typedef struct LLVMOpaqueThinLTOCodeGenerator *thinlto_code_gen_t; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Returns a printable string. + * + * \since prior to LTO_API_VERSION=3 + */ +extern const char* +lto_get_version(void); + +/** + * Returns the last error string or NULL if last operation was successful. + * + * \since prior to LTO_API_VERSION=3 + */ +extern const char* +lto_get_error_message(void); + +/** + * Checks if a file is a loadable object file. + * + * \since prior to LTO_API_VERSION=3 + */ +extern lto_bool_t +lto_module_is_object_file(const char* path); + +/** + * Checks if a file is a loadable object compiled for requested target. + * + * \since prior to LTO_API_VERSION=3 + */ +extern lto_bool_t +lto_module_is_object_file_for_target(const char* path, + const char* target_triple_prefix); + +/** + * Return true if \p Buffer contains a bitcode file with ObjC code (category + * or class) in it. + * + * \since LTO_API_VERSION=20 + */ +extern lto_bool_t +lto_module_has_objc_category(const void *mem, size_t length); + +/** + * Checks if a buffer is a loadable object file. + * + * \since prior to LTO_API_VERSION=3 + */ +extern lto_bool_t lto_module_is_object_file_in_memory(const void *mem, + size_t length); + +/** + * Checks if a buffer is a loadable object compiled for requested target. + * + * \since prior to LTO_API_VERSION=3 + */ +extern lto_bool_t +lto_module_is_object_file_in_memory_for_target(const void* mem, size_t length, + const char* target_triple_prefix); + +/** + * Loads an object file from disk. + * Returns NULL on error (check lto_get_error_message() for details). + * + * \since prior to LTO_API_VERSION=3 + */ +extern lto_module_t +lto_module_create(const char* path); + +/** + * Loads an object file from memory. + * Returns NULL on error (check lto_get_error_message() for details). + * + * \since prior to LTO_API_VERSION=3 + */ +extern lto_module_t +lto_module_create_from_memory(const void* mem, size_t length); + +/** + * Loads an object file from memory with an extra path argument. + * Returns NULL on error (check lto_get_error_message() for details). + * + * \since LTO_API_VERSION=9 + */ +extern lto_module_t +lto_module_create_from_memory_with_path(const void* mem, size_t length, + const char *path); + +/** + * Loads an object file in its own context. + * + * Loads an object file in its own LLVMContext. This function call is + * thread-safe. However, modules created this way should not be merged into an + * lto_code_gen_t using \a lto_codegen_add_module(). + * + * Returns NULL on error (check lto_get_error_message() for details). + * + * \since LTO_API_VERSION=11 + */ +extern lto_module_t +lto_module_create_in_local_context(const void *mem, size_t length, + const char *path); + +/** + * Loads an object file in the codegen context. + * + * Loads an object file into the same context as \c cg. The module is safe to + * add using \a lto_codegen_add_module(). + * + * Returns NULL on error (check lto_get_error_message() for details). + * + * \since LTO_API_VERSION=11 + */ +extern lto_module_t +lto_module_create_in_codegen_context(const void *mem, size_t length, + const char *path, lto_code_gen_t cg); + +/** + * Loads an object file from disk. The seek point of fd is not preserved. + * Returns NULL on error (check lto_get_error_message() for details). + * + * \since LTO_API_VERSION=5 + */ +extern lto_module_t +lto_module_create_from_fd(int fd, const char *path, size_t file_size); + +/** + * Loads an object file from disk. The seek point of fd is not preserved. + * Returns NULL on error (check lto_get_error_message() for details). + * + * \since LTO_API_VERSION=5 + */ +extern lto_module_t +lto_module_create_from_fd_at_offset(int fd, const char *path, size_t file_size, + size_t map_size, off_t offset); + +/** + * Frees all memory internally allocated by the module. + * Upon return the lto_module_t is no longer valid. + * + * \since prior to LTO_API_VERSION=3 + */ +extern void +lto_module_dispose(lto_module_t mod); + +/** + * Returns triple string which the object module was compiled under. + * + * \since prior to LTO_API_VERSION=3 + */ +extern const char* +lto_module_get_target_triple(lto_module_t mod); + +/** + * Sets triple string with which the object will be codegened. + * + * \since LTO_API_VERSION=4 + */ +extern void +lto_module_set_target_triple(lto_module_t mod, const char *triple); + +/** + * Returns the number of symbols in the object module. + * + * \since prior to LTO_API_VERSION=3 + */ +extern unsigned int +lto_module_get_num_symbols(lto_module_t mod); + +/** + * Returns the name of the ith symbol in the object module. + * + * \since prior to LTO_API_VERSION=3 + */ +extern const char* +lto_module_get_symbol_name(lto_module_t mod, unsigned int index); + +/** + * Returns the attributes of the ith symbol in the object module. + * + * \since prior to LTO_API_VERSION=3 + */ +extern lto_symbol_attributes +lto_module_get_symbol_attribute(lto_module_t mod, unsigned int index); + +/** + * Returns the module's linker options. + * + * The linker options may consist of multiple flags. It is the linker's + * responsibility to split the flags using a platform-specific mechanism. + * + * \since LTO_API_VERSION=16 + */ +extern const char* +lto_module_get_linkeropts(lto_module_t mod); + +/** + * Diagnostic severity. + * + * \since LTO_API_VERSION=7 + */ +typedef enum { + LTO_DS_ERROR = 0, + LTO_DS_WARNING = 1, + LTO_DS_REMARK = 3, // Added in LTO_API_VERSION=10. + LTO_DS_NOTE = 2 +} lto_codegen_diagnostic_severity_t; + +/** + * Diagnostic handler type. + * \p severity defines the severity. + * \p diag is the actual diagnostic. + * The diagnostic is not prefixed by any of severity keyword, e.g., 'error: '. + * \p ctxt is used to pass the context set with the diagnostic handler. + * + * \since LTO_API_VERSION=7 + */ +typedef void (*lto_diagnostic_handler_t)( + lto_codegen_diagnostic_severity_t severity, const char *diag, void *ctxt); + +/** + * Set a diagnostic handler and the related context (void *). + * This is more general than lto_get_error_message, as the diagnostic handler + * can be called at anytime within lto. + * + * \since LTO_API_VERSION=7 + */ +extern void lto_codegen_set_diagnostic_handler(lto_code_gen_t, + lto_diagnostic_handler_t, + void *); + +/** + * Instantiates a code generator. + * Returns NULL on error (check lto_get_error_message() for details). + * + * All modules added using \a lto_codegen_add_module() must have been created + * in the same context as the codegen. + * + * \since prior to LTO_API_VERSION=3 + */ +extern lto_code_gen_t +lto_codegen_create(void); + +/** + * Instantiate a code generator in its own context. + * + * Instantiates a code generator in its own context. Modules added via \a + * lto_codegen_add_module() must have all been created in the same context, + * using \a lto_module_create_in_codegen_context(). + * + * \since LTO_API_VERSION=11 + */ +extern lto_code_gen_t +lto_codegen_create_in_local_context(void); + +/** + * Frees all code generator and all memory it internally allocated. + * Upon return the lto_code_gen_t is no longer valid. + * + * \since prior to LTO_API_VERSION=3 + */ +extern void +lto_codegen_dispose(lto_code_gen_t); + +/** + * Add an object module to the set of modules for which code will be generated. + * Returns true on error (check lto_get_error_message() for details). + * + * \c cg and \c mod must both be in the same context. See \a + * lto_codegen_create_in_local_context() and \a + * lto_module_create_in_codegen_context(). + * + * \since prior to LTO_API_VERSION=3 + */ +extern lto_bool_t +lto_codegen_add_module(lto_code_gen_t cg, lto_module_t mod); + +/** + * Sets the object module for code generation. This will transfer the ownership + * of the module to the code generator. + * + * \c cg and \c mod must both be in the same context. + * + * \since LTO_API_VERSION=13 + */ +extern void +lto_codegen_set_module(lto_code_gen_t cg, lto_module_t mod); + +/** + * Sets if debug info should be generated. + * Returns true on error (check lto_get_error_message() for details). + * + * \since prior to LTO_API_VERSION=3 + */ +extern lto_bool_t +lto_codegen_set_debug_model(lto_code_gen_t cg, lto_debug_model); + +/** + * Sets which PIC code model to generated. + * Returns true on error (check lto_get_error_message() for details). + * + * \since prior to LTO_API_VERSION=3 + */ +extern lto_bool_t +lto_codegen_set_pic_model(lto_code_gen_t cg, lto_codegen_model); + +/** + * Sets the cpu to generate code for. + * + * \since LTO_API_VERSION=4 + */ +extern void +lto_codegen_set_cpu(lto_code_gen_t cg, const char *cpu); + +/** + * Sets the location of the assembler tool to run. If not set, libLTO + * will use gcc to invoke the assembler. + * + * \since LTO_API_VERSION=3 + */ +extern void +lto_codegen_set_assembler_path(lto_code_gen_t cg, const char* path); + +/** + * Sets extra arguments that libLTO should pass to the assembler. + * + * \since LTO_API_VERSION=4 + */ +extern void +lto_codegen_set_assembler_args(lto_code_gen_t cg, const char **args, + int nargs); + +/** + * Adds to a list of all global symbols that must exist in the final generated + * code. If a function is not listed there, it might be inlined into every usage + * and optimized away. + * + * \since prior to LTO_API_VERSION=3 + */ +extern void +lto_codegen_add_must_preserve_symbol(lto_code_gen_t cg, const char* symbol); + +/** + * Writes a new object file at the specified path that contains the + * merged contents of all modules added so far. + * Returns true on error (check lto_get_error_message() for details). + * + * \since LTO_API_VERSION=5 + */ +extern lto_bool_t +lto_codegen_write_merged_modules(lto_code_gen_t cg, const char* path); + +/** + * Generates code for all added modules into one native object file. + * This calls lto_codegen_optimize then lto_codegen_compile_optimized. + * + * On success returns a pointer to a generated mach-o/ELF buffer and + * length set to the buffer size. The buffer is owned by the + * lto_code_gen_t and will be freed when lto_codegen_dispose() + * is called, or lto_codegen_compile() is called again. + * On failure, returns NULL (check lto_get_error_message() for details). + * + * \since prior to LTO_API_VERSION=3 + */ +extern const void* +lto_codegen_compile(lto_code_gen_t cg, size_t* length); + +/** + * Generates code for all added modules into one native object file. + * This calls lto_codegen_optimize then lto_codegen_compile_optimized (instead + * of returning a generated mach-o/ELF buffer, it writes to a file). + * + * The name of the file is written to name. Returns true on error. + * + * \since LTO_API_VERSION=5 + */ +extern lto_bool_t +lto_codegen_compile_to_file(lto_code_gen_t cg, const char** name); + +/** + * Runs optimization for the merged module. Returns true on error. + * + * \since LTO_API_VERSION=12 + */ +extern lto_bool_t +lto_codegen_optimize(lto_code_gen_t cg); + +/** + * Generates code for the optimized merged module into one native object file. + * It will not run any IR optimizations on the merged module. + * + * On success returns a pointer to a generated mach-o/ELF buffer and length set + * to the buffer size. The buffer is owned by the lto_code_gen_t and will be + * freed when lto_codegen_dispose() is called, or + * lto_codegen_compile_optimized() is called again. On failure, returns NULL + * (check lto_get_error_message() for details). + * + * \since LTO_API_VERSION=12 + */ +extern const void* +lto_codegen_compile_optimized(lto_code_gen_t cg, size_t* length); + +/** + * Returns the runtime API version. + * + * \since LTO_API_VERSION=12 + */ +extern unsigned int +lto_api_version(void); + +/** + * Sets options to help debug codegen bugs. + * + * \since prior to LTO_API_VERSION=3 + */ +extern void +lto_codegen_debug_options(lto_code_gen_t cg, const char *); + +/** + * Initializes LLVM disassemblers. + * FIXME: This doesn't really belong here. + * + * \since LTO_API_VERSION=5 + */ +extern void +lto_initialize_disassembler(void); + +/** + * Sets if we should run internalize pass during optimization and code + * generation. + * + * \since LTO_API_VERSION=14 + */ +extern void +lto_codegen_set_should_internalize(lto_code_gen_t cg, + lto_bool_t ShouldInternalize); + +/** + * Set whether to embed uselists in bitcode. + * + * Sets whether \a lto_codegen_write_merged_modules() should embed uselists in + * output bitcode. This should be turned on for all -save-temps output. + * + * \since LTO_API_VERSION=15 + */ +extern void +lto_codegen_set_should_embed_uselists(lto_code_gen_t cg, + lto_bool_t ShouldEmbedUselists); + +/** + * @} // endgoup LLVMCLTO + * @defgroup LLVMCTLTO ThinLTO + * @ingroup LLVMC + * + * @{ + */ + +/** + * Type to wrap a single object returned by ThinLTO. + * + * \since LTO_API_VERSION=18 + */ +typedef struct { + const char *Buffer; + size_t Size; +} LTOObjectBuffer; + +/** + * Instantiates a ThinLTO code generator. + * Returns NULL on error (check lto_get_error_message() for details). + * + * + * The ThinLTOCodeGenerator is not intended to be reuse for multiple + * compilation: the model is that the client adds modules to the generator and + * ask to perform the ThinLTO optimizations / codegen, and finally destroys the + * codegenerator. + * + * \since LTO_API_VERSION=18 + */ +extern thinlto_code_gen_t thinlto_create_codegen(void); + +/** + * Frees the generator and all memory it internally allocated. + * Upon return the thinlto_code_gen_t is no longer valid. + * + * \since LTO_API_VERSION=18 + */ +extern void thinlto_codegen_dispose(thinlto_code_gen_t cg); + +/** + * Add a module to a ThinLTO code generator. Identifier has to be unique among + * all the modules in a code generator. The data buffer stays owned by the + * client, and is expected to be available for the entire lifetime of the + * thinlto_code_gen_t it is added to. + * + * On failure, returns NULL (check lto_get_error_message() for details). + * + * + * \since LTO_API_VERSION=18 + */ +extern void thinlto_codegen_add_module(thinlto_code_gen_t cg, + const char *identifier, const char *data, + int length); + +/** + * Optimize and codegen all the modules added to the codegenerator using + * ThinLTO. Resulting objects are accessible using thinlto_module_get_object(). + * + * \since LTO_API_VERSION=18 + */ +extern void thinlto_codegen_process(thinlto_code_gen_t cg); + +/** + * Returns the number of object files produced by the ThinLTO CodeGenerator. + * + * It usually matches the number of input files, but this is not a guarantee of + * the API and may change in future implementation, so the client should not + * assume it. + * + * \since LTO_API_VERSION=18 + */ +extern unsigned int thinlto_module_get_num_objects(thinlto_code_gen_t cg); + +/** + * Returns a reference to the ith object file produced by the ThinLTO + * CodeGenerator. + * + * Client should use \p thinlto_module_get_num_objects() to get the number of + * available objects. + * + * \since LTO_API_VERSION=18 + */ +extern LTOObjectBuffer thinlto_module_get_object(thinlto_code_gen_t cg, + unsigned int index); + +/** + * Returns the number of object files produced by the ThinLTO CodeGenerator. + * + * It usually matches the number of input files, but this is not a guarantee of + * the API and may change in future implementation, so the client should not + * assume it. + * + * \since LTO_API_VERSION=21 + */ +unsigned int thinlto_module_get_num_object_files(thinlto_code_gen_t cg); + +/** + * Returns the path to the ith object file produced by the ThinLTO + * CodeGenerator. + * + * Client should use \p thinlto_module_get_num_object_files() to get the number + * of available objects. + * + * \since LTO_API_VERSION=21 + */ +const char *thinlto_module_get_object_file(thinlto_code_gen_t cg, + unsigned int index); + +/** + * Sets which PIC code model to generate. + * Returns true on error (check lto_get_error_message() for details). + * + * \since LTO_API_VERSION=18 + */ +extern lto_bool_t thinlto_codegen_set_pic_model(thinlto_code_gen_t cg, + lto_codegen_model); + +/** + * Sets the path to a directory to use as a storage for temporary bitcode files. + * The intention is to make the bitcode files available for debugging at various + * stage of the pipeline. + * + * \since LTO_API_VERSION=18 + */ +extern void thinlto_codegen_set_savetemps_dir(thinlto_code_gen_t cg, + const char *save_temps_dir); + +/** + * Set the path to a directory where to save generated object files. This + * path can be used by a linker to request on-disk files instead of in-memory + * buffers. When set, results are available through + * thinlto_module_get_object_file() instead of thinlto_module_get_object(). + * + * \since LTO_API_VERSION=21 + */ +void thinlto_set_generated_objects_dir(thinlto_code_gen_t cg, + const char *save_temps_dir); + +/** + * Sets the cpu to generate code for. + * + * \since LTO_API_VERSION=18 + */ +extern void thinlto_codegen_set_cpu(thinlto_code_gen_t cg, const char *cpu); + +/** + * Disable CodeGen, only run the stages till codegen and stop. The output will + * be bitcode. + * + * \since LTO_API_VERSION=19 + */ +extern void thinlto_codegen_disable_codegen(thinlto_code_gen_t cg, + lto_bool_t disable); + +/** + * Perform CodeGen only: disable all other stages. + * + * \since LTO_API_VERSION=19 + */ +extern void thinlto_codegen_set_codegen_only(thinlto_code_gen_t cg, + lto_bool_t codegen_only); + +/** + * Parse -mllvm style debug options. + * + * \since LTO_API_VERSION=18 + */ +extern void thinlto_debug_options(const char *const *options, int number); + +/** + * Test if a module has support for ThinLTO linking. + * + * \since LTO_API_VERSION=18 + */ +extern lto_bool_t lto_module_is_thinlto(lto_module_t mod); + +/** + * Adds a symbol to the list of global symbols that must exist in the final + * generated code. If a function is not listed there, it might be inlined into + * every usage and optimized away. For every single module, the functions + * referenced from code outside of the ThinLTO modules need to be added here. + * + * \since LTO_API_VERSION=18 + */ +extern void thinlto_codegen_add_must_preserve_symbol(thinlto_code_gen_t cg, + const char *name, + int length); + +/** + * Adds a symbol to the list of global symbols that are cross-referenced between + * ThinLTO files. If the ThinLTO CodeGenerator can ensure that every + * references from a ThinLTO module to this symbol is optimized away, then + * the symbol can be discarded. + * + * \since LTO_API_VERSION=18 + */ +extern void thinlto_codegen_add_cross_referenced_symbol(thinlto_code_gen_t cg, + const char *name, + int length); + +/** + * @} // endgoup LLVMCTLTO + * @defgroup LLVMCTLTO_CACHING ThinLTO Cache Control + * @ingroup LLVMCTLTO + * + * These entry points control the ThinLTO cache. The cache is intended to + * support incremental builds, and thus needs to be persistent across builds. + * The client enables the cache by supplying a path to an existing directory. + * The code generator will use this to store objects files that may be reused + * during a subsequent build. + * To avoid filling the disk space, a few knobs are provided: + * - The pruning interval limits the frequency at which the garbage collector + * will try to scan the cache directory to prune expired entries. + * Setting to a negative number disables the pruning. + * - The pruning expiration time indicates to the garbage collector how old an + * entry needs to be to be removed. + * - Finally, the garbage collector can be instructed to prune the cache until + * the occupied space goes below a threshold. + * @{ + */ + +/** + * Sets the path to a directory to use as a cache storage for incremental build. + * Setting this activates caching. + * + * \since LTO_API_VERSION=18 + */ +extern void thinlto_codegen_set_cache_dir(thinlto_code_gen_t cg, + const char *cache_dir); + +/** + * Sets the cache pruning interval (in seconds). A negative value disables the + * pruning. An unspecified default value will be applied, and a value of 0 will + * force prunning to occur. + * + * \since LTO_API_VERSION=18 + */ +extern void thinlto_codegen_set_cache_pruning_interval(thinlto_code_gen_t cg, + int interval); + +/** + * Sets the maximum cache size that can be persistent across build, in terms of + * percentage of the available space on the disk. Set to 100 to indicate + * no limit, 50 to indicate that the cache size will not be left over half the + * available space. A value over 100 will be reduced to 100, a value of 0 will + * be ignored. An unspecified default value will be applied. + * + * The formula looks like: + * AvailableSpace = FreeSpace + ExistingCacheSize + * NewCacheSize = AvailableSpace * P/100 + * + * \since LTO_API_VERSION=18 + */ +extern void thinlto_codegen_set_final_cache_size_relative_to_available_space( + thinlto_code_gen_t cg, unsigned percentage); + +/** + * Sets the expiration (in seconds) for an entry in the cache. An unspecified + * default value will be applied. A value of 0 will be ignored. + * + * \since LTO_API_VERSION=18 + */ +extern void thinlto_codegen_set_cache_entry_expiration(thinlto_code_gen_t cg, + unsigned expiration); + +/** + * Sets the maximum size of the cache directory (in bytes). A value over the + * amount of available space on the disk will be reduced to the amount of + * available space. An unspecified default value will be applied. A value of 0 + * will be ignored. + * + * \since LTO_API_VERSION=22 + */ +extern void thinlto_codegen_set_cache_size_bytes(thinlto_code_gen_t cg, + unsigned max_size_bytes); + +/** + * Same as thinlto_codegen_set_cache_size_bytes, except the maximum size is in + * megabytes (2^20 bytes). + * + * \since LTO_API_VERSION=23 + */ +extern void +thinlto_codegen_set_cache_size_megabytes(thinlto_code_gen_t cg, + unsigned max_size_megabytes); + +/** + * Sets the maximum number of files in the cache directory. An unspecified + * default value will be applied. A value of 0 will be ignored. + * + * \since LTO_API_VERSION=22 + */ +extern void thinlto_codegen_set_cache_size_files(thinlto_code_gen_t cg, + unsigned max_size_files); + +/** Opaque reference to an LTO input file */ +typedef struct LLVMOpaqueLTOInput *lto_input_t; + +/** + * Creates an LTO input file from a buffer. The path + * argument is used for diagnotics as this function + * otherwise does not know which file the given buffer + * is associated with. + * + * \since LTO_API_VERSION=24 + */ +extern lto_input_t lto_input_create(const void *buffer, + size_t buffer_size, + const char *path); + +/** + * Frees all memory internally allocated by the LTO input file. + * Upon return the lto_module_t is no longer valid. + * + * \since LTO_API_VERSION=24 + */ +extern void lto_input_dispose(lto_input_t input); + +/** + * Returns the number of dependent library specifiers + * for the given LTO input file. + * + * \since LTO_API_VERSION=24 + */ +extern unsigned lto_input_get_num_dependent_libraries(lto_input_t input); + +/** + * Returns the ith dependent library specifier + * for the given LTO input file. The returned + * string is not null-terminated. + * + * \since LTO_API_VERSION=24 + */ +extern const char * lto_input_get_dependent_library(lto_input_t input, + size_t index, + size_t *size); + +/** + * @} // endgroup LLVMCTLTO_CACHING + */ + +#ifdef __cplusplus +} +#endif + +#endif /* LLVM_C_LTO_H */ diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp new file mode 100644 index 000000000..520eff313 --- /dev/null +++ b/src/llvm_backend.cpp @@ -0,0 +1,11024 @@ +#include "llvm_backend.hpp" + +gb_global lbAddr lb_global_type_info_data = {}; +gb_global lbAddr lb_global_type_info_member_types = {}; +gb_global lbAddr lb_global_type_info_member_names = {}; +gb_global lbAddr lb_global_type_info_member_offsets = {}; +gb_global lbAddr lb_global_type_info_member_usings = {}; +gb_global lbAddr lb_global_type_info_member_tags = {}; + +gb_global isize lb_global_type_info_data_index = 0; +gb_global isize lb_global_type_info_member_types_index = 0; +gb_global isize lb_global_type_info_member_names_index = 0; +gb_global isize lb_global_type_info_member_offsets_index = 0; +gb_global isize lb_global_type_info_member_usings_index = 0; +gb_global isize lb_global_type_info_member_tags_index = 0; + + +struct lbLoopData { + lbAddr idx_addr; + lbValue idx; + lbBlock *body; + lbBlock *done; + lbBlock *loop; +}; + +struct lbCompoundLitElemTempData { + Ast * expr; + lbValue value; + i32 elem_index; + lbValue gep; +}; + +lbLoopData lb_loop_start(lbProcedure *p, isize count, Type *index_type=t_i32); +void lb_loop_end(lbProcedure *p, lbLoopData const &data); + +LLVMValueRef llvm_zero32(lbModule *m) { + return LLVMConstInt(lb_type(m, t_i32), 0, false); +} +LLVMValueRef llvm_one32(lbModule *m) { + return LLVMConstInt(lb_type(m, t_i32), 1, false); +} + +lbValue lb_zero(lbModule *m, Type *t) { + lbValue v = {}; + v.value = LLVMConstInt(lb_type(m, t), 0, false); + v.type = t; + return v; +} + +LLVMValueRef llvm_cstring(lbModule *m, String const &str) { + lbValue v = lb_find_or_add_entity_string(m, str); + unsigned indices[1] = {0}; + return LLVMConstExtractValue(v.value, indices, gb_count_of(indices)); +} + + +lbAddr lb_addr(lbValue addr) { + lbAddr v = {lbAddr_Default, addr}; + return v; +} + + +lbAddr lb_addr_map(lbValue addr, lbValue map_key, Type *map_type, Type *map_result) { + lbAddr v = {lbAddr_Map, addr}; + v.map.key = map_key; + v.map.type = map_type; + v.map.result = map_result; + return v; +} + + +lbAddr lb_addr_soa_variable(lbValue addr, lbValue index, Ast *index_expr) { + lbAddr v = {lbAddr_SoaVariable, addr}; + v.soa.index = index; + v.soa.index_expr = index_expr; + return v; +} + +lbAddr lb_addr_bit_field(lbValue value, i32 index) { + lbAddr addr = {}; + addr.kind = lbAddr_BitField; + addr.addr = value; + addr.bit_field.value_index = index; + return addr; +} + + +Type *lb_addr_type(lbAddr const &addr) { + if (addr.addr.value == nullptr) { + return nullptr; + } + if (addr.kind == lbAddr_Map) { + Type *t = base_type(addr.map.type); + GB_ASSERT(is_type_map(t)); + return t->Map.value; + } + return type_deref(addr.addr.type); +} +LLVMTypeRef lb_addr_lb_type(lbAddr const &addr) { + return LLVMGetElementType(LLVMTypeOf(addr.addr.value)); +} + +lbValue lb_addr_get_ptr(lbProcedure *p, lbAddr const &addr) { + if (addr.addr.value == nullptr) { + GB_PANIC("Illegal addr -> nullptr"); + return {}; + } + + switch (addr.kind) { + case lbAddr_Map: { + Type *map_type = base_type(addr.map.type); + lbValue h = lb_gen_map_header(p, addr.addr, map_type); + lbValue key = lb_gen_map_key(p, addr.map.key, map_type->Map.key); + + auto args = array_make(heap_allocator(), 2); + args[0] = h; + args[1] = key; + + lbValue ptr = lb_emit_runtime_call(p, "__dynamic_map_get", args); + + return lb_emit_conv(p, ptr, alloc_type_pointer(map_type->Map.value)); + } + case lbAddr_BitField: { + lbValue v = lb_addr_load(p, addr); + return lb_address_from_load_or_generate_local(p, v); + } + + case lbAddr_Context: + GB_PANIC("lbAddr_Context should be handled elsewhere"); + } + + return addr.addr; +} + + +lbValue lb_build_addr_ptr(lbProcedure *p, Ast *expr) { + lbAddr addr = lb_build_addr(p, expr); + return lb_addr_get_ptr(p, addr); +} + + + +void lb_addr_store(lbProcedure *p, lbAddr const &addr, lbValue value) { + if (addr.addr.value == nullptr) { + return; + } + GB_ASSERT(value.type != nullptr); + if (is_type_untyped_undef(value.type)) { + Type *t = lb_addr_type(addr); + value.type = t; + value.value = LLVMGetUndef(lb_type(p->module, t)); + } else if (is_type_untyped_nil(value.type)) { + Type *t = lb_addr_type(addr); + value.type = t; + value.value = LLVMConstNull(lb_type(p->module, t)); + } + + + if (addr.kind == lbAddr_Map) { + lb_insert_dynamic_map_key_and_value(p, addr, addr.map.type, addr.map.key, value); + return; + } else if (addr.kind == lbAddr_BitField) { + Type *bft = base_type(type_deref(addr.addr.type)); + GB_ASSERT(is_type_bit_field(bft)); + + unsigned value_index = cast(unsigned)addr.bit_field.value_index; + i32 size_in_bits = bft->BitField.fields[value_index]->type->BitFieldValue.bits; + if (size_in_bits == 0) { + return; + } + i32 size_in_bytes = next_pow2((size_in_bits+7)/8); + + LLVMTypeRef dst_type = LLVMIntTypeInContext(p->module->ctx, size_in_bits); + LLVMValueRef src = LLVMBuildIntCast2(p->builder, value.value, dst_type, false, ""); + + LLVMValueRef internal_data = LLVMBuildStructGEP(p->builder, addr.addr.value, 1, ""); + LLVMValueRef field_ptr = LLVMBuildStructGEP(p->builder, internal_data, value_index, ""); + LLVMBuildStore(p->builder, src, field_ptr); + return; + } else if (addr.kind == lbAddr_Context) { + lbValue old = lb_addr_load(p, lb_find_or_generate_context_ptr(p)); + lbAddr next_addr = lb_add_local_generated(p, t_context, true); + lb_addr_store(p, next_addr, old); + lb_push_context_onto_stack(p, next_addr); + lbValue next = lb_addr_get_ptr(p, next_addr); + + if (addr.ctx.sel.index.count > 0) { + lbValue lhs = lb_emit_deep_field_gep(p, next, addr.ctx.sel); + lbValue rhs = lb_emit_conv(p, value, type_deref(lhs.type)); + lb_emit_store(p, lhs, rhs); + } else { + lbValue lhs = next; + lbValue rhs = lb_emit_conv(p, value, lb_addr_type(addr)); + lb_emit_store(p, lhs, rhs); + } + + return; + } else if (addr.kind == lbAddr_SoaVariable) { + Type *t = type_deref(addr.addr.type); + t = base_type(t); + GB_ASSERT(t->kind == Type_Struct && t->Struct.soa_kind != StructSoa_None); + value = lb_emit_conv(p, value, t->Struct.soa_elem); + + lbValue index = addr.soa.index; + if (!lb_is_const(index) || t->Struct.soa_kind != StructSoa_Fixed) { + Type *t = base_type(type_deref(addr.addr.type)); + GB_ASSERT(t->kind == Type_Struct && t->Struct.soa_kind != StructSoa_None); + i64 count = t->Struct.soa_count; + lbValue len = lb_const_int(p->module, t_int, count); + // lb_emit_bounds_check(p, ast_token(addr.soa.index_expr), index, len); + } + + for_array(i, t->Struct.fields) { + lbValue dst = lb_emit_struct_ep(p, addr.addr, cast(i32)i); + dst = lb_emit_array_ep(p, dst, index); + lbValue src = lb_emit_struct_ev(p, value, cast(i32)i); + lb_emit_store(p, dst, src); + } + return; + } + + GB_ASSERT(value.value != nullptr); + value = lb_emit_conv(p, value, lb_addr_type(addr)); + + LLVMBuildStore(p->builder, value.value, addr.addr.value); +} + +void lb_const_store(lbValue ptr, lbValue value) { + GB_ASSERT(lb_is_const(ptr)); + GB_ASSERT(lb_is_const(value)); + GB_ASSERT(is_type_pointer(ptr.type)); + LLVMSetInitializer(ptr.value, value.value); +} + + +void lb_emit_store(lbProcedure *p, lbValue ptr, lbValue value) { + GB_ASSERT(value.value != nullptr); + Type *a = type_deref(ptr.type); + if (is_type_boolean(a)) { + // NOTE(bill): There are multiple sized booleans, thus force a conversion (if necessarily) + value = lb_emit_conv(p, value, a); + } + Type *ca = core_type(a); + if (ca->kind == Type_Basic) { + GB_ASSERT_MSG(are_types_identical(ca, core_type(value.type)), "%s != %s", type_to_string(a), type_to_string(value.type)); + } else { + GB_ASSERT_MSG(are_types_identical(a, value.type), "%s != %s", type_to_string(a), type_to_string(value.type)); + } + + LLVMBuildStore(p->builder, value.value, ptr.value); +} + +lbValue lb_emit_load(lbProcedure *p, lbValue value) { + lbModule *m = p->module; + GB_ASSERT(value.value != nullptr); + Type *t = type_deref(value.type); + LLVMValueRef v = LLVMBuildLoad2(p->builder, lb_type(m, t), value.value, ""); + return lbValue{v, t}; +} + +lbValue lb_addr_load(lbProcedure *p, lbAddr const &addr) { + GB_ASSERT(addr.addr.value != nullptr); + + if (addr.kind == lbAddr_Map) { + Type *map_type = base_type(addr.map.type); + lbAddr v = lb_add_local_generated(p, map_type->Map.lookup_result_type, true); + lbValue h = lb_gen_map_header(p, addr.addr, map_type); + lbValue key = lb_gen_map_key(p, addr.map.key, map_type->Map.key); + + auto args = array_make(heap_allocator(), 2); + args[0] = h; + args[1] = key; + + lbValue ptr = lb_emit_runtime_call(p, "__dynamic_map_get", args); + lbValue ok = lb_emit_conv(p, lb_emit_comp_against_nil(p, Token_NotEq, ptr), t_bool); + lb_emit_store(p, lb_emit_struct_ep(p, v.addr, 1), ok); + + lbBlock *then = lb_create_block(p, "map.get.then"); + lbBlock *done = lb_create_block(p, "map.get.done"); + lb_emit_if(p, ok, then, done); + lb_start_block(p, then); + { + // TODO(bill): mem copy it instead? + lbValue gep0 = lb_emit_struct_ep(p, v.addr, 0); + lbValue value = lb_emit_conv(p, ptr, gep0.type); + lb_emit_store(p, gep0, lb_emit_load(p, value)); + } + lb_emit_jump(p, done); + lb_start_block(p, done); + + + if (is_type_tuple(addr.map.result)) { + return lb_addr_load(p, v); + } else { + lbValue single = lb_emit_struct_ep(p, v.addr, 0); + return lb_emit_load(p, single); + } + + } else if (addr.kind == lbAddr_BitField) { + Type *bft = base_type(type_deref(addr.addr.type)); + GB_ASSERT(is_type_bit_field(bft)); + + unsigned value_index = cast(unsigned)addr.bit_field.value_index; + i32 size_in_bits = bft->BitField.fields[value_index]->type->BitFieldValue.bits; + + i32 size_in_bytes = next_pow2((size_in_bits+7)/8); + if (size_in_bytes == 0) { + GB_ASSERT(size_in_bits == 0); + lbValue res = {}; + res.type = t_i32; + res.value = LLVMConstInt(lb_type(p->module, res.type), 0, false); + return res; + } + + Type *int_type = nullptr; + switch (size_in_bytes) { + case 1: int_type = t_u8; break; + case 2: int_type = t_u16; break; + case 4: int_type = t_u32; break; + case 8: int_type = t_u64; break; + case 16: int_type = t_u128; break; + } + GB_ASSERT(int_type != nullptr); + + LLVMValueRef internal_data = LLVMBuildStructGEP(p->builder, addr.addr.value, 1, ""); + LLVMValueRef field_ptr = LLVMBuildStructGEP(p->builder, internal_data, value_index, ""); + LLVMValueRef field = LLVMBuildLoad(p->builder, field_ptr, ""); + + lbValue res = {}; + res.type = int_type; + res.value = LLVMBuildZExtOrBitCast(p->builder, field, lb_type(p->module, int_type), ""); + return res; + } else if (addr.kind == lbAddr_Context) { + if (addr.ctx.sel.index.count > 0) { + 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); + t = base_type(t); + GB_ASSERT(t->kind == Type_Struct && t->Struct.soa_kind != StructSoa_None); + Type *elem = t->Struct.soa_elem; + + lbValue len = {}; + if (t->Struct.soa_kind == StructSoa_Fixed) { + len = lb_const_int(p->module, t_int, t->Struct.soa_count); + } else { + lbValue v = lb_emit_load(p, addr.addr); + len = lb_soa_struct_len(p, v); + } + + lbAddr res = lb_add_local_generated(p, elem, true); + + if (!lb_is_const(addr.soa.index) || t->Struct.soa_kind != StructSoa_Fixed) { + // lb_emit_bounds_check(p, ast_token(addr.soa.index_expr), addr.soa.index, len); + } + + if (t->Struct.soa_kind == StructSoa_Fixed) { + for_array(i, t->Struct.fields) { + Entity *field = t->Struct.fields[i]; + Type *base_type = field->type; + GB_ASSERT(base_type->kind == Type_Array); + + lbValue dst = lb_emit_struct_ep(p, res.addr, cast(i32)i); + lbValue src_ptr = lb_emit_struct_ep(p, addr.addr, cast(i32)i); + src_ptr = lb_emit_array_ep(p, src_ptr, addr.soa.index); + lbValue src = lb_emit_load(p, src_ptr); + lb_emit_store(p, dst, src); + } + } else { + isize field_count = t->Struct.fields.count; + if (t->Struct.soa_kind == StructSoa_Slice) { + field_count -= 1; + } else if (t->Struct.soa_kind == StructSoa_Dynamic) { + field_count -= 3; + } + for (isize i = 0; i < field_count; i++) { + Entity *field = t->Struct.fields[i]; + Type *base_type = field->type; + GB_ASSERT(base_type->kind == Type_Pointer); + Type *elem = base_type->Pointer.elem; + + lbValue dst = lb_emit_struct_ep(p, res.addr, cast(i32)i); + lbValue src_ptr = lb_emit_struct_ep(p, addr.addr, cast(i32)i); + src_ptr = lb_emit_ptr_offset(p, src_ptr, addr.soa.index); + lbValue src = lb_emit_load(p, src_ptr); + src = lb_emit_load(p, src); + lb_emit_store(p, dst, src); + } + } + + return lb_addr_load(p, res); + } + + if (is_type_proc(addr.addr.type)) { + return addr.addr; + } + return lb_emit_load(p, addr.addr); +} + +lbValue lb_const_union_tag(lbModule *m, Type *u, Type *v) { + return lb_const_value(m, union_tag_type(u), exact_value_i64(union_variant_index(u, v))); +} + +lbValue lb_emit_union_tag_ptr(lbProcedure *p, lbValue u) { + Type *t = u.type; + GB_ASSERT_MSG(is_type_pointer(t) && + is_type_union(type_deref(t)), "%s", type_to_string(t)); + Type *ut = type_deref(t); + + GB_ASSERT(!is_type_union_maybe_pointer_original_alignment(ut)); + GB_ASSERT(!is_type_union_maybe_pointer(ut)); + GB_ASSERT(type_size_of(ut) > 0); + + Type *tag_type = union_tag_type(ut); + + LLVMTypeRef uvt = LLVMGetElementType(LLVMTypeOf(u.value)); + unsigned element_count = LLVMCountStructElementTypes(uvt); + GB_ASSERT_MSG(element_count == 3, "(%s) != (%s)", type_to_string(ut), LLVMPrintTypeToString(uvt)); + + lbValue tag_ptr = {}; + tag_ptr.value = LLVMBuildStructGEP(p->builder, u.value, 2, ""); + tag_ptr.type = alloc_type_pointer(tag_type); + return tag_ptr; +} + +lbValue lb_emit_union_tag_value(lbProcedure *p, lbValue u) { + lbValue ptr = lb_address_from_load_or_generate_local(p, u); + lbValue tag_ptr = lb_emit_union_tag_ptr(p, ptr); + return lb_emit_load(p, tag_ptr); +} + + +void lb_emit_store_union_variant_tag(lbProcedure *p, lbValue parent, Type *variant_type) { + Type *t = type_deref(parent.type); + + if (is_type_union_maybe_pointer(t) || type_size_of(t) == 0) { + // No tag needed! + } else { + lbValue tag_ptr = lb_emit_union_tag_ptr(p, parent); + lb_emit_store(p, tag_ptr, lb_const_union_tag(p->module, t, variant_type)); + } +} + +void lb_emit_store_union_variant(lbProcedure *p, lbValue parent, lbValue variant, Type *variant_type) { + gbAllocator a = heap_allocator(); + lbValue underlying = lb_emit_conv(p, parent, alloc_type_pointer(variant_type)); + + lb_emit_store(p, underlying, variant); + lb_emit_store_union_variant_tag(p, parent, variant_type); +} + + +void lb_clone_struct_type(LLVMTypeRef dst, LLVMTypeRef src) { + unsigned field_count = LLVMCountStructElementTypes(src); + LLVMTypeRef *fields = gb_alloc_array(heap_allocator(), LLVMTypeRef, field_count); + LLVMGetStructElementTypes(src, fields); + LLVMStructSetBody(dst, fields, field_count, LLVMIsPackedStruct(src)); + gb_free(heap_allocator(), fields); +} + +LLVMTypeRef lb_alignment_prefix_type_hack(lbModule *m, i64 alignment) { + switch (alignment) { + case 1: + return LLVMArrayType(lb_type(m, t_u8), 0); + case 2: + return LLVMArrayType(lb_type(m, t_u16), 0); + case 4: + return LLVMArrayType(lb_type(m, t_u32), 0); + case 8: + return LLVMArrayType(lb_type(m, t_u64), 0); + case 16: + return LLVMArrayType(LLVMVectorType(lb_type(m, t_u32), 4), 0); + default: + GB_PANIC("Invalid alignment %d", cast(i32)alignment); + break; + } + return nullptr; +} + +bool lb_is_elem_const(Ast *elem, Type *elem_type) { + if (!elem_type_can_be_constant(elem_type)) { + return false; + } + if (elem->kind == Ast_FieldValue) { + elem = elem->FieldValue.value; + } + TypeAndValue tav = type_and_value_of_expr(elem); + GB_ASSERT_MSG(tav.mode != Addressing_Invalid, "%s %s", expr_to_string(elem), type_to_string(tav.type)); + return tav.value.kind != ExactValue_Invalid; +} + +String lb_mangle_name(lbModule *m, Entity *e) { + gbAllocator a = heap_allocator(); + + String name = e->token.string; + + AstPackage *pkg = e->pkg; + GB_ASSERT_MSG(pkg != nullptr, "Missing package for '%.*s'", LIT(name)); + String pkgn = pkg->name; + GB_ASSERT(!rune_is_digit(pkgn[0])); + + + isize max_len = pkgn.len + 1 + name.len + 1; + bool require_suffix_id = is_type_polymorphic(e->type, true); + + if ((e->scope->flags & (ScopeFlag_File | ScopeFlag_Pkg)) == 0) { + require_suffix_id = true; + } else if (is_blank_ident(e->token)) { + require_suffix_id = true; + } + + if (require_suffix_id) { + max_len += 21; + } + + char *new_name = gb_alloc_array(a, char, max_len); + isize new_name_len = gb_snprintf( + new_name, max_len, + "%.*s.%.*s", LIT(pkgn), LIT(name) + ); + if (require_suffix_id) { + char *str = new_name + new_name_len-1; + isize len = max_len-new_name_len; + isize extra = gb_snprintf(str, len, "-%llu", cast(unsigned long long)e->id); + new_name_len += extra-1; + } + + String mangled_name = make_string((u8 const *)new_name, new_name_len-1); + return mangled_name; +} + +String lb_set_nested_type_name_ir_mangled_name(Entity *e, lbProcedure *p) { + // NOTE(bill, 2020-03-08): A polymorphic procedure may take a nested type declaration + // and as a result, the declaration does not have time to determine what it should be + + GB_ASSERT(e != nullptr && e->kind == Entity_TypeName); + if (e->TypeName.ir_mangled_name.len != 0) { + return e->TypeName.ir_mangled_name; + } + GB_ASSERT((e->scope->flags & ScopeFlag_File) == 0); + + if (p == nullptr) { + Entity *proc = nullptr; + if (e->parent_proc_decl != nullptr) { + proc = e->parent_proc_decl->entity; + } else { + Scope *scope = e->scope; + while (scope != nullptr && (scope->flags & ScopeFlag_Proc) == 0) { + scope = scope->parent; + } + GB_ASSERT(scope != nullptr); + GB_ASSERT(scope->flags & ScopeFlag_Proc); + proc = scope->procedure_entity; + } + GB_ASSERT(proc->kind == Entity_Procedure); + GB_ASSERT(proc->code_gen_procedure != nullptr); + p = proc->code_gen_procedure; + } + + // NOTE(bill): Generate a new name + // parent_proc.name-guid + String ts_name = e->token.string; + + lbModule *m = p->module; + isize name_len = p->name.len + 1 + ts_name.len + 1 + 10 + 1; + char *name_text = gb_alloc_array(heap_allocator(), char, name_len); + u32 guid = ++p->module->nested_type_name_guid; + name_len = gb_snprintf(name_text, name_len, "%.*s.%.*s-%u", LIT(p->name), LIT(ts_name), guid); + + String name = make_string(cast(u8 *)name_text, name_len-1); + e->TypeName.ir_mangled_name = name; + return name; +} + + +String lb_get_entity_name(lbModule *m, Entity *e, String default_name) { + if (e != nullptr && e->kind == Entity_TypeName && e->TypeName.ir_mangled_name.len != 0) { + return e->TypeName.ir_mangled_name; + } + GB_ASSERT(e != nullptr); + + if (e->pkg == nullptr) { + return e->token.string; + } + + if (e->kind == Entity_TypeName && (e->scope->flags & ScopeFlag_File) == 0) { + return lb_set_nested_type_name_ir_mangled_name(e, nullptr); + } + + String name = {}; + + bool no_name_mangle = false; + + if (e->kind == Entity_Variable) { + bool is_foreign = e->Variable.is_foreign; + bool is_export = e->Variable.is_export; + no_name_mangle = e->Variable.link_name.len > 0 || is_foreign || is_export; + if (e->Variable.link_name.len > 0) { + return e->Variable.link_name; + } + } else if (e->kind == Entity_Procedure && e->Procedure.link_name.len > 0) { + return e->Procedure.link_name; + } else if (e->kind == Entity_Procedure && e->Procedure.is_export) { + no_name_mangle = true; + } + + if (!no_name_mangle) { + name = lb_mangle_name(m, e); + } + if (name.len == 0) { + name = e->token.string; + } + + if (e->kind == Entity_TypeName) { + if ((e->scope->flags & ScopeFlag_File) == 0) { + gb_printf_err("<<< %.*s %.*s %p\n", LIT(e->token.string), LIT(name), e); + } + + e->TypeName.ir_mangled_name = name; + } else if (e->kind == Entity_Procedure) { + e->Procedure.link_name = name; + } + + return name; +} + +LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { + Type *original_type = type; + + LLVMContextRef ctx = m->ctx; + i64 size = type_size_of(type); // Check size + + GB_ASSERT(type != t_invalid); + + switch (type->kind) { + case Type_Basic: + switch (type->Basic.kind) { + case Basic_llvm_bool: return LLVMInt1TypeInContext(ctx); + case Basic_bool: return LLVMInt8TypeInContext(ctx); + case Basic_b8: return LLVMInt8TypeInContext(ctx); + case Basic_b16: return LLVMInt16TypeInContext(ctx); + case Basic_b32: return LLVMInt32TypeInContext(ctx); + case Basic_b64: return LLVMInt64TypeInContext(ctx); + + case Basic_i8: return LLVMInt8TypeInContext(ctx); + case Basic_u8: return LLVMInt8TypeInContext(ctx); + case Basic_i16: return LLVMInt16TypeInContext(ctx); + case Basic_u16: return LLVMInt16TypeInContext(ctx); + case Basic_i32: return LLVMInt32TypeInContext(ctx); + case Basic_u32: return LLVMInt32TypeInContext(ctx); + case Basic_i64: return LLVMInt64TypeInContext(ctx); + case Basic_u64: return LLVMInt64TypeInContext(ctx); + case Basic_i128: return LLVMInt128TypeInContext(ctx); + case Basic_u128: return LLVMInt128TypeInContext(ctx); + + case Basic_rune: return LLVMInt32TypeInContext(ctx); + + // Basic_f16, + case Basic_f32: return LLVMFloatTypeInContext(ctx); + case Basic_f64: return LLVMDoubleTypeInContext(ctx); + + // Basic_complex32, + case Basic_complex64: + { + char const *name = "..complex64"; + LLVMTypeRef type = LLVMGetTypeByName(m->mod, name); + if (type != nullptr) { + return type; + } + type = LLVMStructCreateNamed(ctx, name); + LLVMTypeRef fields[2] = { + lb_type(m, t_f32), + lb_type(m, t_f32), + }; + LLVMStructSetBody(type, fields, 2, false); + return type; + } + case Basic_complex128: + { + char const *name = "..complex128"; + LLVMTypeRef type = LLVMGetTypeByName(m->mod, name); + if (type != nullptr) { + return type; + } + type = LLVMStructCreateNamed(ctx, name); + LLVMTypeRef fields[2] = { + lb_type(m, t_f64), + lb_type(m, t_f64), + }; + LLVMStructSetBody(type, fields, 2, false); + return type; + } + + case Basic_quaternion128: + { + char const *name = "..quaternion128"; + LLVMTypeRef type = LLVMGetTypeByName(m->mod, name); + if (type != nullptr) { + return type; + } + type = LLVMStructCreateNamed(ctx, name); + LLVMTypeRef fields[4] = { + lb_type(m, t_f32), + lb_type(m, t_f32), + lb_type(m, t_f32), + lb_type(m, t_f32), + }; + LLVMStructSetBody(type, fields, 4, false); + return type; + } + case Basic_quaternion256: + { + char const *name = "..quaternion256"; + LLVMTypeRef type = LLVMGetTypeByName(m->mod, name); + if (type != nullptr) { + return type; + } + type = LLVMStructCreateNamed(ctx, name); + LLVMTypeRef fields[4] = { + lb_type(m, t_f64), + lb_type(m, t_f64), + lb_type(m, t_f64), + lb_type(m, t_f64), + }; + LLVMStructSetBody(type, fields, 4, false); + return type; + } + + case Basic_int: return LLVMIntTypeInContext(ctx, 8*cast(unsigned)build_context.word_size); + case Basic_uint: return LLVMIntTypeInContext(ctx, 8*cast(unsigned)build_context.word_size); + + case Basic_uintptr: return LLVMIntTypeInContext(ctx, 8*cast(unsigned)build_context.word_size); + + case Basic_rawptr: return LLVMPointerType(LLVMInt8Type(), 0); + case Basic_string: + { + char const *name = "..string"; + LLVMTypeRef type = LLVMGetTypeByName(m->mod, name); + if (type != nullptr) { + return type; + } + type = LLVMStructCreateNamed(ctx, name); + LLVMTypeRef fields[2] = { + LLVMPointerType(lb_type(m, t_u8), 0), + lb_type(m, t_int), + }; + LLVMStructSetBody(type, fields, 2, false); + return type; + } + case Basic_cstring: return LLVMPointerType(LLVMInt8Type(), 0); + case Basic_any: + { + char const *name = "..any"; + LLVMTypeRef type = LLVMGetTypeByName(m->mod, name); + if (type != nullptr) { + return type; + } + type = LLVMStructCreateNamed(ctx, name); + LLVMTypeRef fields[2] = { + lb_type(m, t_rawptr), + lb_type(m, t_typeid), + }; + LLVMStructSetBody(type, fields, 2, false); + return type; + } + + case Basic_typeid: return LLVMIntType(8*cast(unsigned)build_context.word_size); + + // Endian Specific Types + case Basic_i16le: return LLVMInt16TypeInContext(ctx); + case Basic_u16le: return LLVMInt16TypeInContext(ctx); + case Basic_i32le: return LLVMInt32TypeInContext(ctx); + case Basic_u32le: return LLVMInt32TypeInContext(ctx); + case Basic_i64le: return LLVMInt64TypeInContext(ctx); + case Basic_u64le: return LLVMInt64TypeInContext(ctx); + case Basic_i128le: return LLVMInt128TypeInContext(ctx); + case Basic_u128le: return LLVMInt128TypeInContext(ctx); + + case Basic_i16be: return LLVMInt16TypeInContext(ctx); + case Basic_u16be: return LLVMInt16TypeInContext(ctx); + case Basic_i32be: return LLVMInt32TypeInContext(ctx); + case Basic_u32be: return LLVMInt32TypeInContext(ctx); + case Basic_i64be: return LLVMInt64TypeInContext(ctx); + case Basic_u64be: return LLVMInt64TypeInContext(ctx); + case Basic_i128be: return LLVMInt128TypeInContext(ctx); + case Basic_u128be: return LLVMInt128TypeInContext(ctx); + + // Untyped types + case Basic_UntypedBool: GB_PANIC("Basic_UntypedBool"); break; + case Basic_UntypedInteger: GB_PANIC("Basic_UntypedInteger"); break; + case Basic_UntypedFloat: GB_PANIC("Basic_UntypedFloat"); break; + case Basic_UntypedComplex: GB_PANIC("Basic_UntypedComplex"); break; + case Basic_UntypedQuaternion: GB_PANIC("Basic_UntypedQuaternion"); break; + case Basic_UntypedString: GB_PANIC("Basic_UntypedString"); break; + case Basic_UntypedRune: GB_PANIC("Basic_UntypedRune"); break; + case Basic_UntypedNil: GB_PANIC("Basic_UntypedNil"); break; + case Basic_UntypedUndef: GB_PANIC("Basic_UntypedUndef"); break; + } + break; + case Type_Named: + { + Type *base = base_type(type->Named.base); + + switch (base->kind) { + case Type_Basic: + return lb_type(m, base); + + case Type_Named: + case Type_Generic: + case Type_BitFieldValue: + GB_PANIC("INVALID TYPE"); + break; + + case Type_Opaque: + return lb_type(m, base->Opaque.elem); + + case Type_Pointer: + case Type_Array: + case Type_EnumeratedArray: + case Type_Slice: + case Type_DynamicArray: + case Type_Map: + case Type_Enum: + case Type_BitSet: + case Type_SimdVector: + return lb_type(m, base); + + // TODO(bill): Deal with this correctly. Can this be named? + case Type_Proc: + return lb_type(m, base); + + case Type_Tuple: + return lb_type(m, base); + } + + LLVMTypeRef *found = map_get(&m->types, hash_type(base)); + if (found) { + LLVMTypeKind kind = LLVMGetTypeKind(*found); + if (kind == LLVMStructTypeKind) { + char const *name = alloc_cstring(heap_allocator(), lb_get_entity_name(m, type->Named.type_name)); + LLVMTypeRef llvm_type = LLVMGetTypeByName(m->mod, name); + if (llvm_type != nullptr) { + return llvm_type; + } + llvm_type = LLVMStructCreateNamed(ctx, name); + map_set(&m->types, hash_type(type), llvm_type); + lb_clone_struct_type(llvm_type, *found); + return llvm_type; + } + } + + switch (base->kind) { + case Type_Struct: + case Type_Union: + case Type_BitField: + { + char const *name = alloc_cstring(heap_allocator(), lb_get_entity_name(m, type->Named.type_name)); + LLVMTypeRef llvm_type = LLVMGetTypeByName(m->mod, name); + if (llvm_type != nullptr) { + return llvm_type; + } + llvm_type = LLVMStructCreateNamed(ctx, name); + map_set(&m->types, hash_type(type), llvm_type); + lb_clone_struct_type(llvm_type, lb_type(m, base)); + return llvm_type; + } + } + + + return lb_type(m, base); + } + + case Type_Pointer: + return LLVMPointerType(lb_type(m, type_deref(type)), 0); + + case Type_Opaque: + return lb_type(m, base_type(type)); + + case Type_Array: + return LLVMArrayType(lb_type(m, type->Array.elem), cast(unsigned)type->Array.count); + + case Type_EnumeratedArray: + return LLVMArrayType(lb_type(m, type->EnumeratedArray.elem), cast(unsigned)type->EnumeratedArray.count); + + case Type_Slice: + { + LLVMTypeRef fields[2] = { + LLVMPointerType(lb_type(m, type->Slice.elem), 0), // data + lb_type(m, t_int), // len + }; + return LLVMStructTypeInContext(ctx, fields, 2, false); + } + break; + + case Type_DynamicArray: + { + LLVMTypeRef fields[4] = { + LLVMPointerType(lb_type(m, type->DynamicArray.elem), 0), // data + lb_type(m, t_int), // len + lb_type(m, t_int), // cap + lb_type(m, t_allocator), // allocator + }; + return LLVMStructTypeInContext(ctx, fields, 4, false); + } + break; + + case Type_Map: + return lb_type(m, type->Map.internal_type); + + case Type_Struct: + { + if (type->Struct.is_raw_union) { + unsigned field_count = 2; + LLVMTypeRef *fields = gb_alloc_array(heap_allocator(), LLVMTypeRef, field_count); + i64 alignment = type_align_of(type); + unsigned size_of_union = cast(unsigned)type_size_of(type); + fields[0] = lb_alignment_prefix_type_hack(m, alignment); + fields[1] = LLVMArrayType(lb_type(m, t_u8), size_of_union); + return LLVMStructTypeInContext(ctx, fields, field_count, false); + } + + isize offset = 0; + if (type->Struct.custom_align > 0) { + offset = 1; + } + + unsigned field_count = cast(unsigned)(type->Struct.fields.count + offset); + LLVMTypeRef *fields = gb_alloc_array(heap_allocator(), LLVMTypeRef, field_count); + GB_ASSERT(fields != nullptr); + defer (gb_free(heap_allocator(), fields)); + + for_array(i, type->Struct.fields) { + Entity *field = type->Struct.fields[i]; + fields[i+offset] = lb_type(m, field->type); + } + + if (type->Struct.custom_align > 0) { + fields[0] = lb_alignment_prefix_type_hack(m, type->Struct.custom_align); + } + + return LLVMStructTypeInContext(ctx, fields, field_count, type->Struct.is_packed); + } + break; + + case Type_Union: + if (type->Union.variants.count == 0) { + return LLVMStructTypeInContext(ctx, nullptr, 0, false); + } else { + // NOTE(bill): The zero size array is used to fix the alignment used in a structure as + // LLVM takes the first element's alignment as the entire alignment (like C) + i64 align = type_align_of(type); + i64 size = type_size_of(type); + + if (is_type_union_maybe_pointer_original_alignment(type)) { + LLVMTypeRef fields[1] = {lb_type(m, type->Union.variants[0])}; + return LLVMStructTypeInContext(ctx, fields, 1, false); + } + + unsigned block_size = cast(unsigned)type->Union.variant_block_size; + + LLVMTypeRef fields[3] = {}; + unsigned field_count = 1; + fields[0] = lb_alignment_prefix_type_hack(m, align); + if (is_type_union_maybe_pointer(type)) { + field_count += 1; + fields[1] = lb_type(m, type->Union.variants[0]); + } else { + field_count += 2; + if (block_size == align) { + fields[1] = LLVMIntTypeInContext(m->ctx, 8*block_size); + } else { + fields[1] = LLVMArrayType(lb_type(m, t_u8), block_size); + } + fields[2] = lb_type(m, union_tag_type(type)); + } + + return LLVMStructTypeInContext(ctx, fields, field_count, false); + } + break; + + case Type_Enum: + return lb_type(m, base_enum_type(type)); + + case Type_Tuple: + if (type->Tuple.variables.count == 1) { + return lb_type(m, type->Tuple.variables[0]->type); + } else { + unsigned field_count = cast(unsigned)(type->Tuple.variables.count); + LLVMTypeRef *fields = gb_alloc_array(heap_allocator(), LLVMTypeRef, field_count); + defer (gb_free(heap_allocator(), fields)); + + for_array(i, type->Tuple.variables) { + Entity *field = type->Tuple.variables[i]; + fields[i] = lb_type(m, field->type); + } + + return LLVMStructTypeInContext(ctx, fields, field_count, type->Tuple.is_packed); + } + + case Type_Proc: + { + set_procedure_abi_types(heap_allocator(), type); + + LLVMTypeRef return_type = LLVMVoidTypeInContext(ctx); + isize offset = 0; + if (type->Proc.return_by_pointer) { + offset = 1; + } else if (type->Proc.abi_compat_result_type != nullptr) { + return_type = lb_type(m, type->Proc.abi_compat_result_type); + } + + isize extra_param_count = offset; + if (type->Proc.calling_convention == ProcCC_Odin) { + extra_param_count += 1; + } + + isize param_count = type->Proc.abi_compat_params.count + extra_param_count; + LLVMTypeRef *param_types = gb_alloc_array(heap_allocator(), LLVMTypeRef, param_count); + defer (gb_free(heap_allocator(), param_types)); + + isize param_index = offset; + for_array(i, type->Proc.abi_compat_params) { + Type *param = type->Proc.abi_compat_params[i]; + if (param == nullptr) { + continue; + } + param_types[param_index++] = lb_type(m, param); + } + if (type->Proc.return_by_pointer) { + param_types[0] = LLVMPointerType(lb_type(m, type->Proc.abi_compat_result_type), 0); + } + if (type->Proc.calling_convention == ProcCC_Odin) { + param_types[param_index++] = lb_type(m, t_context_ptr); + } + + LLVMTypeRef t = LLVMFunctionType(return_type, param_types, cast(unsigned)param_index, type->Proc.c_vararg); + return LLVMPointerType(t, 0); + } + break; + case Type_BitFieldValue: + return LLVMIntType(type->BitFieldValue.bits); + + case Type_BitField: + { + LLVMTypeRef internal_type = nullptr; + { + GB_ASSERT(type->BitField.fields.count == type->BitField.sizes.count); + unsigned field_count = cast(unsigned)type->BitField.fields.count; + LLVMTypeRef *fields = gb_alloc_array(heap_allocator(), LLVMTypeRef, field_count); + defer (gb_free(heap_allocator(), fields)); + + for_array(i, type->BitField.sizes) { + u32 size = type->BitField.sizes[i]; + fields[i] = LLVMIntType(size); + } + + internal_type = LLVMStructTypeInContext(ctx, fields, field_count, true); + } + unsigned field_count = 2; + LLVMTypeRef *fields = gb_alloc_array(heap_allocator(), LLVMTypeRef, field_count); + + i64 alignment = 1; + if (type->BitField.custom_align > 0) { + alignment = type->BitField.custom_align; + } + fields[0] = lb_alignment_prefix_type_hack(m, alignment); + fields[1] = internal_type; + + return LLVMStructTypeInContext(ctx, fields, field_count, true); + } + break; + case Type_BitSet: + return LLVMIntType(8*cast(unsigned)type_size_of(type)); + case Type_SimdVector: + if (type->SimdVector.is_x86_mmx) { + return LLVMX86MMXTypeInContext(ctx); + } + return LLVMVectorType(lb_type(m, type->SimdVector.elem), cast(unsigned)type->SimdVector.count); + } + + GB_PANIC("Invalid type %s", type_to_string(type)); + return LLVMInt32TypeInContext(ctx); +} + +LLVMTypeRef lb_type(lbModule *m, Type *type) { + type = default_type(type); + + LLVMTypeRef *found = map_get(&m->types, hash_type(type)); + if (found) { + return *found; + } + + LLVMTypeRef llvm_type = lb_type_internal(m, type); + + map_set(&m->types, hash_type(type), llvm_type); + + return llvm_type; +} + +void lb_add_entity(lbModule *m, Entity *e, lbValue val) { + if (e != nullptr) { + map_set(&m->values, hash_entity(e), val); + } +} +void lb_add_member(lbModule *m, String const &name, lbValue val) { + if (name.len > 0) { + map_set(&m->members, hash_string(name), val); + } +} +void lb_add_member(lbModule *m, HashKey const &key, lbValue val) { + map_set(&m->members, key, val); +} +void lb_add_procedure_value(lbModule *m, lbProcedure *p) { + if (p->entity != nullptr) { + map_set(&m->procedure_values, hash_pointer(p->value), p->entity); + } + map_set(&m->procedures, hash_string(p->name), p); +} + + + +lbValue lb_emit_string(lbProcedure *p, lbValue str_elem, lbValue str_len) { + if (false && lb_is_const(str_elem) && lb_is_const(str_len)) { + LLVMValueRef values[2] = { + str_elem.value, + str_len.value, + }; + lbValue res = {}; + res.type = t_string; + res.value = LLVMConstNamedStruct(lb_type(p->module, t_string), values, gb_count_of(values)); + return res; + } else { + lbAddr res = lb_add_local_generated(p, t_string, false); + lb_emit_store(p, lb_emit_struct_ep(p, res.addr, 0), str_elem); + lb_emit_store(p, lb_emit_struct_ep(p, res.addr, 1), str_len); + return lb_addr_load(p, res); + } +} + +LLVMAttributeRef lb_create_enum_attribute(LLVMContextRef ctx, char const *name, u64 value) { + unsigned kind = LLVMGetEnumAttributeKindForName(name, gb_strlen(name)); + GB_ASSERT(kind != 0); + return LLVMCreateEnumAttribute(ctx, kind, value); +} + +void lb_add_proc_attribute_at_index(lbProcedure *p, isize index, char const *name, u64 value) { + LLVMAttributeRef attr = lb_create_enum_attribute(p->module->ctx, name, value); + GB_ASSERT(attr != nullptr); + LLVMAddAttributeAtIndex(p->value, cast(unsigned)index, attr); +} + +void lb_add_proc_attribute_at_index(lbProcedure *p, isize index, char const *name) { + lb_add_proc_attribute_at_index(p, index, name, cast(u64)true); +} + + + + +lbProcedure *lb_create_procedure(lbModule *m, Entity *entity) { + GB_ASSERT(entity != nullptr); + + String link_name = lb_get_entity_name(m, entity); + + { + HashKey key = hash_string(link_name); + lbValue *found = map_get(&m->members, key); + if (found) { + lb_add_entity(m, entity, *found); + lbProcedure **p_found = map_get(&m->procedures, key); + GB_ASSERT(p_found != nullptr); + return *p_found; + } + } + + + lbProcedure *p = gb_alloc_item(heap_allocator(), lbProcedure); + + p->module = m; + entity->code_gen_module = m; + entity->code_gen_procedure = p; + p->entity = entity; + p->name = link_name; + + DeclInfo *decl = entity->decl_info; + + ast_node(pl, ProcLit, decl->proc_lit); + Type *pt = base_type(entity->type); + GB_ASSERT(pt->kind == Type_Proc); + + set_procedure_abi_types(heap_allocator(), entity->type); + + p->type = entity->type; + p->type_expr = decl->type_expr; + p->body = pl->body; + p->tags = pt->Proc.tags; + p->inlining = ProcInlining_none; + p->is_foreign = entity->Procedure.is_foreign; + p->is_export = entity->Procedure.is_export; + p->is_entry_point = false; + + gbAllocator a = heap_allocator(); + p->children.allocator = a; + p->params.allocator = a; + p->defer_stmts.allocator = a; + p->blocks.allocator = a; + p->branch_blocks.allocator = a; + p->context_stack.allocator = a; + + + char *c_link_name = alloc_cstring(heap_allocator(), p->name); + LLVMTypeRef func_ptr_type = lb_type(m, p->type); + LLVMTypeRef func_type = LLVMGetElementType(func_ptr_type); + + p->value = LLVMAddFunction(m->mod, c_link_name, func_type); + + LLVMSetFunctionCallConv(p->value, lb_calling_convention_map[pt->Proc.calling_convention]); + lbValue proc_value = {p->value, p->type}; + lb_add_entity(m, entity, proc_value); + lb_add_member(m, p->name, proc_value); + lb_add_procedure_value(m, p); + + + // NOTE(bill): offset==0 is the return value + isize offset = 1; + if (pt->Proc.return_by_pointer) { + lb_add_proc_attribute_at_index(p, 1, "sret"); + lb_add_proc_attribute_at_index(p, 1, "noalias"); + offset = 2; + } + + isize parameter_index = 0; + if (pt->Proc.param_count) { + TypeTuple *params = &pt->Proc.params->Tuple; + for (isize i = 0; i < pt->Proc.param_count; i++) { + Entity *e = params->variables[i]; + Type *original_type = e->type; + Type *abi_type = pt->Proc.abi_compat_params[i]; + if (e->kind != Entity_Variable) continue; + + if (i+1 == params->variables.count && pt->Proc.c_vararg) { + continue; + } + if (is_type_tuple(abi_type)) { + for_array(j, abi_type->Tuple.variables) { + Type *tft = abi_type->Tuple.variables[j]->type; + if (e->flags&EntityFlag_NoAlias) { + lb_add_proc_attribute_at_index(p, offset+parameter_index+j, "noalias"); + } + } + parameter_index += abi_type->Tuple.variables.count; + } else { + if (e->flags&EntityFlag_NoAlias) { + lb_add_proc_attribute_at_index(p, offset+parameter_index, "noalias"); + } + parameter_index += 1; + } + } + } + + if (pt->Proc.calling_convention == ProcCC_Odin) { + 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"); + } + + + if (entity->Procedure.is_foreign) { + lb_add_foreign_library_path(p->module, entity->Procedure.foreign_library); + } + + + { // 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 type = nullptr; + + // type = LLVMDIBuilderCreateSubroutineType(m->debug_builder, file, nullptr, 0, LLVMDIFlagZero); + + + 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, type, + true, p->body == nullptr, + line, LLVMDIFlagZero, false + ); + GB_ASSERT(res != nullptr); + map_set(&m->debug_values, hash_pointer(p), res); + } + + return p; +} + +lbProcedure *lb_create_dummy_procedure(lbModule *m, String link_name, Type *type) { + { + HashKey key = hash_string(link_name); + lbValue *found = map_get(&m->members, key); + GB_ASSERT(found == nullptr); + } + + lbProcedure *p = gb_alloc_item(heap_allocator(), lbProcedure); + + p->module = m; + p->name = link_name; + + p->type = type; + p->type_expr = nullptr; + p->body = nullptr; + p->tags = 0; + p->inlining = ProcInlining_none; + p->is_foreign = false; + p->is_export = false; + p->is_entry_point = false; + + gbAllocator a = heap_allocator(); + p->children.allocator = a; + p->params.allocator = a; + p->defer_stmts.allocator = a; + p->blocks.allocator = a; + p->branch_blocks.allocator = a; + p->context_stack.allocator = a; + + + char *c_link_name = alloc_cstring(heap_allocator(), p->name); + LLVMTypeRef func_ptr_type = lb_type(m, p->type); + LLVMTypeRef func_type = LLVMGetElementType(func_ptr_type); + + p->value = LLVMAddFunction(m->mod, c_link_name, func_type); + + Type *pt = p->type; + + LLVMSetFunctionCallConv(p->value, lb_calling_convention_map[pt->Proc.calling_convention]); + lbValue proc_value = {p->value, p->type}; + lb_add_member(m, p->name, proc_value); + lb_add_procedure_value(m, p); + + + // NOTE(bill): offset==0 is the return value + isize offset = 1; + if (pt->Proc.return_by_pointer) { + lb_add_proc_attribute_at_index(p, 1, "sret"); + lb_add_proc_attribute_at_index(p, 1, "noalias"); + offset = 2; + } + + isize parameter_index = 0; + if (pt->Proc.param_count) { + TypeTuple *params = &pt->Proc.params->Tuple; + for (isize i = 0; i < pt->Proc.param_count; i++) { + Entity *e = params->variables[i]; + Type *original_type = e->type; + Type *abi_type = pt->Proc.abi_compat_params[i]; + if (e->kind != Entity_Variable) continue; + + if (i+1 == params->variables.count && pt->Proc.c_vararg) { + continue; + } + if (is_type_tuple(abi_type)) { + for_array(j, abi_type->Tuple.variables) { + Type *tft = abi_type->Tuple.variables[j]->type; + if (e->flags&EntityFlag_NoAlias) { + lb_add_proc_attribute_at_index(p, offset+parameter_index+j, "noalias"); + } + } + parameter_index += abi_type->Tuple.variables.count; + } else { + if (e->flags&EntityFlag_NoAlias) { + lb_add_proc_attribute_at_index(p, offset+parameter_index, "noalias"); + } + parameter_index += 1; + } + } + } + + if (pt->Proc.calling_convention == ProcCC_Odin) { + 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"); + } + + return p; +} + + +lbValue lb_value_param(lbProcedure *p, Entity *e, Type *abi_type, i32 index, lbParamPasskind *kind_) { + lbParamPasskind kind = lbParamPass_Value; + + if (e != nullptr && abi_type != e->type) { + if (is_type_pointer(abi_type)) { + GB_ASSERT(e->kind == Entity_Variable); + kind = lbParamPass_Pointer; + if (e->flags&EntityFlag_Value) { + kind = lbParamPass_ConstRef; + } + } else if (is_type_integer(abi_type)) { + kind = lbParamPass_Integer; + } else if (abi_type == t_llvm_bool) { + kind = lbParamPass_Value; + } else if (is_type_simd_vector(abi_type)) { + kind = lbParamPass_BitCast; + } else if (is_type_float(abi_type)) { + kind = lbParamPass_BitCast; + } else if (is_type_tuple(abi_type)) { + kind = lbParamPass_Tuple; + } else { + GB_PANIC("Invalid abi type pass kind %s", type_to_string(abi_type)); + } + } + + if (kind_) *kind_ = kind; + lbValue res = {}; + res.value = LLVMGetParam(p->value, cast(unsigned)index); + res.type = abi_type; + return res; +} + +lbValue lb_add_param(lbProcedure *p, Entity *e, Ast *expr, Type *abi_type, i32 index) { + lbParamPasskind kind = lbParamPass_Value; + lbValue v = lb_value_param(p, e, abi_type, index, &kind); + array_add(&p->params, v); + + lbValue res = {}; + + switch (kind) { + case lbParamPass_Value: { + lbAddr l = lb_add_local(p, e->type, e, false, index); + lbValue x = v; + if (abi_type == t_llvm_bool) { + x = lb_emit_conv(p, x, t_bool); + } + lb_addr_store(p, l, x); + return x; + } + case lbParamPass_Pointer: + lb_add_entity(p->module, e, v); + return lb_emit_load(p, v); + + case lbParamPass_Integer: { + lbAddr l = lb_add_local(p, e->type, e, false, index); + lbValue iptr = lb_emit_conv(p, l.addr, alloc_type_pointer(abi_type)); + lb_emit_store(p, iptr, v); + return lb_addr_load(p, l); + } + + case lbParamPass_ConstRef: + lb_add_entity(p->module, e, v); + return lb_emit_load(p, v); + + case lbParamPass_BitCast: { + lbAddr l = lb_add_local(p, e->type, e, false, index); + lbValue x = lb_emit_transmute(p, v, e->type); + lb_addr_store(p, l, x); + return x; + } + case lbParamPass_Tuple: { + lbAddr l = lb_add_local(p, e->type, e, true, index); + Type *st = struct_type_from_systemv_distribute_struct_fields(abi_type); + lbValue ptr = lb_emit_transmute(p, l.addr, alloc_type_pointer(st)); + if (abi_type->Tuple.variables.count > 0) { + array_pop(&p->params); + } + for_array(i, abi_type->Tuple.variables) { + Type *t = abi_type->Tuple.variables[i]->type; + + lbParamPasskind elem_kind = lbParamPass_Value; + lbValue elem = lb_value_param(p, nullptr, t, index+cast(i32)i, &elem_kind); + array_add(&p->params, elem); + + lbValue dst = lb_emit_struct_ep(p, ptr, cast(i32)i); + lb_emit_store(p, dst, elem); + } + return lb_addr_load(p, l); + } + + } + + GB_PANIC("Unreachable"); + return {}; +} + +void lb_start_block(lbProcedure *p, lbBlock *b) { + GB_ASSERT(b != nullptr); + if (!b->appended) { + b->appended = true; + LLVMAppendExistingBasicBlock(p->value, b->block); + } + LLVMPositionBuilderAtEnd(p->builder, b->block); + p->curr_block = b; +} + + +void lb_begin_procedure_body(lbProcedure *p) { + DeclInfo *decl = decl_info_of_entity(p->entity); + if (decl != nullptr) { + for_array(i, decl->labels) { + BlockLabel bl = decl->labels[i]; + lbBranchBlocks bb = {bl.label, nullptr, nullptr}; + array_add(&p->branch_blocks, bb); + } + } + + p->builder = LLVMCreateBuilder(); + + p->decl_block = lb_create_block(p, "decls", true); + p->entry_block = lb_create_block(p, "entry", true); + lb_start_block(p, p->entry_block); + + GB_ASSERT(p->type != nullptr); + + i32 parameter_index = 0; + + if (p->type->Proc.return_by_pointer) { + // NOTE(bill): this must be parameter 0 + Type *ptr_type = alloc_type_pointer(reduce_tuple_to_single_type(p->type->Proc.results)); + Entity *e = alloc_entity_param(nullptr, make_token_ident(str_lit("agg.result")), ptr_type, false, false); + e->flags |= EntityFlag_Sret | EntityFlag_NoAlias; + + lbValue return_ptr_value = {}; + return_ptr_value.value = LLVMGetParam(p->value, 0); + return_ptr_value.type = alloc_type_pointer(p->type->Proc.abi_compat_result_type); + p->return_ptr = lb_addr(return_ptr_value); + + lb_add_entity(p->module, e, return_ptr_value); + + parameter_index += 1; + } + + if (p->type->Proc.params != nullptr) { + TypeTuple *params = &p->type->Proc.params->Tuple; + if (p->type_expr != nullptr) { + ast_node(pt, ProcType, p->type_expr); + isize param_index = 0; + isize q_index = 0; + + for_array(i, params->variables) { + ast_node(fl, FieldList, pt->params); + GB_ASSERT(fl->list.count > 0); + GB_ASSERT(fl->list[0]->kind == Ast_Field); + if (q_index == fl->list[param_index]->Field.names.count) { + q_index = 0; + param_index++; + } + ast_node(field, Field, fl->list[param_index]); + Ast *name = field->names[q_index++]; + + Entity *e = params->variables[i]; + if (e->kind != Entity_Variable) { + continue; + } + + Type *abi_type = p->type->Proc.abi_compat_params[i]; + if (e->token.string != "") { + lb_add_param(p, e, name, abi_type, parameter_index); + } + + if (is_type_tuple(abi_type)) { + parameter_index += cast(i32)abi_type->Tuple.variables.count; + } else { + parameter_index += 1; + } + } + } else { + auto abi_types = p->type->Proc.abi_compat_params; + + for_array(i, params->variables) { + Entity *e = params->variables[i]; + if (e->kind != Entity_Variable) { + continue; + } + Type *abi_type = e->type; + if (abi_types.count > 0) { + abi_type = abi_types[i]; + } + if (e->token.string != "") { + lb_add_param(p, e, nullptr, abi_type, parameter_index); + } + if (is_type_tuple(abi_type)) { + parameter_index += cast(i32)abi_type->Tuple.variables.count; + } else { + parameter_index += 1; + } + } + } + } + + + if (p->type->Proc.has_named_results) { + GB_ASSERT(p->type->Proc.result_count > 0); + TypeTuple *results = &p->type->Proc.results->Tuple; + LLVMValueRef return_ptr = LLVMGetParam(p->value, 0); + + isize result_index = 0; + + for_array(i, results->variables) { + Entity *e = results->variables[i]; + if (e->kind != Entity_Variable) { + continue; + } + + if (e->token.string != "") { + GB_ASSERT(!is_blank_ident(e->token)); + + lbAddr res = lb_add_local(p, e->type, e); + + lbValue c = {}; + switch (e->Variable.param_value.kind) { + case ParameterValue_Constant: + c = lb_const_value(p->module, e->type, e->Variable.param_value.value); + break; + case ParameterValue_Nil: + c = lb_const_nil(p->module, e->type); + break; + case ParameterValue_Location: + GB_PANIC("ParameterValue_Location"); + break; + } + if (c.value != nullptr) { + lb_addr_store(p, res, c); + } + } + + result_index += 1; + } + } + + if (p->type->Proc.calling_convention == ProcCC_Odin) { + Entity *e = alloc_entity_param(nullptr, make_token_ident(str_lit("__.context_ptr")), t_context_ptr, false, false); + e->flags |= EntityFlag_NoAlias; + lbValue param = {}; + param.value = LLVMGetParam(p->value, LLVMCountParams(p->value)-1); + param.type = e->type; + lb_add_entity(p->module, e, param); + lbAddr ctx_addr = {}; + ctx_addr.kind = lbAddr_Context; + ctx_addr.addr = param; + lbContextData ctx = {ctx_addr, p->scope_index}; + array_add(&p->context_stack, ctx); + } + + lb_start_block(p, p->entry_block); +} + +void lb_end_procedure_body(lbProcedure *p) { + LLVMPositionBuilderAtEnd(p->builder, p->decl_block->block); + LLVMBuildBr(p->builder, p->entry_block->block); + LLVMPositionBuilderAtEnd(p->builder, p->curr_block->block); + + if (p->type->Proc.result_count == 0) { + LLVMValueRef instr = LLVMGetLastInstruction(p->curr_block->block); + if (!LLVMIsAReturnInst(instr)) { + lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr); + LLVMBuildRetVoid(p->builder); + } + } else { + if (p->curr_block->preds.count == 0) { + LLVMValueRef instr = LLVMGetLastInstruction(p->curr_block->block); + if (instr == nullptr) { + // NOTE(bill): Remove dead trailing block + LLVMDeleteBasicBlock(p->curr_block->block); + } + } + } + + p->curr_block = nullptr; + +} +void lb_end_procedure(lbProcedure *p) { + LLVMDisposeBuilder(p->builder); +} + +void lb_add_edge(lbBlock *from, lbBlock *to) { + LLVMValueRef instr = LLVMGetLastInstruction(from->block); + if (instr == nullptr || !LLVMIsATerminatorInst(instr)) { + array_add(&from->succs, to); + array_add(&to->preds, from); + } +} + + +lbBlock *lb_create_block(lbProcedure *p, char const *name, bool append) { + lbBlock *b = gb_alloc_item(heap_allocator(), lbBlock); + b->block = LLVMCreateBasicBlockInContext(p->module->ctx, name); + b->appended = false; + if (append) { + b->appended = true; + LLVMAppendExistingBasicBlock(p->value, b->block); + } + + b->scope = p->curr_scope; + b->scope_index = p->scope_index; + + b->preds.allocator = heap_allocator(); + b->succs.allocator = heap_allocator(); + + array_add(&p->blocks, b); + + return b; +} + +void lb_emit_jump(lbProcedure *p, lbBlock *target_block) { + if (p->curr_block == nullptr) { + return; + } + LLVMValueRef last_instr = LLVMGetLastInstruction(p->curr_block->block); + if (last_instr != nullptr && LLVMIsATerminatorInst(last_instr)) { + return; + } + + lb_add_edge(p->curr_block, target_block); + LLVMBuildBr(p->builder, target_block->block); + p->curr_block = nullptr; +} + +void lb_emit_if(lbProcedure *p, lbValue cond, lbBlock *true_block, lbBlock *false_block) { + lbBlock *b = p->curr_block; + if (b == nullptr) { + return; + } + LLVMValueRef last_instr = LLVMGetLastInstruction(p->curr_block->block); + if (last_instr != nullptr && LLVMIsATerminatorInst(last_instr)) { + return; + } + + lb_add_edge(b, true_block); + lb_add_edge(b, false_block); + + LLVMValueRef cv = cond.value; + cv = LLVMBuildTruncOrBitCast(p->builder, cv, lb_type(p->module, t_llvm_bool), ""); + LLVMBuildCondBr(p->builder, cv, true_block->block, false_block->block); +} + +lbValue lb_build_cond(lbProcedure *p, Ast *cond, lbBlock *true_block, lbBlock *false_block) { + GB_ASSERT(cond != nullptr); + GB_ASSERT(true_block != nullptr); + GB_ASSERT(false_block != nullptr); + + switch (cond->kind) { + case_ast_node(pe, ParenExpr, cond); + return lb_build_cond(p, pe->expr, true_block, false_block); + case_end; + + case_ast_node(ue, UnaryExpr, cond); + if (ue->op.kind == Token_Not) { + return lb_build_cond(p, ue->expr, false_block, true_block); + } + case_end; + + case_ast_node(be, BinaryExpr, cond); + if (be->op.kind == Token_CmpAnd) { + lbBlock *block = lb_create_block(p, "cmp.and"); + lb_build_cond(p, be->left, block, false_block); + lb_start_block(p, block); + return lb_build_cond(p, be->right, true_block, false_block); + } else if (be->op.kind == Token_CmpOr) { + lbBlock *block = lb_create_block(p, "cmp.or"); + lb_build_cond(p, be->left, true_block, block); + lb_start_block(p, block); + return lb_build_cond(p, be->right, true_block, false_block); + } + case_end; + } + + lbValue v = lb_build_expr(p, cond); + // v = lb_emit_conv(p, v, t_bool); + v = lb_emit_conv(p, v, t_llvm_bool); + + lb_emit_if(p, v, true_block, false_block); + + return v; +} + + + +lbAddr lb_add_local(lbProcedure *p, Type *type, Entity *e, bool zero_init, i32 param_index) { + GB_ASSERT(p->decl_block != p->curr_block); + LLVMPositionBuilderAtEnd(p->builder, p->decl_block->block); + + char const *name = ""; + if (e != nullptr) { + // name = alloc_cstring(heap_allocator(), e->token.string); + } + + LLVMTypeRef llvm_type = lb_type(p->module, type); + LLVMValueRef ptr = LLVMBuildAlloca(p->builder, llvm_type, name); + LLVMSetAlignment(ptr, 16); // TODO(bill): Make this configurable + + LLVMPositionBuilderAtEnd(p->builder, p->curr_block->block); + if (zero_init) { + LLVMBuildStore(p->builder, LLVMConstNull(lb_type(p->module, type)), ptr); + } + + lbValue val = {}; + val.value = ptr; + val.type = alloc_type_pointer(type); + + if (e != nullptr) { + lb_add_entity(p->module, e, val); + } + + return lb_addr(val); +} + +lbAddr lb_add_local_generated(lbProcedure *p, Type *type, bool zero_init) { + return lb_add_local(p, type, nullptr, zero_init); +} + + +void lb_build_nested_proc(lbProcedure *p, AstProcLit *pd, Entity *e) { + GB_ASSERT(pd->body != nullptr); + lbModule *m = p->module; + auto *min_dep_set = &m->info->minimum_dependency_set; + + if (ptr_set_exists(min_dep_set, e) == false) { + // NOTE(bill): Nothing depends upon it so doesn't need to be built + return; + } + + // NOTE(bill): Generate a new name + // parent.name-guid + String original_name = e->token.string; + String pd_name = original_name; + if (e->Procedure.link_name.len > 0) { + pd_name = e->Procedure.link_name; + } + + isize name_len = p->name.len + 1 + pd_name.len + 1 + 10 + 1; + char *name_text = gb_alloc_array(heap_allocator(), char, name_len); + + i32 guid = cast(i32)p->children.count; + name_len = gb_snprintf(name_text, name_len, "%.*s.%.*s-%d", LIT(p->name), LIT(pd_name), guid); + String name = make_string(cast(u8 *)name_text, name_len-1); + + set_procedure_abi_types(heap_allocator(), e->type); + + + e->Procedure.link_name = name; + + lbProcedure *nested_proc = lb_create_procedure(p->module, e); + + lbValue value = {}; + value.value = nested_proc->value; + value.type = nested_proc->type; + + lb_add_entity(m, e, value); + array_add(&p->children, nested_proc); + array_add(&m->procedures_to_generate, nested_proc); +} + + +void lb_add_foreign_library_path(lbModule *m, Entity *e) { + if (e == nullptr) { + return; + } + GB_ASSERT(e->kind == Entity_LibraryName); + GB_ASSERT(e->flags & EntityFlag_Used); + + for_array(i, e->LibraryName.paths) { + String library_path = e->LibraryName.paths[i]; + if (library_path.len == 0) { + continue; + } + + bool ok = true; + for_array(path_index, m->foreign_library_paths) { + String path = m->foreign_library_paths[path_index]; + #if defined(GB_SYSTEM_WINDOWS) + if (str_eq_ignore_case(path, library_path)) { + #else + if (str_eq(path, library_path)) { + #endif + ok = false; + break; + } + } + + if (ok) { + array_add(&m->foreign_library_paths, library_path); + } + } +} + + + +void lb_build_constant_value_decl(lbProcedure *p, AstValueDecl *vd) { + if (vd == nullptr || vd->is_mutable) { + return; + } + + auto *min_dep_set = &p->module->info->minimum_dependency_set; + + static i32 global_guid = 0; + + for_array(i, vd->names) { + Ast *ident = vd->names[i]; + GB_ASSERT(ident->kind == Ast_Ident); + Entity *e = entity_of_ident(ident); + GB_ASSERT(e != nullptr); + if (e->kind != Entity_TypeName) { + continue; + } + + bool polymorphic_struct = false; + if (e->type != nullptr && e->kind == Entity_TypeName) { + Type *bt = base_type(e->type); + if (bt->kind == Type_Struct) { + polymorphic_struct = bt->Struct.is_polymorphic; + } + } + + if (!polymorphic_struct && !ptr_set_exists(min_dep_set, e)) { + continue; + } + + if (e->TypeName.ir_mangled_name.len != 0) { + // NOTE(bill): Already set + continue; + } + + lb_set_nested_type_name_ir_mangled_name(e, p); + } + + for_array(i, vd->names) { + Ast *ident = vd->names[i]; + GB_ASSERT(ident->kind == Ast_Ident); + Entity *e = entity_of_ident(ident); + GB_ASSERT(e != nullptr); + if (e->kind != Entity_Procedure) { + continue; + } + + CheckerInfo *info = p->module->info; + DeclInfo *decl = decl_info_of_entity(e); + ast_node(pl, ProcLit, decl->proc_lit); + if (pl->body != nullptr) { + auto *found = map_get(&info->gen_procs, hash_pointer(ident)); + if (found) { + auto procs = *found; + for_array(i, procs) { + Entity *e = procs[i]; + if (!ptr_set_exists(min_dep_set, e)) { + continue; + } + DeclInfo *d = decl_info_of_entity(e); + lb_build_nested_proc(p, &d->proc_lit->ProcLit, e); + } + } else { + lb_build_nested_proc(p, pl, e); + } + } else { + + // FFI - Foreign function interace + String original_name = e->token.string; + String name = original_name; + + if (e->Procedure.is_foreign) { + lb_add_foreign_library_path(p->module, e->Procedure.foreign_library); + } + + if (e->Procedure.link_name.len > 0) { + name = e->Procedure.link_name; + } + + HashKey key = hash_string(name); + lbValue *prev_value = map_get(&p->module->members, key); + if (prev_value != nullptr) { + // NOTE(bill): Don't do mutliple declarations in the IR + return; + } + + set_procedure_abi_types(heap_allocator(), e->type); + e->Procedure.link_name = name; + + lbProcedure *nested_proc = lb_create_procedure(p->module, e); + + lbValue value = {}; + value.value = nested_proc->value; + value.type = nested_proc->type; + + array_add(&p->module->procedures_to_generate, nested_proc); + if (p != nullptr) { + array_add(&p->children, nested_proc); + } else { + map_set(&p->module->members, hash_string(name), value); + } + } + } +} + + +void lb_build_stmt_list(lbProcedure *p, Array const &stmts) { + for_array(i, stmts) { + Ast *stmt = stmts[i]; + switch (stmt->kind) { + case_ast_node(vd, ValueDecl, stmt); + lb_build_constant_value_decl(p, vd); + case_end; + case_ast_node(fb, ForeignBlockDecl, stmt); + ast_node(block, BlockStmt, fb->body); + lb_build_stmt_list(p, block->stmts); + case_end; + } + } + for_array(i, stmts) { + lb_build_stmt(p, stmts[i]); + } +} + +lbBranchBlocks lb_lookup_branch_blocks(lbProcedure *p, Ast *ident) { + GB_ASSERT(ident->kind == Ast_Ident); + Entity *e = entity_of_ident(ident); + GB_ASSERT(e->kind == Entity_Label); + for_array(i, p->branch_blocks) { + lbBranchBlocks *b = &p->branch_blocks[i]; + if (b->label == e->Label.node) { + return *b; + } + } + + GB_PANIC("Unreachable"); + lbBranchBlocks empty = {}; + return empty; +} + + +lbTargetList *lb_push_target_list(lbProcedure *p, Ast *label, lbBlock *break_, lbBlock *continue_, lbBlock *fallthrough_) { + lbTargetList *tl = gb_alloc_item(heap_allocator(), lbTargetList); + tl->prev = p->target_list; + tl->break_ = break_; + tl->continue_ = continue_; + tl->fallthrough_ = fallthrough_; + p->target_list = tl; + + if (label != nullptr) { // Set label blocks + GB_ASSERT(label->kind == Ast_Label); + + for_array(i, p->branch_blocks) { + lbBranchBlocks *b = &p->branch_blocks[i]; + GB_ASSERT(b->label != nullptr && label != nullptr); + GB_ASSERT(b->label->kind == Ast_Label); + if (b->label == label) { + b->break_ = break_; + b->continue_ = continue_; + return tl; + } + } + + GB_PANIC("Unreachable"); + } + + return tl; +} + +void lb_pop_target_list(lbProcedure *p) { + p->target_list = p->target_list->prev; +} + + + + +void lb_open_scope(lbProcedure *p) { + p->scope_index += 1; +} + +void lb_close_scope(lbProcedure *p, lbDeferExitKind kind, lbBlock *block, bool pop_stack=true) { + lb_emit_defer_stmts(p, kind, block); + GB_ASSERT(p->scope_index > 0); + + // NOTE(bill): Remove `context`s made in that scope + 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; +} + +void lb_build_when_stmt(lbProcedure *p, AstWhenStmt *ws) { + TypeAndValue tv = type_and_value_of_expr(ws->cond); + GB_ASSERT(is_type_boolean(tv.type)); + GB_ASSERT(tv.value.kind == ExactValue_Bool); + if (tv.value.value_bool) { + lb_build_stmt_list(p, ws->body->BlockStmt.stmts); + } else if (ws->else_stmt) { + switch (ws->else_stmt->kind) { + case Ast_BlockStmt: + lb_build_stmt_list(p, ws->else_stmt->BlockStmt.stmts); + break; + case Ast_WhenStmt: + lb_build_when_stmt(p, &ws->else_stmt->WhenStmt); + break; + default: + GB_PANIC("Invalid 'else' statement in 'when' statement"); + break; + } + } +} + + + +void lb_build_range_indexed(lbProcedure *p, lbValue expr, Type *val_type, lbValue count_ptr, + lbValue *val_, lbValue *idx_, lbBlock **loop_, lbBlock **done_) { + lbModule *m = p->module; + + lbValue count = {}; + Type *expr_type = base_type(type_deref(expr.type)); + switch (expr_type->kind) { + case Type_Array: + count = lb_const_int(m, t_int, expr_type->Array.count); + break; + } + + lbValue val = {}; + lbValue idx = {}; + lbBlock *loop = nullptr; + lbBlock *done = nullptr; + lbBlock *body = nullptr; + + + lbAddr index = lb_add_local_generated(p, t_int, false); + lb_addr_store(p, index, lb_const_int(m, t_int, cast(u64)-1)); + + loop = lb_create_block(p, "for.index.loop"); + lb_emit_jump(p, loop); + lb_start_block(p, loop); + + lbValue incr = lb_emit_arith(p, Token_Add, lb_addr_load(p, index), lb_const_int(m, t_int, 1), t_int); + lb_addr_store(p, index, incr); + + body = lb_create_block(p, "for.index.body"); + done = lb_create_block(p, "for.index.done"); + if (count.value == nullptr) { + GB_ASSERT(count_ptr.value != nullptr); + count = lb_emit_load(p, count_ptr); + } + lbValue cond = lb_emit_comp(p, Token_Lt, incr, count); + lb_emit_if(p, cond, body, done); + lb_start_block(p, body); + + idx = lb_addr_load(p, index); + switch (expr_type->kind) { + case Type_Array: { + if (val_type != nullptr) { + val = lb_emit_load(p, lb_emit_array_ep(p, expr, idx)); + } + break; + } + case Type_EnumeratedArray: { + if (val_type != nullptr) { + val = lb_emit_load(p, lb_emit_array_ep(p, expr, idx)); + // NOTE(bill): Override the idx value for the enumeration + Type *index_type = expr_type->EnumeratedArray.index; + if (compare_exact_values(Token_NotEq, expr_type->EnumeratedArray.min_value, exact_value_u64(0))) { + idx = lb_emit_arith(p, Token_Add, idx, lb_const_value(m, index_type, expr_type->EnumeratedArray.min_value), index_type); + } + } + break; + } + case Type_Slice: { + if (val_type != nullptr) { + lbValue elem = lb_slice_elem(p, expr); + val = lb_emit_load(p, lb_emit_ptr_offset(p, elem, idx)); + } + break; + } + case Type_DynamicArray: { + if (val_type != nullptr) { + lbValue elem = lb_emit_struct_ep(p, expr, 0); + elem = lb_emit_load(p, elem); + val = lb_emit_load(p, lb_emit_ptr_offset(p, elem, idx)); + } + break; + } + case Type_Map: { + lbAddr key = lb_add_local_generated(p, expr_type->Map.key, true); + + lbValue entries = lb_map_entries_ptr(p, expr); + lbValue elem = lb_emit_struct_ep(p, entries, 0); + elem = lb_emit_load(p, elem); + + lbValue entry = lb_emit_ptr_offset(p, elem, idx); + val = lb_emit_load(p, lb_emit_struct_ep(p, entry, 2)); + + lbValue hash = lb_emit_struct_ep(p, entry, 0); + if (is_type_string(expr_type->Map.key)) { + lbValue str = lb_emit_struct_ep(p, hash, 1); + lb_addr_store(p, key, lb_emit_load(p, str)); + } else { + lbValue hash_ptr = lb_emit_struct_ep(p, hash, 0); + hash_ptr = lb_emit_conv(p, hash_ptr, key.addr.type); + lb_addr_store(p, key, lb_emit_load(p, hash_ptr)); + } + + idx = lb_addr_load(p, key); + + break; + } + default: + GB_PANIC("Cannot do range_indexed of %s", type_to_string(expr_type)); + break; + } + + if (val_) *val_ = val; + if (idx_) *idx_ = idx; + if (loop_) *loop_ = loop; + if (done_) *done_ = done; +} + + +void lb_build_range_string(lbProcedure *p, lbValue expr, Type *val_type, + lbValue *val_, lbValue *idx_, lbBlock **loop_, lbBlock **done_) { + lbModule *m = p->module; + lbValue count = lb_const_int(m, t_int, 0); + Type *expr_type = base_type(expr.type); + switch (expr_type->kind) { + case Type_Basic: + count = lb_string_len(p, expr); + break; + default: + GB_PANIC("Cannot do range_string of %s", type_to_string(expr_type)); + break; + } + + lbValue val = {}; + lbValue idx = {}; + lbBlock *loop = nullptr; + lbBlock *done = nullptr; + lbBlock *body = nullptr; + + + lbAddr offset_ = lb_add_local_generated(p, t_int, false); + lb_addr_store(p, offset_, lb_const_int(m, t_int, 0)); + + loop = lb_create_block(p, "for.string.loop"); + lb_emit_jump(p, loop); + lb_start_block(p, loop); + + + + body = lb_create_block(p, "for.string.body"); + done = lb_create_block(p, "for.string.done"); + + lbValue offset = lb_addr_load(p, offset_); + lbValue cond = lb_emit_comp(p, Token_Lt, offset, count); + lb_emit_if(p, cond, body, done); + lb_start_block(p, body); + + + lbValue str_elem = lb_emit_ptr_offset(p, lb_string_elem(p, expr), offset); + lbValue str_len = lb_emit_arith(p, Token_Sub, count, offset, t_int); + auto args = array_make(heap_allocator(), 1); + args[0] = lb_emit_string(p, str_elem, str_len); + lbValue rune_and_len = lb_emit_runtime_call(p, "string_decode_rune", args); + lbValue len = lb_emit_struct_ev(p, rune_and_len, 1); + lb_addr_store(p, offset_, lb_emit_arith(p, Token_Add, offset, len, t_int)); + + + idx = offset; + if (val_type != nullptr) { + val = lb_emit_struct_ev(p, rune_and_len, 0); + } + + if (val_) *val_ = val; + if (idx_) *idx_ = idx; + if (loop_) *loop_ = loop; + if (done_) *done_ = done; +} + + +void lb_build_range_interval(lbProcedure *p, AstBinaryExpr *node, Type *val_type, + lbValue *val_, lbValue *idx_, lbBlock **loop_, lbBlock **done_) { + lbModule *m = p->module; + + // TODO(bill): How should the behaviour work for lower and upper bounds checking for iteration? + // If 'lower' is changed, should 'val' do so or is that not typical behaviour? + + lbValue lower = lb_build_expr(p, node->left); + lbValue upper = {}; + + lbValue val = {}; + lbValue idx = {}; + lbBlock *loop = nullptr; + lbBlock *done = nullptr; + lbBlock *body = nullptr; + + if (val_type == nullptr) { + val_type = lower.type; + } + lbAddr value = lb_add_local_generated(p, val_type, false); + lb_addr_store(p, value, lower); + + lbAddr index = lb_add_local_generated(p, t_int, false); + lb_addr_store(p, index, lb_const_int(m, t_int, 0)); + + loop = lb_create_block(p, "for.interval.loop"); + lb_emit_jump(p, loop); + lb_start_block(p, loop); + + body = lb_create_block(p, "for.interval.body"); + done = lb_create_block(p, "for.interval.done"); + + + TokenKind op = Token_Lt; + switch (node->op.kind) { + case Token_Ellipsis: op = Token_LtEq; break; + case Token_RangeHalf: op = Token_Lt; break; + default: GB_PANIC("Invalid interval operator"); break; + } + + upper = lb_build_expr(p, node->right); + + lbValue curr_value = lb_addr_load(p, value); + lbValue cond = lb_emit_comp(p, op, curr_value, upper); + lb_emit_if(p, cond, body, done); + lb_start_block(p, body); + + val = lb_addr_load(p, value); + idx = lb_addr_load(p, index); + + lb_emit_increment(p, value.addr); + lb_emit_increment(p, index.addr); + + if (val_) *val_ = val; + if (idx_) *idx_ = idx; + if (loop_) *loop_ = loop; + if (done_) *done_ = done; +} + +void lb_build_range_enum(lbProcedure *p, Type *enum_type, Type *val_type, lbValue *val_, lbValue *idx_, lbBlock **loop_, lbBlock **done_) { + lbModule *m = p->module; + + Type *t = enum_type; + GB_ASSERT(is_type_enum(t)); + Type *enum_ptr = alloc_type_pointer(t); + t = base_type(t); + Type *core_elem = core_type(t); + GB_ASSERT(t->kind == Type_Enum); + i64 enum_count = t->Enum.fields.count; + lbValue max_count = lb_const_int(m, t_int, enum_count); + + lbValue ti = lb_type_info(m, t); + lbValue variant = lb_emit_struct_ep(p, ti, 3); + lbValue eti_ptr = lb_emit_conv(p, variant, t_type_info_enum_ptr); + lbValue values = lb_emit_load(p, lb_emit_struct_ep(p, eti_ptr, 2)); + lbValue values_data = lb_slice_elem(p, values); + + lbAddr offset_ = lb_add_local_generated(p, t_int, false); + lb_addr_store(p, offset_, lb_const_int(m, t_int, 0)); + + lbBlock *loop = lb_create_block(p, "for.enum.loop"); + lb_emit_jump(p, loop); + lb_start_block(p, loop); + + lbBlock *body = lb_create_block(p, "for.enum.body"); + lbBlock *done = lb_create_block(p, "for.enum.done"); + + lbValue offset = lb_addr_load(p, offset_); + lbValue cond = lb_emit_comp(p, Token_Lt, offset, max_count); + lb_emit_if(p, cond, body, done); + lb_start_block(p, body); + + lbValue val_ptr = lb_emit_ptr_offset(p, values_data, offset); + lb_emit_increment(p, offset_.addr); + + lbValue val = {}; + if (val_type != nullptr) { + GB_ASSERT(are_types_identical(enum_type, val_type)); + + if (is_type_integer(core_elem)) { + lbValue i = lb_emit_load(p, lb_emit_conv(p, val_ptr, t_i64_ptr)); + val = lb_emit_conv(p, i, t); + } else { + GB_PANIC("TODO(bill): enum core type %s", type_to_string(core_elem)); + } + } + + if (val_) *val_ = val; + if (idx_) *idx_ = offset; + if (loop_) *loop_ = loop; + if (done_) *done_ = done; +} + +void lb_build_range_tuple(lbProcedure *p, Ast *expr, Type *val0_type, Type *val1_type, + lbValue *val0_, lbValue *val1_, lbBlock **loop_, lbBlock **done_) { + lbBlock *loop = lb_create_block(p, "for.tuple.loop"); + lb_emit_jump(p, loop); + lb_start_block(p, loop); + + lbBlock *body = lb_create_block(p, "for.tuple.body"); + lbBlock *done = lb_create_block(p, "for.tuple.done"); + + lbValue tuple_value = lb_build_expr(p, expr); + Type *tuple = tuple_value.type; + GB_ASSERT(tuple->kind == Type_Tuple); + i32 tuple_count = cast(i32)tuple->Tuple.variables.count; + i32 cond_index = tuple_count-1; + + lbValue cond = lb_emit_struct_ev(p, tuple_value, cond_index); + lb_emit_if(p, cond, body, done); + lb_start_block(p, body); + + + if (val0_) *val0_ = lb_emit_struct_ev(p, tuple_value, 0); + if (val1_) *val1_ = lb_emit_struct_ev(p, tuple_value, 1); + if (loop_) *loop_ = loop; + if (done_) *done_ = done; +} + +void lb_build_range_stmt(lbProcedure *p, AstRangeStmt *rs) { + lb_open_scope(p); + + Type *val0_type = nullptr; + Type *val1_type = nullptr; + if (rs->val0 != nullptr && !is_blank_ident(rs->val0)) { + val0_type = type_of_expr(rs->val0); + } + if (rs->val1 != nullptr && !is_blank_ident(rs->val1)) { + val1_type = type_of_expr(rs->val1); + } + + if (val0_type != nullptr) { + Entity *e = entity_of_ident(rs->val0); + lb_add_local(p, e->type, e, true); + } + if (val1_type != nullptr) { + Entity *e = entity_of_ident(rs->val1); + lb_add_local(p, e->type, e, true); + } + + lbValue val = {}; + lbValue key = {}; + lbBlock *loop = nullptr; + lbBlock *done = nullptr; + Ast *expr = unparen_expr(rs->expr); + bool is_map = false; + + TypeAndValue tav = type_and_value_of_expr(expr); + + if (is_ast_range(expr)) { + lb_build_range_interval(p, &expr->BinaryExpr, val0_type, &val, &key, &loop, &done); + } else if (tav.mode == Addressing_Type) { + lb_build_range_enum(p, type_deref(tav.type), val0_type, &val, &key, &loop, &done); + } else { + Type *expr_type = type_of_expr(expr); + Type *et = base_type(type_deref(expr_type)); + switch (et->kind) { + case Type_Map: { + is_map = true; + gbAllocator a = heap_allocator(); + lbAddr addr = lb_build_addr(p, expr); + lbValue map = lb_addr_get_ptr(p, addr); + if (is_type_pointer(type_deref(lb_addr_type(addr)))) { + map = lb_addr_load(p, addr); + } + lbValue entries_ptr = lb_map_entries_ptr(p, map); + lbValue count_ptr = lb_emit_struct_ep(p, entries_ptr, 1); + lb_build_range_indexed(p, map, val1_type, count_ptr, &val, &key, &loop, &done); + break; + } + case Type_Array: { + lbValue array = lb_build_addr_ptr(p, expr); + if (is_type_pointer(type_deref(array.type))) { + array = lb_emit_load(p, array); + } + lbAddr count_ptr = lb_add_local_generated(p, t_int, false); + lb_addr_store(p, count_ptr, lb_const_int(p->module, t_int, et->Array.count)); + lb_build_range_indexed(p, array, val0_type, count_ptr.addr, &val, &key, &loop, &done); + break; + } + case Type_EnumeratedArray: { + lbValue array = lb_build_addr_ptr(p, expr); + if (is_type_pointer(type_deref(array.type))) { + array = lb_emit_load(p, array); + } + lbAddr count_ptr = lb_add_local_generated(p, t_int, false); + lb_addr_store(p, count_ptr, lb_const_int(p->module, t_int, et->EnumeratedArray.count)); + lb_build_range_indexed(p, array, val0_type, count_ptr.addr, &val, &key, &loop, &done); + break; + } + case Type_DynamicArray: { + lbValue count_ptr = {}; + lbValue array = lb_build_addr_ptr(p, expr); + if (is_type_pointer(type_deref(array.type))) { + array = lb_emit_load(p, array); + } + count_ptr = lb_emit_struct_ep(p, array, 1); + lb_build_range_indexed(p, array, val0_type, count_ptr, &val, &key, &loop, &done); + break; + } + case Type_Slice: { + lbValue count_ptr = {}; + lbValue slice = lb_build_expr(p, expr); + if (is_type_pointer(slice.type)) { + count_ptr = lb_emit_struct_ep(p, slice, 1); + slice = lb_emit_load(p, slice); + } else { + count_ptr = lb_add_local_generated(p, t_int, false).addr; + lb_emit_store(p, count_ptr, lb_slice_len(p, slice)); + } + lb_build_range_indexed(p, slice, val0_type, count_ptr, &val, &key, &loop, &done); + break; + } + case Type_Basic: { + lbValue string = lb_build_expr(p, expr); + if (is_type_pointer(string.type)) { + string = lb_emit_load(p, string); + } + if (is_type_untyped(expr_type)) { + lbAddr s = lb_add_local_generated(p, default_type(string.type), false); + lb_addr_store(p, s, string); + string = lb_addr_load(p, s); + } + Type *t = base_type(string.type); + GB_ASSERT(!is_type_cstring(t)); + lb_build_range_string(p, string, val0_type, &val, &key, &loop, &done); + break; + } + case Type_Tuple: + lb_build_range_tuple(p, expr, val0_type, val1_type, &val, &key, &loop, &done); + break; + default: + GB_PANIC("Cannot range over %s", type_to_string(expr_type)); + break; + } + } + + + if (is_map) { + if (val0_type) lb_store_range_stmt_val(p, rs->val0, key); + if (val1_type) lb_store_range_stmt_val(p, rs->val1, val); + } else { + if (val0_type) lb_store_range_stmt_val(p, rs->val0, val); + if (val1_type) lb_store_range_stmt_val(p, rs->val1, key); + } + + lb_push_target_list(p, rs->label, done, loop, nullptr); + + lb_build_stmt(p, rs->body); + + lb_close_scope(p, lbDeferExit_Default, nullptr); + lb_pop_target_list(p); + lb_emit_jump(p, loop); + lb_start_block(p, done); +} + +void lb_build_inline_range_stmt(lbProcedure *p, AstInlineRangeStmt *rs) { + lbModule *m = p->module; + + lb_open_scope(p); // Open scope here + + Type *val0_type = nullptr; + Type *val1_type = nullptr; + if (rs->val0 != nullptr && !is_blank_ident(rs->val0)) { + val0_type = type_of_expr(rs->val0); + } + if (rs->val1 != nullptr && !is_blank_ident(rs->val1)) { + val1_type = type_of_expr(rs->val1); + } + + if (val0_type != nullptr) { + Entity *e = entity_of_ident(rs->val0); + lb_add_local(p, e->type, e, true); + } + if (val1_type != nullptr) { + Entity *e = entity_of_ident(rs->val1); + lb_add_local(p, e->type, e, true); + } + + lbValue val = {}; + lbValue key = {}; + lbBlock *loop = nullptr; + lbBlock *done = nullptr; + Ast *expr = unparen_expr(rs->expr); + + TypeAndValue tav = type_and_value_of_expr(expr); + + if (is_ast_range(expr)) { + + lbAddr val0_addr = {}; + lbAddr val1_addr = {}; + if (val0_type) val0_addr = lb_build_addr(p, rs->val0); + if (val1_type) val1_addr = lb_build_addr(p, rs->val1); + + TokenKind op = expr->BinaryExpr.op.kind; + Ast *start_expr = expr->BinaryExpr.left; + Ast *end_expr = expr->BinaryExpr.right; + GB_ASSERT(start_expr->tav.mode == Addressing_Constant); + GB_ASSERT(end_expr->tav.mode == Addressing_Constant); + + ExactValue start = start_expr->tav.value; + ExactValue end = end_expr->tav.value; + if (op == Token_Ellipsis) { // .. [start, end] + ExactValue index = exact_value_i64(0); + for (ExactValue val = start; + compare_exact_values(Token_LtEq, val, end); + val = exact_value_increment_one(val), index = exact_value_increment_one(index)) { + + if (val0_type) lb_addr_store(p, val0_addr, lb_const_value(m, val0_type, val)); + if (val1_type) lb_addr_store(p, val1_addr, lb_const_value(m, val1_type, index)); + + lb_build_stmt(p, rs->body); + } + } else if (op == Token_RangeHalf) { // ..< [start, end) + ExactValue index = exact_value_i64(0); + for (ExactValue val = start; + compare_exact_values(Token_Lt, val, end); + val = exact_value_increment_one(val), index = exact_value_increment_one(index)) { + + if (val0_type) lb_addr_store(p, val0_addr, lb_const_value(m, val0_type, val)); + if (val1_type) lb_addr_store(p, val1_addr, lb_const_value(m, val1_type, index)); + + lb_build_stmt(p, rs->body); + } + } + + + } else if (tav.mode == Addressing_Type) { + GB_ASSERT(is_type_enum(type_deref(tav.type))); + Type *et = type_deref(tav.type); + Type *bet = base_type(et); + + lbAddr val0_addr = {}; + lbAddr val1_addr = {}; + if (val0_type) val0_addr = lb_build_addr(p, rs->val0); + if (val1_type) val1_addr = lb_build_addr(p, rs->val1); + + for_array(i, bet->Enum.fields) { + Entity *field = bet->Enum.fields[i]; + GB_ASSERT(field->kind == Entity_Constant); + if (val0_type) lb_addr_store(p, val0_addr, lb_const_value(m, val0_type, field->Constant.value)); + if (val1_type) lb_addr_store(p, val1_addr, lb_const_value(m, val1_type, exact_value_i64(i))); + + lb_build_stmt(p, rs->body); + } + } else { + lbAddr val0_addr = {}; + lbAddr val1_addr = {}; + if (val0_type) val0_addr = lb_build_addr(p, rs->val0); + if (val1_type) val1_addr = lb_build_addr(p, rs->val1); + + GB_ASSERT(expr->tav.mode == Addressing_Constant); + + Type *t = base_type(expr->tav.type); + + + switch (t->kind) { + case Type_Basic: + GB_ASSERT(is_type_string(t)); + { + ExactValue value = expr->tav.value; + GB_ASSERT(value.kind == ExactValue_String); + String str = value.value_string; + Rune codepoint = 0; + isize offset = 0; + do { + isize width = gb_utf8_decode(str.text+offset, str.len-offset, &codepoint); + if (val0_type) lb_addr_store(p, val0_addr, lb_const_value(m, val0_type, exact_value_i64(codepoint))); + if (val1_type) lb_addr_store(p, val1_addr, lb_const_value(m, val1_type, exact_value_i64(offset))); + lb_build_stmt(p, rs->body); + + offset += width; + } while (offset < str.len); + } + break; + case Type_Array: + if (t->Array.count > 0) { + lbValue val = lb_build_expr(p, expr); + lbValue val_addr = lb_address_from_load_or_generate_local(p, val); + + for (i64 i = 0; i < t->Array.count; i++) { + if (val0_type) { + // NOTE(bill): Due to weird legacy issues in LLVM, this needs to be an i32 + lbValue elem = lb_emit_array_epi(p, val_addr, cast(i32)i); + lb_addr_store(p, val0_addr, lb_emit_load(p, elem)); + } + if (val1_type) lb_addr_store(p, val1_addr, lb_const_value(m, val1_type, exact_value_i64(i))); + + lb_build_stmt(p, rs->body); + } + + } + break; + case Type_EnumeratedArray: + if (t->EnumeratedArray.count > 0) { + lbValue val = lb_build_expr(p, expr); + lbValue val_addr = lb_address_from_load_or_generate_local(p, val); + + for (i64 i = 0; i < t->EnumeratedArray.count; i++) { + if (val0_type) { + // NOTE(bill): Due to weird legacy issues in LLVM, this needs to be an i32 + lbValue elem = lb_emit_array_epi(p, val_addr, cast(i32)i); + lb_addr_store(p, val0_addr, lb_emit_load(p, elem)); + } + if (val1_type) { + ExactValue idx = exact_value_add(exact_value_i64(i), t->EnumeratedArray.min_value); + lb_addr_store(p, val1_addr, lb_const_value(m, val1_type, idx)); + } + + lb_build_stmt(p, rs->body); + } + + } + break; + default: + GB_PANIC("Invalid inline for type"); + break; + } + } + + + lb_close_scope(p, lbDeferExit_Default, nullptr); +} + + +void lb_build_switch_stmt(lbProcedure *p, AstSwitchStmt *ss) { + if (ss->init != nullptr) { + lb_build_stmt(p, ss->init); + } + lbValue tag = lb_const_bool(p->module, t_llvm_bool, true); + if (ss->tag != nullptr) { + tag = lb_build_expr(p, ss->tag); + } + lbBlock *done = lb_create_block(p, "switch.done"); // NOTE(bill): Append later + + ast_node(body, BlockStmt, ss->body); + + Array default_stmts = {}; + lbBlock *default_fall = nullptr; + lbBlock *default_block = nullptr; + + lbBlock *fall = nullptr; + + isize case_count = body->stmts.count; + for_array(i, body->stmts) { + Ast *clause = body->stmts[i]; + ast_node(cc, CaseClause, clause); + + lbBlock *body = fall; + + if (body == nullptr) { + body = lb_create_block(p, "switch.case.body"); + } + + fall = done; + if (i+1 < case_count) { + fall = lb_create_block(p, "switch.fall.body"); + } + + if (cc->list.count == 0) { + // default case + default_stmts = cc->stmts; + default_fall = fall; + default_block = body; + continue; + } + + lbBlock *next_cond = nullptr; + for_array(j, cc->list) { + Ast *expr = unparen_expr(cc->list[j]); + next_cond = lb_create_block(p, "switch.case.next"); + + lbValue cond = lb_const_bool(p->module, t_llvm_bool, false); + if (is_ast_range(expr)) { + ast_node(ie, BinaryExpr, expr); + TokenKind op = Token_Invalid; + switch (ie->op.kind) { + case Token_Ellipsis: op = Token_LtEq; break; + case Token_RangeHalf: op = Token_Lt; break; + default: GB_PANIC("Invalid interval operator"); break; + } + lbValue lhs = lb_build_expr(p, ie->left); + lbValue rhs = lb_build_expr(p, ie->right); + // TODO(bill): do short circuit here + lbValue cond_lhs = lb_emit_comp(p, Token_LtEq, lhs, tag); + lbValue cond_rhs = lb_emit_comp(p, op, tag, rhs); + cond = lb_emit_arith(p, Token_And, cond_lhs, cond_rhs, t_bool); + } else { + if (expr->tav.mode == Addressing_Type) { + GB_ASSERT(is_type_typeid(tag.type)); + lbValue e = lb_typeid(p->module, expr->tav.type); + e = lb_emit_conv(p, e, tag.type); + cond = lb_emit_comp(p, Token_CmpEq, tag, e); + } else { + cond = lb_emit_comp(p, Token_CmpEq, tag, lb_build_expr(p, expr)); + } + } + lb_emit_if(p, cond, body, next_cond); + lb_start_block(p, next_cond); + } + lb_start_block(p, body); + + lb_push_target_list(p, ss->label, done, nullptr, fall); + lb_open_scope(p); + lb_build_stmt_list(p, cc->stmts); + lb_close_scope(p, lbDeferExit_Default, body); + lb_pop_target_list(p); + + lb_emit_jump(p, done); + lb_start_block(p, next_cond); + } + + if (default_block != nullptr) { + lb_emit_jump(p, default_block); + lb_start_block(p, default_block); + + lb_push_target_list(p, ss->label, done, nullptr, default_fall); + lb_open_scope(p); + lb_build_stmt_list(p, default_stmts); + lb_close_scope(p, lbDeferExit_Default, default_block); + lb_pop_target_list(p); + } + + lb_emit_jump(p, done); + lb_start_block(p, done); +} + +void lb_store_type_case_implicit(lbProcedure *p, Ast *clause, lbValue value) { + Entity *e = implicit_entity_of_node(clause); + GB_ASSERT(e != nullptr); + if (e->flags & EntityFlag_Value) { + // by value + GB_ASSERT(are_types_identical(e->type, value.type)); + lbAddr x = lb_add_local(p, e->type, e, false); + lb_addr_store(p, x, value); + } else { + // by reference + GB_ASSERT(are_types_identical(e->type, type_deref(value.type))); + lb_add_entity(p->module, e, value); + } +} + +lbAddr lb_store_range_stmt_val(lbProcedure *p, Ast *stmt_val, lbValue value) { + Entity *e = entity_of_node(stmt_val); + if (e == nullptr) { + return {}; + } + + if ((e->flags & EntityFlag_Value) == 0) { + if (LLVMIsALoadInst(value.value)) { + lbValue ptr = lb_address_from_load_or_generate_local(p, value); + lb_add_entity(p->module, e, ptr); + return lb_addr(ptr); + } + } + + // by value + lbAddr addr = lb_add_local(p, e->type, e, false); + lb_addr_store(p, addr, value); + return addr; +} + +void lb_type_case_body(lbProcedure *p, Ast *label, Ast *clause, lbBlock *body, lbBlock *done) { + ast_node(cc, CaseClause, clause); + + lb_push_target_list(p, label, done, nullptr, nullptr); + lb_open_scope(p); + lb_build_stmt_list(p, cc->stmts); + lb_close_scope(p, lbDeferExit_Default, body); + lb_pop_target_list(p); + + lb_emit_jump(p, done); +} + + + +void lb_build_type_switch_stmt(lbProcedure *p, AstTypeSwitchStmt *ss) { + lbModule *m = p->module; + + ast_node(as, AssignStmt, ss->tag); + GB_ASSERT(as->lhs.count == 1); + GB_ASSERT(as->rhs.count == 1); + + lbValue parent = lb_build_expr(p, as->rhs[0]); + bool is_parent_ptr = is_type_pointer(parent.type); + + TypeSwitchKind switch_kind = check_valid_type_switch_type(parent.type); + GB_ASSERT(switch_kind != TypeSwitch_Invalid); + + lbValue parent_value = parent; + + lbValue parent_ptr = parent; + if (!is_parent_ptr) { + parent_ptr = lb_address_from_load_or_generate_local(p, parent); + } + + lbValue tag_index = {}; + lbValue union_data = {}; + if (switch_kind == TypeSwitch_Union) { + lbValue tag_ptr = lb_emit_union_tag_ptr(p, parent_ptr); + tag_index = lb_emit_load(p, tag_ptr); + union_data = lb_emit_conv(p, parent_ptr, t_rawptr); + } + + lbBlock *start_block = lb_create_block(p, "typeswitch.case.first"); + lb_emit_jump(p, start_block); + lb_start_block(p, start_block); + + // NOTE(bill): Append this later + lbBlock *done = lb_create_block(p, "typeswitch.done"); + Ast *default_ = nullptr; + + ast_node(body, BlockStmt, ss->body); + + gb_local_persist i32 weird_count = 0; + + for_array(i, body->stmts) { + Ast *clause = body->stmts[i]; + ast_node(cc, CaseClause, clause); + if (cc->list.count == 0) { + default_ = clause; + continue; + } + + lbBlock *body = lb_create_block(p, "typeswitch.body"); + lbBlock *next = nullptr; + Type *case_type = nullptr; + for_array(type_index, cc->list) { + next = lb_create_block(p, "typeswitch.next"); + case_type = type_of_expr(cc->list[type_index]); + lbValue cond = {}; + if (switch_kind == TypeSwitch_Union) { + Type *ut = base_type(type_deref(parent.type)); + lbValue variant_tag = lb_const_union_tag(m, ut, case_type); + cond = lb_emit_comp(p, Token_CmpEq, tag_index, variant_tag); + } else if (switch_kind == TypeSwitch_Any) { + lbValue any_typeid = lb_emit_load(p, lb_emit_struct_ep(p, parent_ptr, 1)); + lbValue case_typeid = lb_typeid(m, case_type); + cond = lb_emit_comp(p, Token_CmpEq, any_typeid, case_typeid); + } + GB_ASSERT(cond.value != nullptr); + + lb_emit_if(p, cond, body, next); + lb_start_block(p, next); + } + + Entity *case_entity = implicit_entity_of_node(clause); + + lbValue value = parent_value; + + lb_start_block(p, body); + + bool by_reference = (case_entity->flags & EntityFlag_Value) == 0; + + if (cc->list.count == 1) { + lbValue data = {}; + if (switch_kind == TypeSwitch_Union) { + data = union_data; + } else if (switch_kind == TypeSwitch_Any) { + lbValue any_data = lb_emit_load(p, lb_emit_struct_ep(p, parent_ptr, 0)); + data = any_data; + } + + Type *ct = case_entity->type; + Type *ct_ptr = alloc_type_pointer(ct); + + value = lb_emit_conv(p, data, ct_ptr); + if (!by_reference) { + value = lb_emit_load(p, value); + } + } + + lb_store_type_case_implicit(p, clause, value); + lb_type_case_body(p, ss->label, clause, body, done); + lb_start_block(p, next); + } + + if (default_ != nullptr) { + lb_store_type_case_implicit(p, default_, parent_value); + lb_type_case_body(p, ss->label, default_, p->curr_block, done); + } else { + lb_emit_jump(p, done); + } + lb_start_block(p, done); +} + + +lbValue lb_emit_logical_binary_expr(lbProcedure *p, TokenKind op, Ast *left, Ast *right, Type *type) { + lbModule *m = p->module; + + lbBlock *rhs = lb_create_block(p, "logical.cmp.rhs"); + lbBlock *done = lb_create_block(p, "logical.cmp.done"); + + type = default_type(type); + + lbValue short_circuit = {}; + if (op == Token_CmpAnd) { + lb_build_cond(p, left, rhs, done); + short_circuit = lb_const_bool(m, type, false); + } else if (op == Token_CmpOr) { + lb_build_cond(p, left, done, rhs); + short_circuit = lb_const_bool(m, type, true); + } + + if (rhs->preds.count == 0) { + lb_start_block(p, done); + return short_circuit; + } + + if (done->preds.count == 0) { + lb_start_block(p, rhs); + return lb_build_expr(p, right); + } + + Array incoming_values = {}; + Array incoming_blocks = {}; + array_init(&incoming_values, heap_allocator(), done->preds.count+1); + array_init(&incoming_blocks, heap_allocator(), done->preds.count+1); + + for_array(i, done->preds) { + incoming_values[i] = short_circuit.value; + incoming_blocks[i] = done->preds[i]->block; + } + + lb_start_block(p, rhs); + lbValue edge = lb_build_expr(p, right); + + incoming_values[done->preds.count] = edge.value; + incoming_blocks[done->preds.count] = p->curr_block->block; + + lb_emit_jump(p, done); + lb_start_block(p, done); + + lbValue res = {}; + res.type = type; + res.value = LLVMBuildPhi(p->builder, lb_type(m, type), ""); + GB_ASSERT(incoming_values.count == incoming_blocks.count); + LLVMAddIncoming(res.value, incoming_values.data, incoming_blocks.data, cast(unsigned)incoming_values.count); + + return res; +} + + +void lb_build_stmt(lbProcedure *p, Ast *node) { + switch (node->kind) { + case_ast_node(bs, EmptyStmt, node); + case_end; + + case_ast_node(us, UsingStmt, node); + case_end; + + case_ast_node(ws, WhenStmt, node); + lb_build_when_stmt(p, ws); + case_end; + + + case_ast_node(bs, BlockStmt, node); + if (bs->label != nullptr) { + lbBlock *done = lb_create_block(p, "block.done"); + lbTargetList *tl = lb_push_target_list(p, bs->label, done, nullptr, nullptr); + tl->is_block = true; + + lb_open_scope(p); + lb_build_stmt_list(p, bs->stmts); + lb_close_scope(p, lbDeferExit_Default, nullptr); + + lb_emit_jump(p, done); + lb_start_block(p, done); + } else { + lb_open_scope(p); + lb_build_stmt_list(p, bs->stmts); + lb_close_scope(p, lbDeferExit_Default, nullptr); + } + case_end; + + case_ast_node(vd, ValueDecl, node); + if (!vd->is_mutable) { + return; + } + + bool is_static = false; + if (vd->names.count > 0) { + Entity *e = entity_of_ident(vd->names[0]); + if (e->flags & EntityFlag_Static) { + // NOTE(bill): If one of the entities is static, they all are + is_static = true; + } + } + + if (is_static) { + for_array(i, vd->names) { + lbValue value = {}; + if (vd->values.count > 0) { + GB_ASSERT(vd->names.count == vd->values.count); + Ast *ast_value = vd->values[i]; + GB_ASSERT(ast_value->tav.mode == Addressing_Constant || + ast_value->tav.mode == Addressing_Invalid); + + value = lb_const_value(p->module, ast_value->tav.type, ast_value->tav.value); + } + + Ast *ident = vd->names[i]; + GB_ASSERT(!is_blank_ident(ident)); + Entity *e = entity_of_ident(ident); + GB_ASSERT(e->flags & EntityFlag_Static); + String name = e->token.string; + + String mangled_name = {}; + { + gbString str = gb_string_make_length(heap_allocator(), p->name.text, p->name.len); + str = gb_string_appendc(str, "-"); + str = gb_string_append_fmt(str, ".%.*s-%llu", LIT(name), cast(long long)e->id); + mangled_name.text = cast(u8 *)str; + mangled_name.len = gb_string_length(str); + } + + char *c_name = alloc_cstring(heap_allocator(), mangled_name); + + LLVMValueRef global = LLVMAddGlobal(p->module->mod, lb_type(p->module, e->type), c_name); + if (value.value != nullptr) { + LLVMSetInitializer(global, value.value); + } else { + LLVMSetInitializer(global, LLVMConstNull(lb_type(p->module, e->type))); + } + if (e->Variable.thread_local_model != "") { + LLVMSetThreadLocal(global, true); + + String m = e->Variable.thread_local_model; + LLVMThreadLocalMode mode = LLVMGeneralDynamicTLSModel; + if (m == "default") { + mode = LLVMGeneralDynamicTLSModel; + } else if (m == "localdynamic") { + mode = LLVMLocalDynamicTLSModel; + } else if (m == "initialexec") { + mode = LLVMInitialExecTLSModel; + } else if (m == "localexec") { + mode = LLVMLocalExecTLSModel; + } else { + GB_PANIC("Unhandled thread local mode %.*s", LIT(m)); + } + LLVMSetThreadLocalMode(global, mode); + } else { + LLVMSetLinkage(global, LLVMInternalLinkage); + } + + + lbValue global_val = {global, alloc_type_pointer(e->type)}; + lb_add_entity(p->module, e, global_val); + lb_add_member(p->module, mangled_name, global_val); + } + return; + } + + + if (vd->values.count == 0) { // declared and zero-initialized + for_array(i, vd->names) { + Ast *name = vd->names[i]; + if (!is_blank_ident(name)) { + Entity *e = entity_of_ident(name); + lb_add_local(p, e->type, e, true); + } + } + } else { // Tuple(s) + auto lvals = array_make(heap_allocator(), 0, vd->names.count); + auto inits = array_make(heap_allocator(), 0, vd->names.count); + + for_array(i, vd->names) { + Ast *name = vd->names[i]; + lbAddr lval = {}; + if (!is_blank_ident(name)) { + Entity *e = entity_of_ident(name); + lval = lb_add_local(p, e->type, e, false); + } + array_add(&lvals, lval); + } + + for_array(i, vd->values) { + lbValue init = lb_build_expr(p, vd->values[i]); + Type *t = init.type; + if (t->kind == Type_Tuple) { + for_array(i, t->Tuple.variables) { + Entity *e = t->Tuple.variables[i]; + lbValue v = lb_emit_struct_ev(p, init, cast(i32)i); + array_add(&inits, v); + } + } else { + array_add(&inits, init); + } + } + + + for_array(i, inits) { + lbAddr lval = lvals[i]; + lbValue init = inits[i]; + lb_addr_store(p, lval, init); + } + } + case_end; + + case_ast_node(as, AssignStmt, node); + if (as->op.kind == Token_Eq) { + auto lvals = array_make(heap_allocator(), 0, as->lhs.count); + + for_array(i, as->lhs) { + Ast *lhs = as->lhs[i]; + lbAddr lval = {}; + if (!is_blank_ident(lhs)) { + lval = lb_build_addr(p, lhs); + } + array_add(&lvals, lval); + } + + if (as->lhs.count == as->rhs.count) { + if (as->lhs.count == 1) { + lbAddr lval = lvals[0]; + Ast *rhs = as->rhs[0]; + lbValue init = lb_build_expr(p, rhs); + lb_addr_store(p, lvals[0], init); + } else { + auto inits = array_make(heap_allocator(), 0, lvals.count); + + for_array(i, as->rhs) { + lbValue init = lb_build_expr(p, as->rhs[i]); + array_add(&inits, init); + } + + for_array(i, inits) { + lbAddr lval = lvals[i]; + lbValue init = inits[i]; + lb_addr_store(p, lval, init); + } + } + } else { + auto inits = array_make(heap_allocator(), 0, lvals.count); + + for_array(i, as->rhs) { + lbValue init = lb_build_expr(p, as->rhs[i]); + Type *t = init.type; + // TODO(bill): refactor for code reuse as this is repeated a bit + if (t->kind == Type_Tuple) { + for_array(i, t->Tuple.variables) { + Entity *e = t->Tuple.variables[i]; + lbValue v = lb_emit_struct_ev(p, init, cast(i32)i); + array_add(&inits, v); + } + } else { + array_add(&inits, init); + } + } + + for_array(i, inits) { + lbAddr lval = lvals[i]; + lbValue init = inits[i]; + lb_addr_store(p, lval, init); + } + } + } else { + // NOTE(bill): Only 1 += 1 is allowed, no tuples + // +=, -=, etc + i32 op = cast(i32)as->op.kind; + op += Token_Add - Token_AddEq; // Convert += to + + if (op == Token_CmpAnd || op == Token_CmpOr) { + Type *type = as->lhs[0]->tav.type; + lbValue new_value = lb_emit_logical_binary_expr(p, cast(TokenKind)op, as->lhs[0], as->rhs[0], type); + + lbAddr lhs = lb_build_addr(p, as->lhs[0]); + lb_addr_store(p, lhs, new_value); + } else { + lbAddr lhs = lb_build_addr(p, as->lhs[0]); + lbValue value = lb_build_expr(p, as->rhs[0]); + + lbValue old_value = lb_addr_load(p, lhs); + Type *type = old_value.type; + + lbValue change = lb_emit_conv(p, value, type); + lbValue new_value = lb_emit_arith(p, cast(TokenKind)op, old_value, change, type); + lb_addr_store(p, lhs, new_value); + } + return; + } + case_end; + + case_ast_node(es, ExprStmt, node); + lb_build_expr(p, es->expr); + case_end; + + case_ast_node(ds, DeferStmt, node); + isize scope_index = p->scope_index; + lb_add_defer_node(p, scope_index, ds->stmt); + case_end; + + case_ast_node(rs, ReturnStmt, node); + lbValue res = {}; + + TypeTuple *tuple = &p->type->Proc.results->Tuple; + isize return_count = p->type->Proc.result_count; + isize res_count = rs->results.count; + + if (return_count == 0) { + // No return values + LLVMBuildRetVoid(p->builder); + return; + } else if (return_count == 1) { + Entity *e = tuple->variables[0]; + if (res_count == 0) { + lbValue *found = map_get(&p->module->values, hash_entity(e)); + GB_ASSERT(found); + res = lb_emit_load(p, *found); + } else { + res = lb_build_expr(p, rs->results[0]); + res = lb_emit_conv(p, res, e->type); + } + } else { + auto results = array_make(heap_allocator(), 0, return_count); + + if (res_count != 0) { + for (isize res_index = 0; res_index < res_count; res_index++) { + lbValue res = lb_build_expr(p, rs->results[res_index]); + Type *t = res.type; + if (t->kind == Type_Tuple) { + for_array(i, t->Tuple.variables) { + Entity *e = t->Tuple.variables[i]; + lbValue v = lb_emit_struct_ev(p, res, cast(i32)i); + array_add(&results, v); + } + } else { + array_add(&results, res); + } + } + } else { + for (isize res_index = 0; res_index < return_count; res_index++) { + Entity *e = tuple->variables[res_index]; + lbValue *found = map_get(&p->module->values, hash_entity(e)); + GB_ASSERT(found); + lbValue res = lb_emit_load(p, *found); + array_add(&results, res); + } + } + + GB_ASSERT(results.count == return_count); + + Type *ret_type = p->type->Proc.results; + // NOTE(bill): Doesn't need to be zero because it will be initialized in the loops + res = lb_add_local_generated(p, ret_type, false).addr; + for_array(i, results) { + Entity *e = tuple->variables[i]; + lbValue field = lb_emit_struct_ep(p, res, cast(i32)i); + lbValue val = lb_emit_conv(p, results[i], e->type); + lb_emit_store(p, field, val); + } + + res = lb_emit_load(p, res); + } + + lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr); + + if (p->type->Proc.return_by_pointer) { + if (res.value != nullptr) { + lb_addr_store(p, p->return_ptr, res); + } else { + lb_addr_store(p, p->return_ptr, lb_const_nil(p->module, p->type->Proc.abi_compat_result_type)); + } + LLVMBuildRetVoid(p->builder); + } else { + GB_ASSERT_MSG(res.value != nullptr, "%.*s", LIT(p->name)); + Type *abi_rt = p->type->Proc.abi_compat_result_type; + if (!are_types_identical(res.type, abi_rt)) { + res = lb_emit_transmute(p, res, abi_rt); + } + LLVMBuildRet(p->builder, res.value); + } + case_end; + + case_ast_node(is, IfStmt, node); + lb_open_scope(p); // Scope #1 + + if (is->init != nullptr) { + // TODO(bill): Should this have a separate block to begin with? + #if 1 + lbBlock *init = lb_create_block(p, "if.init"); + lb_emit_jump(p, init); + lb_start_block(p, init); + #endif + lb_build_stmt(p, is->init); + } + lbBlock *then = lb_create_block(p, "if.then"); + lbBlock *done = lb_create_block(p, "if.done"); + lbBlock *else_ = done; + if (is->else_stmt != nullptr) { + else_ = lb_create_block(p, "if.else"); + } + + lb_build_cond(p, is->cond, then, else_); + lb_start_block(p, then); + + if (is->label != nullptr) { + lbTargetList *tl = lb_push_target_list(p, is->label, done, nullptr, nullptr); + tl->is_block = true; + } + + lb_build_stmt(p, is->body); + + lb_emit_jump(p, done); + + if (is->else_stmt != nullptr) { + lb_start_block(p, else_); + + lb_open_scope(p); + lb_build_stmt(p, is->else_stmt); + lb_close_scope(p, lbDeferExit_Default, nullptr); + + lb_emit_jump(p, done); + } + + + lb_start_block(p, done); + lb_close_scope(p, lbDeferExit_Default, nullptr); + case_end; + + case_ast_node(fs, ForStmt, node); + lb_open_scope(p); // Open Scope here + + if (fs->init != nullptr) { + #if 1 + lbBlock *init = lb_create_block(p, "for.init"); + lb_emit_jump(p, init); + lb_start_block(p, init); + #endif + lb_build_stmt(p, fs->init); + } + lbBlock *body = lb_create_block(p, "for.body"); + lbBlock *done = lb_create_block(p, "for.done"); // NOTE(bill): Append later + lbBlock *loop = body; + if (fs->cond != nullptr) { + loop = lb_create_block(p, "for.loop"); + } + lbBlock *post = loop; + if (fs->post != nullptr) { + post = lb_create_block(p, "for.post"); + } + + + lb_emit_jump(p, loop); + lb_start_block(p, loop); + + if (loop != body) { + lb_build_cond(p, fs->cond, body, done); + lb_start_block(p, body); + } + + lb_push_target_list(p, fs->label, done, post, nullptr); + + lb_build_stmt(p, fs->body); + lb_close_scope(p, lbDeferExit_Default, nullptr); + + lb_pop_target_list(p); + + lb_emit_jump(p, post); + + if (fs->post != nullptr) { + lb_start_block(p, post); + lb_build_stmt(p, fs->post); + lb_emit_jump(p, loop); + } + + lb_start_block(p, done); + case_end; + + case_ast_node(rs, RangeStmt, node); + lb_build_range_stmt(p, rs); + case_end; + + case_ast_node(rs, InlineRangeStmt, node); + lb_build_inline_range_stmt(p, rs); + case_end; + + case_ast_node(ss, SwitchStmt, node); + lb_build_switch_stmt(p, ss); + case_end; + + case_ast_node(ss, TypeSwitchStmt, node); + lb_build_type_switch_stmt(p, ss); + case_end; + + case_ast_node(bs, BranchStmt, node); + lbBlock *block = nullptr; + + if (bs->label != nullptr) { + lbBranchBlocks bb = lb_lookup_branch_blocks(p, bs->label); + switch (bs->token.kind) { + case Token_break: block = bb.break_; break; + case Token_continue: block = bb.continue_; break; + case Token_fallthrough: + GB_PANIC("fallthrough cannot have a label"); + break; + } + } else { + for (lbTargetList *t = p->target_list; t != nullptr && block == nullptr; t = t->prev) { + if (t->is_block) { + continue; + } + + switch (bs->token.kind) { + case Token_break: block = t->break_; break; + case Token_continue: block = t->continue_; break; + case Token_fallthrough: block = t->fallthrough_; break; + } + } + } + if (block != nullptr) { + lb_emit_defer_stmts(p, lbDeferExit_Branch, block); + } + lb_emit_jump(p, block); + case_end; + } +} + +lbValue lb_emit_select(lbProcedure *p, lbValue cond, lbValue x, lbValue y) { + cond = lb_emit_conv(p, cond, t_llvm_bool); + lbValue res = {}; + res.value = LLVMBuildSelect(p->builder, cond.value, x.value, y.value, ""); + res.type = x.type; + return res; +} + +lbValue lb_const_nil(lbModule *m, Type *type) { + LLVMValueRef v = LLVMConstNull(lb_type(m, type)); + return lbValue{v, type}; +} + +lbValue lb_const_undef(lbModule *m, Type *type) { + LLVMValueRef v = LLVMGetUndef(lb_type(m, type)); + return lbValue{v, type}; +} + + +lbValue lb_const_int(lbModule *m, Type *type, u64 value) { + lbValue res = {}; + res.value = LLVMConstInt(lb_type(m, type), cast(unsigned long long)value, !is_type_unsigned(type)); + res.type = type; + return res; +} + +lbValue lb_const_string(lbModule *m, String const &value) { + return lb_const_value(m, t_string, exact_value_string(value)); +} + + +lbValue lb_const_bool(lbModule *m, Type *type, bool value) { + lbValue res = {}; + res.value = LLVMConstInt(lb_type(m, type), value, false); + res.type = type; + return res; +} + +LLVMValueRef lb_const_f32(lbModule *m, f32 f, Type *type=t_f32) { + u32 u = bit_cast(f); + LLVMValueRef i = LLVMConstInt(LLVMInt32TypeInContext(m->ctx), u, false); + return LLVMConstBitCast(i, lb_type(m, type)); +} + +lbValue lb_emit_min(lbProcedure *p, Type *t, lbValue x, lbValue y) { + x = lb_emit_conv(p, x, t); + y = lb_emit_conv(p, y, t); + + if (is_type_float(t)) { + gbAllocator a = heap_allocator(); + i64 sz = 8*type_size_of(t); + auto args = array_make(heap_allocator(), 2); + args[0] = x; + args[1] = y; + switch (sz) { + case 32: return lb_emit_runtime_call(p, "min_f32", args); + case 64: return lb_emit_runtime_call(p, "min_f64", args); + } + GB_PANIC("Unknown float type"); + } + return lb_emit_select(p, lb_emit_comp(p, Token_Lt, x, y), x, y); +} +lbValue lb_emit_max(lbProcedure *p, Type *t, lbValue x, lbValue y) { + x = lb_emit_conv(p, x, t); + y = lb_emit_conv(p, y, t); + + if (is_type_float(t)) { + gbAllocator a = heap_allocator(); + i64 sz = 8*type_size_of(t); + auto args = array_make(heap_allocator(), 2); + args[0] = x; + args[1] = y; + switch (sz) { + case 32: return lb_emit_runtime_call(p, "max_f32", args); + case 64: return lb_emit_runtime_call(p, "max_f64", args); + } + GB_PANIC("Unknown float type"); + } + return lb_emit_select(p, lb_emit_comp(p, Token_Gt, x, y), x, y); +} + + +lbValue lb_emit_clamp(lbProcedure *p, Type *t, lbValue x, lbValue min, lbValue max) { + lbValue z = {}; + z = lb_emit_max(p, t, x, min); + z = lb_emit_min(p, t, z, max); + return z; +} + + + +LLVMValueRef lb_find_or_add_entity_string_ptr(lbModule *m, String const &str) { + HashKey key = hash_string(str); + LLVMValueRef *found = map_get(&m->const_strings, key); + if (found != nullptr) { + return *found; + } else { + LLVMValueRef indices[2] = {llvm_zero32(m), llvm_zero32(m)}; + LLVMValueRef data = LLVMConstStringInContext(m->ctx, + cast(char const *)str.text, + cast(unsigned)str.len, + false); + + + isize max_len = 7+8+1; + char *name = gb_alloc_array(heap_allocator(), char, max_len); + isize len = gb_snprintf(name, max_len, "csbs$%x", m->global_array_index); + len -= 1; + m->global_array_index++; + + LLVMValueRef global_data = LLVMAddGlobal(m->mod, LLVMTypeOf(data), name); + LLVMSetInitializer(global_data, data); + + LLVMValueRef ptr = LLVMConstInBoundsGEP(global_data, indices, 2); + map_set(&m->const_strings, key, ptr); + return ptr; + } +} + +lbValue lb_find_or_add_entity_string(lbModule *m, String const &str) { + LLVMValueRef ptr = lb_find_or_add_entity_string_ptr(m, str); + LLVMValueRef str_len = LLVMConstInt(lb_type(m, t_int), str.len, true); + LLVMValueRef values[2] = {ptr, str_len}; + + lbValue res = {}; + res.value = LLVMConstNamedStruct(lb_type(m, t_string), values, 2); + res.type = t_string; + return res; +} + +lbValue lb_find_or_add_entity_string_byte_slice(lbModule *m, String const &str) { + LLVMValueRef indices[2] = {llvm_zero32(m), llvm_zero32(m)}; + LLVMValueRef data = LLVMConstStringInContext(m->ctx, + cast(char const *)str.text, + cast(unsigned)str.len, + false); + + + char *name = nullptr; + { + isize max_len = 7+8+1; + name = gb_alloc_array(heap_allocator(), char, max_len); + isize len = gb_snprintf(name, max_len, "csbs$%x", m->global_array_index); + len -= 1; + m->global_array_index++; + } + LLVMValueRef global_data = LLVMAddGlobal(m->mod, LLVMTypeOf(data), name); + LLVMSetInitializer(global_data, data); + + LLVMValueRef ptr = LLVMConstInBoundsGEP(global_data, indices, 2); + LLVMValueRef len = LLVMConstInt(lb_type(m, t_int), str.len, true); + LLVMValueRef values[2] = {ptr, len}; + + lbValue res = {}; + res.value = LLVMConstNamedStruct(lb_type(m, t_u8_slice), values, 2); + res.type = t_u8_slice; + return res; +} + +isize lb_type_info_index(CheckerInfo *info, Type *type, bool err_on_not_found=true) { + isize index = type_info_index(info, type, false); + if (index >= 0) { + auto *set = &info->minimum_dependency_type_info_set; + for_array(i, set->entries) { + if (set->entries[i].ptr == index) { + return i+1; + } + } + } + if (err_on_not_found) { + GB_PANIC("NOT FOUND lb_type_info_index %s @ index %td", type_to_string(type), index); + } + return -1; +} + +lbValue lb_typeid(lbModule *m, Type *type, Type *typeid_type) { + type = default_type(type); + + u64 id = cast(u64)lb_type_info_index(m->info, type); + GB_ASSERT(id >= 0); + + u64 kind = Typeid_Invalid; + u64 named = is_type_named(type) && type->kind != Type_Basic; + u64 special = 0; + u64 reserved = 0; + + Type *bt = base_type(type); + TypeKind tk = bt->kind; + switch (tk) { + case Type_Basic: { + u32 flags = bt->Basic.flags; + if (flags & BasicFlag_Boolean) kind = Typeid_Boolean; + if (flags & BasicFlag_Integer) kind = Typeid_Integer; + if (flags & BasicFlag_Unsigned) kind = Typeid_Integer; + if (flags & BasicFlag_Float) kind = Typeid_Float; + if (flags & BasicFlag_Complex) kind = Typeid_Complex; + if (flags & BasicFlag_Pointer) kind = Typeid_Pointer; + if (flags & BasicFlag_String) kind = Typeid_String; + if (flags & BasicFlag_Rune) kind = Typeid_Rune; + } break; + case Type_Pointer: kind = Typeid_Pointer; break; + case Type_Array: kind = Typeid_Array; break; + case Type_EnumeratedArray: kind = Typeid_Enumerated_Array; break; + case Type_Slice: kind = Typeid_Slice; break; + case Type_DynamicArray: kind = Typeid_Dynamic_Array; break; + case Type_Map: kind = Typeid_Map; break; + case Type_Struct: kind = Typeid_Struct; break; + case Type_Enum: kind = Typeid_Enum; break; + case Type_Union: kind = Typeid_Union; break; + case Type_Tuple: kind = Typeid_Tuple; break; + case Type_Proc: kind = Typeid_Procedure; break; + case Type_BitField: kind = Typeid_Bit_Field; break; + case Type_BitSet: kind = Typeid_Bit_Set; break; + } + + if (is_type_cstring(type)) { + special = 1; + } else if (is_type_integer(type) && !is_type_unsigned(type)) { + special = 1; + } + + u64 data = 0; + if (build_context.word_size == 4) { + data |= (id &~ (1u<<24)) << 0u; // index + data |= (kind &~ (1u<<5)) << 24u; // kind + data |= (named &~ (1u<<1)) << 29u; // kind + data |= (special &~ (1u<<1)) << 30u; // kind + data |= (reserved &~ (1u<<1)) << 31u; // kind + } else { + GB_ASSERT(build_context.word_size == 8); + data |= (id &~ (1ull<<56)) << 0ul; // index + data |= (kind &~ (1ull<<5)) << 56ull; // kind + data |= (named &~ (1ull<<1)) << 61ull; // kind + data |= (special &~ (1ull<<1)) << 62ull; // kind + data |= (reserved &~ (1ull<<1)) << 63ull; // kind + } + + + lbValue res = {}; + res.value = LLVMConstInt(lb_type(m, typeid_type), data, false); + res.type = typeid_type; + return res; +} + +lbValue lb_type_info(lbModule *m, Type *type) { + type = default_type(type); + + isize index = lb_type_info_index(m->info, type); + GB_ASSERT(index >= 0); + + LLVMTypeRef it = lb_type(m, t_int); + LLVMValueRef indices[2] = { + LLVMConstInt(it, 0, false), + LLVMConstInt(it, index, true), + }; + + lbValue value = {}; + value.value = LLVMConstGEP(lb_global_type_info_data.addr.value, indices, gb_count_of(indices)); + value.type = t_type_info_ptr; + return value; +} + + +lbValue lb_const_value(lbModule *m, Type *type, ExactValue value) { + LLVMContextRef ctx = m->ctx; + + type = default_type(type); + Type *original_type = type; + + lbValue res = {}; + res.type = original_type; + type = core_type(type); + value = convert_exact_value_for_type(value, type); + + if (value.kind == ExactValue_Typeid) { + return lb_typeid(m, value.value_typeid, original_type); + } + + if (value.kind == ExactValue_Invalid) { + return lb_const_nil(m, type); + } + + // GB_ASSERT_MSG(is_type_typed(type), "%s", type_to_string(type)); + + if (is_type_slice(type)) { + if (value.kind == ExactValue_String) { + GB_ASSERT(is_type_u8_slice(type)); + res.value = lb_find_or_add_entity_string_byte_slice(m, value.value_string).value; + return res; + } else { + ast_node(cl, CompoundLit, value.value_compound); + + isize count = cl->elems.count; + if (count == 0) { + return lb_const_nil(m, type); + } + count = gb_max(cl->max_count, count); + Type *elem = base_type(type)->Slice.elem; + Type *t = alloc_type_array(elem, count); + lbValue backing_array = lb_const_value(m, t, value); + + + isize max_len = 7+8+1; + char *str = gb_alloc_array(heap_allocator(), char, max_len); + isize len = gb_snprintf(str, max_len, "csba$%x", m->global_array_index); + m->global_array_index++; + + String name = make_string(cast(u8 *)str, len-1); + + Entity *e = alloc_entity_constant(nullptr, make_token_ident(name), t, value); + LLVMValueRef global_data = LLVMAddGlobal(m->mod, lb_type(m, t), str); + LLVMSetInitializer(global_data, backing_array.value); + + lbValue g = {}; + g.value = global_data; + g.type = t; + + lb_add_entity(m, e, g); + lb_add_member(m, name, g); + + { + LLVMValueRef indices[2] = {llvm_zero32(m), llvm_zero32(m)}; + LLVMValueRef ptr = LLVMConstInBoundsGEP(global_data, indices, 2); + LLVMValueRef len = LLVMConstInt(lb_type(m, t_int), count, true); + LLVMValueRef values[2] = {ptr, len}; + + res.value = LLVMConstNamedStruct(lb_type(m, original_type), values, 2); + return res; + } + + } + } else if (is_type_array(type) && value.kind == ExactValue_String && !is_type_u8(core_array_type(type))) { + LLVMValueRef data = LLVMConstStringInContext(ctx, + cast(char const *)value.value_string.text, + cast(unsigned)value.value_string.len, + false); + res.value = data; + return res; + } else if (is_type_array(type) && + value.kind != ExactValue_Invalid && + value.kind != ExactValue_String && + value.kind != ExactValue_Compound) { + + i64 count = type->Array.count; + Type *elem = type->Array.elem; + + + lbValue single_elem = lb_const_value(m, elem, value); + + LLVMValueRef *elems = gb_alloc_array(heap_allocator(), LLVMValueRef, count); + for (i64 i = 0; i < count; i++) { + elems[i] = single_elem.value; + } + + res.value = LLVMConstArray(lb_type(m, elem), elems, cast(unsigned)count); + return res; + } + + switch (value.kind) { + case ExactValue_Invalid: + res.value = LLVMConstNull(lb_type(m, original_type)); + return res; + case ExactValue_Bool: + res.value = LLVMConstInt(lb_type(m, original_type), value.value_bool, false); + return res; + case ExactValue_String: + { + LLVMValueRef ptr = lb_find_or_add_entity_string_ptr(m, value.value_string); + lbValue res = {}; + res.type = default_type(original_type); + if (is_type_cstring(res.type)) { + res.value = ptr; + } else { + LLVMValueRef str_len = LLVMConstInt(lb_type(m, t_int), value.value_string.len, true); + LLVMValueRef values[2] = {ptr, str_len}; + + res.value = LLVMConstNamedStruct(lb_type(m, original_type), values, 2); + } + + return res; + } + + case ExactValue_Integer: + if (is_type_pointer(type)) { + LLVMValueRef i = LLVMConstIntOfArbitraryPrecision(lb_type(m, t_uintptr), cast(unsigned)value.value_integer.len, big_int_ptr(&value.value_integer)); + res.value = LLVMConstIntToPtr(i, lb_type(m, original_type)); + } else { + res.value = LLVMConstIntOfArbitraryPrecision(lb_type(m, original_type), cast(unsigned)value.value_integer.len, big_int_ptr(&value.value_integer)); + if (value.value_integer.neg) { + res.value = LLVMConstNeg(res.value); + } + } + return res; + case ExactValue_Float: + if (type_size_of(type) == 4) { + f32 f = cast(f32)value.value_float; + res.value = lb_const_f32(m, f, type); + return res; + } + res.value = LLVMConstReal(lb_type(m, original_type), value.value_float); + return res; + case ExactValue_Complex: + { + LLVMValueRef values[2] = {}; + switch (8*type_size_of(type)) { + case 64: + values[0] = lb_const_f32(m, cast(f32)value.value_complex.real); + values[1] = lb_const_f32(m, cast(f32)value.value_complex.imag); + break; + case 128: + values[0] = LLVMConstReal(lb_type(m, t_f64), value.value_complex.real); + values[1] = LLVMConstReal(lb_type(m, t_f64), value.value_complex.imag); + break; + } + + res.value = LLVMConstNamedStruct(lb_type(m, original_type), values, 2); + return res; + } + break; + case ExactValue_Quaternion: + { + LLVMValueRef values[4] = {}; + switch (8*type_size_of(type)) { + case 128: + // @QuaternionLayout + values[3] = lb_const_f32(m, cast(f32)value.value_quaternion.real); + values[0] = lb_const_f32(m, cast(f32)value.value_quaternion.imag); + values[1] = lb_const_f32(m, cast(f32)value.value_quaternion.jmag); + values[2] = lb_const_f32(m, cast(f32)value.value_quaternion.kmag); + break; + case 256: + // @QuaternionLayout + values[3] = LLVMConstReal(lb_type(m, t_f64), value.value_quaternion.real); + values[0] = LLVMConstReal(lb_type(m, t_f64), value.value_quaternion.imag); + values[1] = LLVMConstReal(lb_type(m, t_f64), value.value_quaternion.jmag); + values[2] = LLVMConstReal(lb_type(m, t_f64), value.value_quaternion.kmag); + break; + } + + res.value = LLVMConstNamedStruct(lb_type(m, original_type), values, 4); + return res; + } + break; + + case ExactValue_Pointer: + res.value = LLVMConstIntToPtr(LLVMConstInt(lb_type(m, t_uintptr), value.value_pointer, false), lb_type(m, original_type)); + return res; + + case ExactValue_Compound: + if (is_type_slice(type)) { + return lb_const_value(m, type, value); + } else if (is_type_array(type)) { + ast_node(cl, CompoundLit, value.value_compound); + Type *elem_type = type->Array.elem; + isize elem_count = cl->elems.count; + if (elem_count == 0) { + return lb_const_nil(m, original_type); + } + if (cl->elems[0]->kind == Ast_FieldValue) { + // TODO(bill): This is O(N*M) and will be quite slow; it should probably be sorted before hand + + LLVMValueRef *values = gb_alloc_array(heap_allocator(), LLVMValueRef, type->Array.count); + defer (gb_free(heap_allocator(), values)); + + isize value_index = 0; + for (i64 i = 0; i < type->Array.count; i++) { + bool found = false; + + for (isize j = 0; j < elem_count; j++) { + Ast *elem = cl->elems[j]; + ast_node(fv, FieldValue, elem); + if (is_ast_range(fv->field)) { + ast_node(ie, BinaryExpr, fv->field); + TypeAndValue lo_tav = ie->left->tav; + TypeAndValue hi_tav = ie->right->tav; + GB_ASSERT(lo_tav.mode == Addressing_Constant); + GB_ASSERT(hi_tav.mode == Addressing_Constant); + + TokenKind op = ie->op.kind; + i64 lo = exact_value_to_i64(lo_tav.value); + i64 hi = exact_value_to_i64(hi_tav.value); + if (op == Token_Ellipsis) { + hi += 1; + } + if (lo == i) { + TypeAndValue tav = fv->value->tav; + if (tav.mode != Addressing_Constant) { + break; + } + LLVMValueRef val = lb_const_value(m, elem_type, tav.value).value; + for (i64 k = lo; k < hi; k++) { + values[value_index++] = val; + } + + found = true; + i += (hi-lo-1); + break; + } + } else { + TypeAndValue index_tav = fv->field->tav; + GB_ASSERT(index_tav.mode == Addressing_Constant); + i64 index = exact_value_to_i64(index_tav.value); + if (index == i) { + TypeAndValue tav = fv->value->tav; + if (tav.mode != Addressing_Constant) { + break; + } + LLVMValueRef val = lb_const_value(m, elem_type, tav.value).value; + values[value_index++] = val; + found = true; + break; + } + } + } + + if (!found) { + values[value_index++] = LLVMConstNull(lb_type(m, elem_type)); + } + } + + res.value = LLVMConstArray(lb_type(m, elem_type), values, cast(unsigned int)type->Array.count); + return res; + } else { + GB_ASSERT_MSG(elem_count == type->Array.count, "%td != %td", elem_count, type->Array.count); + + LLVMValueRef *values = gb_alloc_array(heap_allocator(), LLVMValueRef, type->Array.count); + defer (gb_free(heap_allocator(), values)); + + for (isize i = 0; i < elem_count; i++) { + TypeAndValue tav = cl->elems[i]->tav; + GB_ASSERT(tav.mode != Addressing_Invalid); + values[i] = lb_const_value(m, elem_type, tav.value).value; + } + for (isize i = elem_count; i < type->Array.count; i++) { + values[i] = LLVMConstNull(lb_type(m, elem_type)); + } + + res.value = LLVMConstArray(lb_type(m, elem_type), values, cast(unsigned int)type->Array.count); + return res; + } + } else if (is_type_enumerated_array(type)) { + ast_node(cl, CompoundLit, value.value_compound); + Type *elem_type = type->EnumeratedArray.elem; + isize elem_count = cl->elems.count; + if (elem_count == 0) { + return lb_const_nil(m, original_type); + } + if (cl->elems[0]->kind == Ast_FieldValue) { + // TODO(bill): This is O(N*M) and will be quite slow; it should probably be sorted before hand + + LLVMValueRef *values = gb_alloc_array(heap_allocator(), LLVMValueRef, type->EnumeratedArray.count); + defer (gb_free(heap_allocator(), values)); + + isize value_index = 0; + + i64 total_lo = exact_value_to_i64(type->EnumeratedArray.min_value); + i64 total_hi = exact_value_to_i64(type->EnumeratedArray.max_value); + + for (i64 i = total_lo; i <= total_hi; i++) { + bool found = false; + + for (isize j = 0; j < elem_count; j++) { + Ast *elem = cl->elems[j]; + ast_node(fv, FieldValue, elem); + if (is_ast_range(fv->field)) { + ast_node(ie, BinaryExpr, fv->field); + TypeAndValue lo_tav = ie->left->tav; + TypeAndValue hi_tav = ie->right->tav; + GB_ASSERT(lo_tav.mode == Addressing_Constant); + GB_ASSERT(hi_tav.mode == Addressing_Constant); + + TokenKind op = ie->op.kind; + i64 lo = exact_value_to_i64(lo_tav.value); + i64 hi = exact_value_to_i64(hi_tav.value); + if (op == Token_Ellipsis) { + hi += 1; + } + if (lo == i) { + TypeAndValue tav = fv->value->tav; + if (tav.mode != Addressing_Constant) { + break; + } + LLVMValueRef val = lb_const_value(m, elem_type, tav.value).value; + for (i64 k = lo; k < hi; k++) { + values[value_index++] = val; + } + + found = true; + i += (hi-lo-1); + break; + } + } else { + TypeAndValue index_tav = fv->field->tav; + GB_ASSERT(index_tav.mode == Addressing_Constant); + i64 index = exact_value_to_i64(index_tav.value); + if (index == i) { + TypeAndValue tav = fv->value->tav; + if (tav.mode != Addressing_Constant) { + break; + } + LLVMValueRef val = lb_const_value(m, elem_type, tav.value).value; + values[value_index++] = val; + found = true; + break; + } + } + } + + if (!found) { + values[value_index++] = LLVMConstNull(lb_type(m, elem_type)); + } + } + + res.value = LLVMConstArray(lb_type(m, elem_type), values, cast(unsigned int)type->EnumeratedArray.count); + return res; + } else { + GB_ASSERT_MSG(elem_count == type->EnumeratedArray.count, "%td != %td", elem_count, type->EnumeratedArray.count); + + LLVMValueRef *values = gb_alloc_array(heap_allocator(), LLVMValueRef, type->EnumeratedArray.count); + defer (gb_free(heap_allocator(), values)); + + for (isize i = 0; i < elem_count; i++) { + TypeAndValue tav = cl->elems[i]->tav; + GB_ASSERT(tav.mode != Addressing_Invalid); + values[i] = lb_const_value(m, elem_type, tav.value).value; + } + for (isize i = elem_count; i < type->EnumeratedArray.count; i++) { + values[i] = LLVMConstNull(lb_type(m, elem_type)); + } + + res.value = LLVMConstArray(lb_type(m, elem_type), values, cast(unsigned int)type->EnumeratedArray.count); + return res; + } + } else if (is_type_simd_vector(type)) { + ast_node(cl, CompoundLit, value.value_compound); + + Type *elem_type = type->SimdVector.elem; + isize elem_count = cl->elems.count; + if (elem_count == 0) { + return lb_const_nil(m, original_type); + } + + isize total_elem_count = type->SimdVector.count; + LLVMValueRef *values = gb_alloc_array(heap_allocator(), LLVMValueRef, total_elem_count); + defer (gb_free(heap_allocator(), values)); + + for (isize i = 0; i < elem_count; i++) { + TypeAndValue tav = cl->elems[i]->tav; + GB_ASSERT(tav.mode != Addressing_Invalid); + values[i] = lb_const_value(m, elem_type, tav.value).value; + } + for (isize i = elem_count; i < type->SimdVector.count; i++) { + values[i] = LLVMConstNull(lb_type(m, elem_type)); + } + + res.value = LLVMConstVector(values, cast(unsigned)total_elem_count); + return res; + } else if (is_type_struct(type)) { + ast_node(cl, CompoundLit, value.value_compound); + + if (cl->elems.count == 0) { + return lb_const_nil(m, original_type); + } + + isize offset = 0; + if (type->Struct.custom_align > 0) { + offset = 1; + } + + isize value_count = type->Struct.fields.count + offset; + LLVMValueRef *values = gb_alloc_array(heap_allocator(), LLVMValueRef, value_count); + bool *visited = gb_alloc_array(heap_allocator(), bool, value_count); + defer (gb_free(heap_allocator(), values)); + defer (gb_free(heap_allocator(), visited)); + + + + if (cl->elems.count > 0) { + if (cl->elems[0]->kind == Ast_FieldValue) { + isize elem_count = cl->elems.count; + for (isize i = 0; i < elem_count; i++) { + ast_node(fv, FieldValue, cl->elems[i]); + String name = fv->field->Ident.token.string; + + TypeAndValue tav = fv->value->tav; + GB_ASSERT(tav.mode != Addressing_Invalid); + + Selection sel = lookup_field(type, name, false); + Entity *f = type->Struct.fields[sel.index[0]]; + + values[offset+f->Variable.field_index] = lb_const_value(m, f->type, tav.value).value; + visited[offset+f->Variable.field_index] = true; + } + } else { + for_array(i, cl->elems) { + Entity *f = type->Struct.fields[i]; + TypeAndValue tav = cl->elems[i]->tav; + ExactValue val = {}; + if (tav.mode != Addressing_Invalid) { + val = tav.value; + } + values[offset+f->Variable.field_index] = lb_const_value(m, f->type, val).value; + visited[offset+f->Variable.field_index] = true; + } + } + } + + for (isize i = 0; i < type->Struct.fields.count; i++) { + if (!visited[offset+i]) { + GB_ASSERT(values[offset+i] == nullptr); + values[offset+i] = lb_const_nil(m, get_struct_field_type(type, i)).value; + } + } + + if (type->Struct.custom_align > 0) { + values[0] = LLVMConstNull(lb_alignment_prefix_type_hack(m, type->Struct.custom_align)); + } + + res.value = LLVMConstNamedStruct(lb_type(m, original_type), values, cast(unsigned)value_count); + return res; + } else if (is_type_bit_set(type)) { + ast_node(cl, CompoundLit, value.value_compound); + if (cl->elems.count == 0) { + return lb_const_nil(m, original_type); + } + + i64 sz = type_size_of(type); + if (sz == 0) { + return lb_const_nil(m, original_type); + } + + u64 bits = 0; + for_array(i, cl->elems) { + Ast *e = cl->elems[i]; + GB_ASSERT(e->kind != Ast_FieldValue); + + TypeAndValue tav = e->tav; + if (tav.mode != Addressing_Constant) { + continue; + } + GB_ASSERT(tav.value.kind == ExactValue_Integer); + i64 v = big_int_to_i64(&tav.value.value_integer); + i64 lower = type->BitSet.lower; + bits |= 1ull<kind == Ast_ProcLit) { + return lb_generate_anonymous_proc_lit(m, str_lit("_proclit"), expr); + } + } + break; + case ExactValue_Typeid: + return lb_typeid(m, value.value_typeid, original_type); + } + + return lb_const_nil(m, original_type); +} + +u64 lb_generate_source_code_location_hash(TokenPos const &pos) { + u64 h = 0xcbf29ce484222325; + for (isize i = 0; i < pos.file.len; i++) { + h = (h ^ u64(pos.file[i])) * 0x100000001b3; + } + h = h ^ (u64(pos.line) * 0x100000001b3); + h = h ^ (u64(pos.column) * 0x100000001b3); + return h; +} + +lbValue lb_emit_source_code_location(lbProcedure *p, String const &procedure, TokenPos const &pos) { + lbModule *m = p->module; + + LLVMValueRef fields[5] = {}; + fields[0]/*file*/ = lb_find_or_add_entity_string(p->module, pos.file).value; + fields[1]/*line*/ = lb_const_int(m, t_int, pos.line).value; + fields[2]/*column*/ = lb_const_int(m, t_int, pos.column).value; + fields[3]/*procedure*/ = lb_find_or_add_entity_string(p->module, procedure).value; + fields[4]/*hash*/ = lb_const_int(m, t_u64, lb_generate_source_code_location_hash(pos)).value; + + lbValue res = {}; + res.value = LLVMConstNamedStruct(lb_type(m, t_source_code_location), fields, 5); + res.type = t_source_code_location; + return res; +} + +lbValue lb_emit_source_code_location(lbProcedure *p, Ast *node) { + String proc_name = {}; + if (p->entity) { + proc_name = p->entity->token.string; + } + TokenPos pos = {}; + if (node) { + pos = ast_token(node).pos; + } + return lb_emit_source_code_location(p, proc_name, pos); +} + + +lbValue lb_emit_unary_arith(lbProcedure *p, TokenKind op, lbValue x, Type *type) { + switch (op) { + case Token_Add: + return x; + case Token_Not: // Boolean not + case Token_Xor: // Bitwise not + case Token_Sub: // Number negation + break; + case Token_Pointer: + GB_PANIC("This should be handled elsewhere"); + break; + } + + if (is_type_array(x.type)) { + // IMPORTANT TODO(bill): This is very wasteful with regards to stack memory + Type *tl = base_type(x.type); + lbValue val = lb_address_from_load_or_generate_local(p, x); + GB_ASSERT(is_type_array(type)); + Type *elem_type = base_array_type(type); + + // NOTE(bill): Doesn't need to be zero because it will be initialized in the loops + lbAddr res_addr = lb_add_local_generated(p, type, false); + lbValue res = lb_addr_get_ptr(p, res_addr); + + bool inline_array_arith = type_size_of(type) <= build_context.max_align; + + i32 count = cast(i32)tl->Array.count; + + if (inline_array_arith) { + // inline + for (i32 i = 0; i < count; i++) { + lbValue e = lb_emit_load(p, lb_emit_array_epi(p, val, i)); + lbValue z = lb_emit_unary_arith(p, op, e, elem_type); + lb_emit_store(p, lb_emit_array_epi(p, res, i), z); + } + } else { + auto loop_data = lb_loop_start(p, count, t_i32); + + lbValue e = lb_emit_load(p, lb_emit_array_ep(p, val, loop_data.idx)); + lbValue z = lb_emit_unary_arith(p, op, e, elem_type); + lb_emit_store(p, lb_emit_array_ep(p, res, loop_data.idx), z); + + lb_loop_end(p, loop_data); + } + return lb_emit_load(p, res); + + } + + if (op == Token_Xor) { + lbValue cmp = {}; + cmp.value = LLVMBuildNot(p->builder, x.value, ""); + cmp.type = x.type; + return lb_emit_conv(p, cmp, type); + } + + if (op == Token_Not) { + lbValue cmp = {}; + LLVMValueRef zero = LLVMConstInt(lb_type(p->module, x.type), 0, false); + cmp.value = LLVMBuildICmp(p->builder, LLVMIntEQ, x.value, zero, ""); + cmp.type = t_llvm_bool; + return lb_emit_conv(p, cmp, type); + } + + if (op == Token_Sub && is_type_integer(type) && is_type_different_to_arch_endianness(type)) { + Type *platform_type = integer_endian_type_to_platform_type(type); + lbValue v = lb_emit_byte_swap(p, x, platform_type); + + lbValue res = {}; + res.value = LLVMBuildNeg(p->builder, v.value, ""); + res.type = platform_type; + + return lb_emit_byte_swap(p, res, type); + } + + + lbValue res = {}; + + switch (op) { + case Token_Not: // Boolean not + case Token_Xor: // Bitwise not + res.value = LLVMBuildNot(p->builder, x.value, ""); + res.type = x.type; + return res; + case Token_Sub: // Number negation + if (is_type_integer(x.type)) { + res.value = LLVMBuildNeg(p->builder, x.value, ""); + } else if (is_type_float(x.type)) { + res.value = LLVMBuildFNeg(p->builder, x.value, ""); + } else { + GB_PANIC("Unhandled type %s", type_to_string(x.type)); + } + res.type = x.type; + return res; + } + + return res; +} + + + +lbValue lb_emit_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type) { + lbModule *m = p->module; + + if (is_type_array(lhs.type) || is_type_array(rhs.type)) { + lhs = lb_emit_conv(p, lhs, type); + rhs = lb_emit_conv(p, rhs, type); + + lbValue x = lb_address_from_load_or_generate_local(p, lhs); + lbValue y = lb_address_from_load_or_generate_local(p, rhs); + + GB_ASSERT(is_type_array(type)); + Type *elem_type = base_array_type(type); + + lbAddr res = lb_add_local_generated(p, type, false); + + i64 count = base_type(type)->Array.count; + + bool inline_array_arith = type_size_of(type) <= build_context.max_align; + + if (inline_array_arith) { + for (i64 i = 0; i < count; i++) { + lbValue a = lb_emit_load(p, lb_emit_array_epi(p, x, i)); + lbValue b = lb_emit_load(p, lb_emit_array_epi(p, y, i)); + lbValue c = lb_emit_arith(p, op, a, b, elem_type); + lb_emit_store(p, lb_emit_array_epi(p, res.addr, i), c); + } + } else { + auto loop_data = lb_loop_start(p, count); + + lbValue a = lb_emit_load(p, lb_emit_array_ep(p, x, loop_data.idx)); + lbValue b = lb_emit_load(p, lb_emit_array_ep(p, y, loop_data.idx)); + lbValue c = lb_emit_arith(p, op, a, b, elem_type); + lb_emit_store(p, lb_emit_array_ep(p, res.addr, loop_data.idx), c); + + lb_loop_end(p, loop_data); + } + + return lb_addr_load(p, res); + } else if (is_type_complex(type)) { + lhs = lb_emit_conv(p, lhs, type); + rhs = lb_emit_conv(p, rhs, type); + + Type *ft = base_complex_elem_type(type); + + if (op == Token_Quo) { + auto args = array_make(heap_allocator(), 2); + args[0] = lhs; + args[1] = rhs; + + switch (type_size_of(ft)) { + case 4: return lb_emit_runtime_call(p, "quo_complex64", args); + case 8: return lb_emit_runtime_call(p, "quo_complex128", args); + default: GB_PANIC("Unknown float type"); break; + } + } + + lbAddr res = lb_add_local_generated(p, type, false); // NOTE: initialized in full later + lbValue a = lb_emit_struct_ev(p, lhs, 0); + lbValue b = lb_emit_struct_ev(p, lhs, 1); + lbValue c = lb_emit_struct_ev(p, rhs, 0); + lbValue d = lb_emit_struct_ev(p, rhs, 1); + + lbValue real = {}; + lbValue imag = {}; + + switch (op) { + case Token_Add: + real = lb_emit_arith(p, Token_Add, a, c, ft); + imag = lb_emit_arith(p, Token_Add, b, d, ft); + break; + case Token_Sub: + real = lb_emit_arith(p, Token_Sub, a, c, ft); + imag = lb_emit_arith(p, Token_Sub, b, d, ft); + break; + case Token_Mul: { + lbValue x = lb_emit_arith(p, Token_Mul, a, c, ft); + lbValue y = lb_emit_arith(p, Token_Mul, b, d, ft); + real = lb_emit_arith(p, Token_Sub, x, y, ft); + lbValue z = lb_emit_arith(p, Token_Mul, b, c, ft); + lbValue w = lb_emit_arith(p, Token_Mul, a, d, ft); + imag = lb_emit_arith(p, Token_Add, z, w, ft); + break; + } + } + + lb_emit_store(p, lb_emit_struct_ep(p, res.addr, 0), real); + lb_emit_store(p, lb_emit_struct_ep(p, res.addr, 1), imag); + + return lb_addr_load(p, res); + } else if (is_type_quaternion(type)) { + lhs = lb_emit_conv(p, lhs, type); + rhs = lb_emit_conv(p, rhs, type); + + Type *ft = base_complex_elem_type(type); + + if (op == Token_Add || op == Token_Sub) { + lbAddr res = lb_add_local_generated(p, type, false); // NOTE: initialized in full later + lbValue x0 = lb_emit_struct_ev(p, lhs, 0); + lbValue x1 = lb_emit_struct_ev(p, lhs, 1); + lbValue x2 = lb_emit_struct_ev(p, lhs, 2); + lbValue x3 = lb_emit_struct_ev(p, lhs, 3); + + lbValue y0 = lb_emit_struct_ev(p, rhs, 0); + lbValue y1 = lb_emit_struct_ev(p, rhs, 1); + lbValue y2 = lb_emit_struct_ev(p, rhs, 2); + lbValue y3 = lb_emit_struct_ev(p, rhs, 3); + + lbValue z0 = lb_emit_arith(p, op, x0, y0, ft); + lbValue z1 = lb_emit_arith(p, op, x1, y1, ft); + lbValue z2 = lb_emit_arith(p, op, x2, y2, ft); + lbValue z3 = lb_emit_arith(p, op, x3, y3, ft); + + lb_emit_store(p, lb_emit_struct_ep(p, res.addr, 0), z0); + lb_emit_store(p, lb_emit_struct_ep(p, res.addr, 1), z1); + lb_emit_store(p, lb_emit_struct_ep(p, res.addr, 2), z2); + lb_emit_store(p, lb_emit_struct_ep(p, res.addr, 3), z3); + + return lb_addr_load(p, res); + } else if (op == Token_Mul) { + auto args = array_make(heap_allocator(), 2); + args[0] = lhs; + args[1] = rhs; + + switch (8*type_size_of(ft)) { + case 32: return lb_emit_runtime_call(p, "mul_quaternion128", args); + case 64: return lb_emit_runtime_call(p, "mul_quaternion256", args); + default: GB_PANIC("Unknown float type"); break; + } + } else if (op == Token_Quo) { + auto args = array_make(heap_allocator(), 2); + args[0] = lhs; + args[1] = rhs; + + switch (8*type_size_of(ft)) { + case 32: return lb_emit_runtime_call(p, "quo_quaternion128", args); + case 64: return lb_emit_runtime_call(p, "quo_quaternion256", args); + default: GB_PANIC("Unknown float type"); break; + } + } + } + + if (is_type_integer(type) && is_type_different_to_arch_endianness(type)) { + switch (op) { + case Token_AndNot: + case Token_And: + case Token_Or: + case Token_Xor: + goto handle_op; + } + + Type *platform_type = integer_endian_type_to_platform_type(type); + lbValue x = lb_emit_byte_swap(p, lhs, integer_endian_type_to_platform_type(lhs.type)); + lbValue y = lb_emit_byte_swap(p, rhs, integer_endian_type_to_platform_type(rhs.type)); + + lbValue res = lb_emit_arith(p, op, x, y, platform_type); + + return lb_emit_byte_swap(p, res, type); + } + + + +handle_op: + lhs = lb_emit_conv(p, lhs, type); + rhs = lb_emit_conv(p, rhs, type); + + lbValue res = {}; + res.type = type; + + + switch (op) { + case Token_Add: + if (is_type_float(type)) { + res.value = LLVMBuildFAdd(p->builder, lhs.value, rhs.value, ""); + return res; + } + res.value = LLVMBuildAdd(p->builder, lhs.value, rhs.value, ""); + return res; + case Token_Sub: + if (is_type_float(type)) { + res.value = LLVMBuildFSub(p->builder, lhs.value, rhs.value, ""); + return res; + } + res.value = LLVMBuildSub(p->builder, lhs.value, rhs.value, ""); + return res; + case Token_Mul: + if (is_type_float(type)) { + res.value = LLVMBuildFMul(p->builder, lhs.value, rhs.value, ""); + return res; + } + res.value = LLVMBuildMul(p->builder, lhs.value, rhs.value, ""); + return res; + case Token_Quo: + if (is_type_float(type)) { + res.value = LLVMBuildFDiv(p->builder, lhs.value, rhs.value, ""); + return res; + } else if (is_type_unsigned(type)) { + res.value = LLVMBuildUDiv(p->builder, lhs.value, rhs.value, ""); + return res; + } + res.value = LLVMBuildSDiv(p->builder, lhs.value, rhs.value, ""); + return res; + case Token_Mod: + if (is_type_float(type)) { + res.value = LLVMBuildFRem(p->builder, lhs.value, rhs.value, ""); + return res; + } else if (is_type_unsigned(type)) { + res.value = LLVMBuildURem(p->builder, lhs.value, rhs.value, ""); + return res; + } + res.value = LLVMBuildSRem(p->builder, lhs.value, rhs.value, ""); + return res; + case Token_ModMod: + if (is_type_unsigned(type)) { + res.value = LLVMBuildURem(p->builder, lhs.value, rhs.value, ""); + return res; + } else { + LLVMValueRef a = LLVMBuildSRem(p->builder, lhs.value, rhs.value, ""); + LLVMValueRef b = LLVMBuildAdd(p->builder, a, rhs.value, ""); + LLVMValueRef c = LLVMBuildSRem(p->builder, b, rhs.value, ""); + res.value = c; + return res; + } + + case Token_And: + res.value = LLVMBuildAnd(p->builder, lhs.value, rhs.value, ""); + return res; + case Token_Or: + res.value = LLVMBuildOr(p->builder, lhs.value, rhs.value, ""); + return res; + case Token_Xor: + res.value = LLVMBuildXor(p->builder, lhs.value, rhs.value, ""); + return res; + case Token_Shl: + rhs = lb_emit_conv(p, rhs, lhs.type); + res.value = LLVMBuildShl(p->builder, lhs.value, rhs.value, ""); + return res; + case Token_Shr: + if (is_type_unsigned(type)) { + res.value = LLVMBuildLShr(p->builder, lhs.value, rhs.value, ""); + return res; + } + rhs = lb_emit_conv(p, rhs, lhs.type); + res.value = LLVMBuildAShr(p->builder, lhs.value, rhs.value, ""); + return res; + case Token_AndNot: + { + LLVMValueRef new_rhs = LLVMBuildNot(p->builder, rhs.value, ""); + res.value = LLVMBuildAnd(p->builder, lhs.value, new_rhs, ""); + return res; + } + break; + } + + GB_PANIC("unhandled operator of lb_emit_arith"); + + return {}; +} + +lbValue lb_build_binary_expr(lbProcedure *p, Ast *expr) { + ast_node(be, BinaryExpr, expr); + + TypeAndValue tv = type_and_value_of_expr(expr); + + switch (be->op.kind) { + case Token_Add: + case Token_Sub: + case Token_Mul: + case Token_Quo: + case Token_Mod: + case Token_ModMod: + case Token_And: + case Token_Or: + case Token_Xor: + case Token_AndNot: + case Token_Shl: + case Token_Shr: { + Type *type = default_type(tv.type); + lbValue left = lb_build_expr(p, be->left); + lbValue right = lb_build_expr(p, be->right); + return lb_emit_arith(p, be->op.kind, left, right, type); + } + + case Token_CmpEq: + case Token_NotEq: + case Token_Lt: + case Token_LtEq: + case Token_Gt: + case Token_GtEq: + { + lbValue left = lb_build_expr(p, be->left); + Type *type = default_type(tv.type); + lbValue right = lb_build_expr(p, be->right); + lbValue cmp = lb_emit_comp(p, be->op.kind, left, right); + return lb_emit_conv(p, cmp, type); + } + + case Token_CmpAnd: + case Token_CmpOr: + return lb_emit_logical_binary_expr(p, be->op.kind, be->left, be->right, tv.type); + + case Token_in: + case Token_not_in: + { + lbValue left = lb_build_expr(p, be->left); + Type *type = default_type(tv.type); + lbValue right = lb_build_expr(p, be->right); + Type *rt = base_type(right.type); + switch (rt->kind) { + case Type_Map: + { + lbValue addr = lb_address_from_load_or_generate_local(p, right); + lbValue h = lb_gen_map_header(p, addr, rt); + lbValue key = lb_gen_map_key(p, left, rt->Map.key); + + auto args = array_make(heap_allocator(), 2); + args[0] = h; + args[1] = key; + + lbValue ptr = lb_emit_runtime_call(p, "__dynamic_map_get", args); + if (be->op.kind == Token_in) { + return lb_emit_conv(p, lb_emit_comp_against_nil(p, Token_NotEq, ptr), t_bool); + } else { + return lb_emit_conv(p, lb_emit_comp_against_nil(p, Token_CmpEq, ptr), t_bool); + } + } + break; + case Type_BitSet: + { + Type *key_type = rt->BitSet.elem; + GB_ASSERT(are_types_identical(left.type, key_type)); + + Type *it = bit_set_to_int(rt); + left = lb_emit_conv(p, left, it); + + lbValue lower = lb_const_value(p->module, it, exact_value_i64(rt->BitSet.lower)); + lbValue key = lb_emit_arith(p, Token_Sub, left, lower, it); + lbValue bit = lb_emit_arith(p, Token_Shl, lb_const_int(p->module, it, 1), key, it); + bit = lb_emit_conv(p, bit, it); + + lbValue old_value = lb_emit_transmute(p, right, it); + lbValue new_value = lb_emit_arith(p, Token_And, old_value, bit, it); + + if (be->op.kind == Token_in) { + return lb_emit_conv(p, lb_emit_comp(p, Token_NotEq, new_value, lb_const_int(p->module, new_value.type, 0)), t_bool); + } else { + return lb_emit_conv(p, lb_emit_comp(p, Token_CmpEq, new_value, lb_const_int(p->module, new_value.type, 0)), t_bool); + } + } + break; + default: + GB_PANIC("Invalid 'in' type"); + } + break; + } + break; + default: + GB_PANIC("Invalid binary expression"); + break; + } + return {}; +} + + +String lookup_subtype_polymorphic_field(CheckerInfo *info, Type *dst, Type *src) { + Type *prev_src = src; + // Type *prev_dst = dst; + src = base_type(type_deref(src)); + // dst = base_type(type_deref(dst)); + bool src_is_ptr = src != prev_src; + // bool dst_is_ptr = dst != prev_dst; + + GB_ASSERT(is_type_struct(src) || is_type_union(src)); + for_array(i, src->Struct.fields) { + Entity *f = src->Struct.fields[i]; + if (f->kind == Entity_Variable && f->flags & EntityFlag_Using) { + if (are_types_identical(dst, f->type)) { + return f->token.string; + } + if (src_is_ptr && is_type_pointer(dst)) { + if (are_types_identical(type_deref(dst), f->type)) { + return f->token.string; + } + } + if (is_type_struct(f->type)) { + String name = lookup_subtype_polymorphic_field(info, dst, f->type); + if (name.len > 0) { + return name; + } + } + } + } + return str_lit(""); +} + +lbValue lb_const_ptr_cast(lbModule *m, lbValue value, Type *t) { + GB_ASSERT(is_type_pointer(value.type)); + GB_ASSERT(is_type_pointer(t)); + GB_ASSERT(lb_is_const(value)); + + lbValue res = {}; + res.value = LLVMConstPointerCast(value.value, lb_type(m, t)); + res.type = t; + return res; +} + +lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) { + lbModule *m = p->module; + t = reduce_tuple_to_single_type(t); + + Type *src_type = value.type; + if (are_types_identical(t, src_type)) { + return value; + } + + Type *src = core_type(src_type); + Type *dst = core_type(t); + + if (is_type_untyped_nil(src)) { + return lb_const_nil(m, t); + } + if (is_type_untyped_undef(src)) { + return lb_const_undef(m, t); + } + + if (LLVMIsConstant(value.value)) { + if (is_type_any(dst)) { + Type *st = default_type(src_type); + lbAddr default_value = lb_add_local_generated(p, st, false); + lb_addr_store(p, default_value, value); + lbValue data = lb_emit_conv(p, default_value.addr, t_rawptr); + lbValue id = lb_typeid(m, st); + + lbAddr res = lb_add_local_generated(p, t, false); + lbValue a0 = lb_emit_struct_ep(p, res.addr, 0); + lbValue a1 = lb_emit_struct_ep(p, res.addr, 1); + lb_emit_store(p, a0, data); + lb_emit_store(p, a1, id); + return lb_addr_load(p, res); + } else if (dst->kind == Type_Basic) { + if (src->Basic.kind == Basic_string && dst->Basic.kind == Basic_cstring) { + String str = lb_get_const_string(m, value); + lbValue res = {}; + res.type = t; + res.value = llvm_cstring(m, str); + return res; + } + // if (is_type_float(dst)) { + // return value; + // } else if (is_type_integer(dst)) { + // return value; + // } + // ExactValue ev = value->Constant.value; + // if (is_type_float(dst)) { + // ev = exact_value_to_float(ev); + // } else if (is_type_complex(dst)) { + // ev = exact_value_to_complex(ev); + // } else if (is_type_quaternion(dst)) { + // ev = exact_value_to_quaternion(ev); + // } else if (is_type_string(dst)) { + // // Handled elsewhere + // GB_ASSERT_MSG(ev.kind == ExactValue_String, "%d", ev.kind); + // } else if (is_type_integer(dst)) { + // ev = exact_value_to_integer(ev); + // } else if (is_type_pointer(dst)) { + // // IMPORTANT NOTE(bill): LLVM doesn't support pointer constants expect 'null' + // lbValue i = lb_add_module_constant(p->module, t_uintptr, ev); + // return lb_emit(p, lb_instr_conv(p, irConv_inttoptr, i, t_uintptr, dst)); + // } + // return lb_const_value(p->module, t, ev); + } + } + + if (are_types_identical(src, dst)) { + if (!are_types_identical(src_type, t)) { + return lb_emit_transmute(p, value, t); + } + return value; + } + + + + // bool <-> llvm bool + if (is_type_boolean(src) && dst == t_llvm_bool) { + lbValue res = {}; + res.value = LLVMBuildTrunc(p->builder, value.value, lb_type(m, dst), ""); + res.type = dst; + return res; + } + if (src == t_llvm_bool && is_type_boolean(dst)) { + lbValue res = {}; + res.value = LLVMBuildZExt(p->builder, value.value, lb_type(m, dst), ""); + res.type = dst; + return res; + } + + + // integer -> integer + if (is_type_integer(src) && is_type_integer(dst)) { + GB_ASSERT(src->kind == Type_Basic && + dst->kind == Type_Basic); + i64 sz = type_size_of(default_type(src)); + i64 dz = type_size_of(default_type(dst)); + + if (sz > 1 && is_type_different_to_arch_endianness(src)) { + Type *platform_src_type = integer_endian_type_to_platform_type(src); + value = lb_emit_byte_swap(p, value, platform_src_type); + } + LLVMOpcode op = LLVMTrunc; + + if (dz < sz) { + op = LLVMTrunc; + } else if (dz == sz) { + // NOTE(bill): In LLVM, all integers are signed and rely upon 2's compliment + // NOTE(bill): Copy the value just for type correctness + op = LLVMBitCast; + } else if (dz > sz) { + op = is_type_unsigned(src) ? LLVMZExt : LLVMSExt; // zero extent + } + + if (dz > 1 && is_type_different_to_arch_endianness(dst)) { + Type *platform_dst_type = integer_endian_type_to_platform_type(dst); + lbValue res = {}; + res.value = LLVMBuildCast(p->builder, op, value.value, lb_type(m, platform_dst_type), ""); + res.type = t; + return lb_emit_byte_swap(p, res, t); + } else { + lbValue res = {}; + res.value = LLVMBuildCast(p->builder, op, value.value, lb_type(m, t), ""); + res.type = t; + return res; + } + } + + + // boolean -> boolean/integer + if (is_type_boolean(src) && (is_type_boolean(dst) || is_type_integer(dst))) { + LLVMValueRef b = LLVMBuildICmp(p->builder, LLVMIntNE, value.value, LLVMConstNull(lb_type(m, value.type)), ""); + lbValue res = {}; + res.value = LLVMBuildIntCast2(p->builder, value.value, lb_type(m, t), false, ""); + res.type = t; + return res; + } + + if (is_type_cstring(src) && is_type_u8_ptr(dst)) { + return lb_emit_transmute(p, value, dst); + } + if (is_type_u8_ptr(src) && is_type_cstring(dst)) { + return lb_emit_transmute(p, value, dst); + } + if (is_type_cstring(src) && is_type_rawptr(dst)) { + return lb_emit_transmute(p, value, dst); + } + if (is_type_rawptr(src) && is_type_cstring(dst)) { + return lb_emit_transmute(p, value, dst); + } + + if (are_types_identical(src, t_cstring) && are_types_identical(dst, t_string)) { + lbValue c = lb_emit_conv(p, value, t_cstring); + auto args = array_make(heap_allocator(), 1); + args[0] = c; + lbValue s = lb_emit_runtime_call(p, "cstring_to_string", args); + return lb_emit_conv(p, s, dst); + } + + + // integer -> boolean + if (is_type_integer(src) && is_type_boolean(dst)) { + lbValue res = {}; + res.value = LLVMBuildICmp(p->builder, LLVMIntNE, value.value, LLVMConstNull(lb_type(m, value.type)), ""); + res.type = t_llvm_bool; + return lb_emit_conv(p, res, t); + } + + // float -> float + if (is_type_float(src) && is_type_float(dst)) { + gbAllocator a = heap_allocator(); + i64 sz = type_size_of(src); + i64 dz = type_size_of(dst); + + lbValue res = {}; + res.type = t; + + if (dz >= sz) { + res.value = LLVMBuildFPExt(p->builder, value.value, lb_type(m, t), ""); + } else { + res.value = LLVMBuildFPTrunc(p->builder, value.value, lb_type(m, t), ""); + } + return res; + } + + if (is_type_complex(src) && is_type_complex(dst)) { + Type *ft = base_complex_elem_type(dst); + lbAddr gen = lb_add_local_generated(p, dst, false); + lbValue gp = lb_addr_get_ptr(p, gen); + lbValue real = lb_emit_conv(p, lb_emit_struct_ev(p, value, 0), ft); + lbValue imag = lb_emit_conv(p, lb_emit_struct_ev(p, value, 1), ft); + lb_emit_store(p, lb_emit_struct_ep(p, gp, 0), real); + lb_emit_store(p, lb_emit_struct_ep(p, gp, 1), imag); + return lb_addr_load(p, gen); + } + + if (is_type_quaternion(src) && is_type_quaternion(dst)) { + // @QuaternionLayout + Type *ft = base_complex_elem_type(dst); + lbAddr gen = lb_add_local_generated(p, dst, false); + lbValue gp = lb_addr_get_ptr(p, gen); + lbValue q0 = lb_emit_conv(p, lb_emit_struct_ev(p, value, 0), ft); + lbValue q1 = lb_emit_conv(p, lb_emit_struct_ev(p, value, 1), ft); + lbValue q2 = lb_emit_conv(p, lb_emit_struct_ev(p, value, 2), ft); + lbValue q3 = lb_emit_conv(p, lb_emit_struct_ev(p, value, 3), ft); + lb_emit_store(p, lb_emit_struct_ep(p, gp, 0), q0); + lb_emit_store(p, lb_emit_struct_ep(p, gp, 1), q1); + lb_emit_store(p, lb_emit_struct_ep(p, gp, 2), q2); + lb_emit_store(p, lb_emit_struct_ep(p, gp, 3), q3); + return lb_addr_load(p, gen); + } + + if (is_type_float(src) && is_type_complex(dst)) { + Type *ft = base_complex_elem_type(dst); + lbAddr gen = lb_add_local_generated(p, dst, true); + lbValue gp = lb_addr_get_ptr(p, gen); + lbValue real = lb_emit_conv(p, value, ft); + lb_emit_store(p, lb_emit_struct_ep(p, gp, 0), real); + return lb_addr_load(p, gen); + } + if (is_type_float(src) && is_type_quaternion(dst)) { + Type *ft = base_complex_elem_type(dst); + lbAddr gen = lb_add_local_generated(p, dst, true); + lbValue gp = lb_addr_get_ptr(p, gen); + lbValue real = lb_emit_conv(p, value, ft); + // @QuaternionLayout + lb_emit_store(p, lb_emit_struct_ep(p, gp, 3), real); + return lb_addr_load(p, gen); + } + if (is_type_complex(src) && is_type_quaternion(dst)) { + Type *ft = base_complex_elem_type(dst); + lbAddr gen = lb_add_local_generated(p, dst, true); + lbValue gp = lb_addr_get_ptr(p, gen); + lbValue real = lb_emit_conv(p, lb_emit_struct_ev(p, value, 0), ft); + lbValue imag = lb_emit_conv(p, lb_emit_struct_ev(p, value, 1), ft); + // @QuaternionLayout + lb_emit_store(p, lb_emit_struct_ep(p, gp, 3), real); + lb_emit_store(p, lb_emit_struct_ep(p, gp, 0), imag); + return lb_addr_load(p, gen); + } + + // float <-> integer + if (is_type_float(src) && is_type_integer(dst)) { + lbValue res = {}; + res.type = t; + if (is_type_unsigned(dst)) { + res.value = LLVMBuildFPToUI(p->builder, value.value, lb_type(m, t), ""); + } else { + res.value = LLVMBuildFPToSI(p->builder, value.value, lb_type(m, t), ""); + } + return res; + } + if (is_type_integer(src) && is_type_float(dst)) { + lbValue res = {}; + res.type = t; + if (is_type_unsigned(src)) { + res.value = LLVMBuildUIToFP(p->builder, value.value, lb_type(m, t), ""); + } else { + res.value = LLVMBuildSIToFP(p->builder, value.value, lb_type(m, t), ""); + } + return res; + } + + // Pointer <-> uintptr + if (is_type_pointer(src) && is_type_uintptr(dst)) { + lbValue res = {}; + res.type = t; + res.value = LLVMBuildPtrToInt(p->builder, value.value, lb_type(m, t), ""); + return res; + } + if (is_type_uintptr(src) && is_type_pointer(dst)) { + lbValue res = {}; + res.type = t; + res.value = LLVMBuildIntToPtr(p->builder, value.value, lb_type(m, t), ""); + return res; + } + +#if 1 + if (is_type_union(dst)) { + for_array(i, dst->Union.variants) { + Type *vt = dst->Union.variants[i]; + if (are_types_identical(vt, src_type)) { + lbAddr parent = lb_add_local_generated(p, t, true); + lb_emit_store_union_variant(p, parent.addr, value, vt); + return lb_addr_load(p, parent); + } + } + } +#endif + + // NOTE(bill): This has to be done before 'Pointer <-> Pointer' as it's + // subtype polymorphism casting + if (check_is_assignable_to_using_subtype(src_type, t)) { + Type *st = type_deref(src_type); + Type *pst = st; + st = type_deref(st); + + bool st_is_ptr = is_type_pointer(src_type); + st = base_type(st); + + Type *dt = t; + bool dt_is_ptr = type_deref(dt) != dt; + + GB_ASSERT(is_type_struct(st) || is_type_raw_union(st)); + String field_name = lookup_subtype_polymorphic_field(p->module->info, t, src_type); + if (field_name.len > 0) { + // NOTE(bill): It can be casted + Selection sel = lookup_field(st, field_name, false, true); + if (sel.entity != nullptr) { + if (st_is_ptr) { + lbValue res = lb_emit_deep_field_gep(p, value, sel); + Type *rt = res.type; + if (!are_types_identical(rt, dt) && are_types_identical(type_deref(rt), dt)) { + res = lb_emit_load(p, res); + } + return res; + } else { + if (is_type_pointer(value.type)) { + Type *rt = value.type; + if (!are_types_identical(rt, dt) && are_types_identical(type_deref(rt), dt)) { + value = lb_emit_load(p, value); + } else { + value = lb_emit_deep_field_gep(p, value, sel); + return lb_emit_load(p, value); + } + } + + return lb_emit_deep_field_ev(p, value, sel); + + } + } else { + GB_PANIC("invalid subtype cast %s.%.*s", type_to_string(src_type), LIT(field_name)); + } + } + } + + + + // Pointer <-> Pointer + if (is_type_pointer(src) && is_type_pointer(dst)) { + lbValue res = {}; + res.type = t; + res.value = LLVMBuildPointerCast(p->builder, value.value, lb_type(m, t), ""); + return res; + } + + + + // proc <-> proc + if (is_type_proc(src) && is_type_proc(dst)) { + lbValue res = {}; + res.type = t; + res.value = LLVMBuildPointerCast(p->builder, value.value, lb_type(m, t), ""); + return res; + } + + // pointer -> proc + if (is_type_pointer(src) && is_type_proc(dst)) { + lbValue res = {}; + res.type = t; + res.value = LLVMBuildPointerCast(p->builder, value.value, lb_type(m, t), ""); + return res; + } + // proc -> pointer + if (is_type_proc(src) && is_type_pointer(dst)) { + lbValue res = {}; + res.type = t; + res.value = LLVMBuildPointerCast(p->builder, value.value, lb_type(m, t), ""); + return res; + } + + + + // []byte/[]u8 <-> string + if (is_type_u8_slice(src) && is_type_string(dst)) { + return lb_emit_transmute(p, value, t); + } + if (is_type_string(src) && is_type_u8_slice(dst)) { + return lb_emit_transmute(p, value, t); + } + + if (is_type_array(dst)) { + Type *elem = dst->Array.elem; + lbValue e = lb_emit_conv(p, value, elem); + // NOTE(bill): Doesn't need to be zero because it will be initialized in the loops + lbAddr v = lb_add_local_generated(p, t, false); + isize index_count = cast(isize)dst->Array.count; + + for (isize i = 0; i < index_count; i++) { + lbValue elem = lb_emit_array_epi(p, v.addr, i); + lb_emit_store(p, elem, e); + } + return lb_addr_load(p, v); + } + + if (is_type_any(dst)) { + if (is_type_untyped_nil(src)) { + return lb_const_nil(p->module, t); + } + if (is_type_untyped_undef(src)) { + return lb_const_undef(p->module, t); + } + + lbAddr result = lb_add_local_generated(p, t, true); + + Type *st = default_type(src_type); + + lbValue data = lb_address_from_load_or_generate_local(p, value); + GB_ASSERT_MSG(is_type_pointer(data.type), "%s", type_to_string(data.type)); + GB_ASSERT_MSG(is_type_typed(st), "%s", type_to_string(st)); + data = lb_emit_conv(p, data, t_rawptr); + + lbValue id = lb_typeid(p->module, st); + lbValue any_data = lb_emit_struct_ep(p, result.addr, 0); + lbValue any_id = lb_emit_struct_ep(p, result.addr, 1); + + lb_emit_store(p, any_data, data); + lb_emit_store(p, any_id, id); + + return lb_addr_load(p, result); + } + + if (is_type_untyped(src)) { + if (is_type_string(src) && is_type_string(dst)) { + lbAddr result = lb_add_local_generated(p, t, false); + lb_addr_store(p, result, value); + return lb_addr_load(p, result); + } + } + + gb_printf_err("%.*s\n", LIT(p->name)); + gb_printf_err("lb_emit_conv: src -> dst\n"); + gb_printf_err("Not Identical %s != %s\n", type_to_string(src_type), type_to_string(t)); + gb_printf_err("Not Identical %s != %s\n", type_to_string(src), type_to_string(dst)); + gb_printf_err("Not Identical %p != %p\n", src_type, t); + gb_printf_err("Not Identical %p != %p\n", src, dst); + + + GB_PANIC("Invalid type conversion: '%s' to '%s' for procedure '%.*s'", + type_to_string(src_type), type_to_string(t), + LIT(p->name)); + + return {}; +} + +bool lb_is_type_aggregate(Type *t) { + t = base_type(t); + switch (t->kind) { + case Type_Basic: + switch (t->Basic.kind) { + case Basic_string: + case Basic_any: + return true; + + // case Basic_complex32: + case Basic_complex64: + case Basic_complex128: + case Basic_quaternion128: + case Basic_quaternion256: + return true; + } + break; + + case Type_Pointer: + return false; + + case Type_Array: + case Type_Slice: + case Type_Struct: + case Type_Union: + case Type_Tuple: + case Type_DynamicArray: + case Type_Map: + case Type_BitField: + case Type_SimdVector: + return true; + + case Type_Named: + return lb_is_type_aggregate(t->Named.base); + } + + return false; +} + +lbValue lb_emit_transmute(lbProcedure *p, lbValue value, Type *t) { + Type *src_type = value.type; + if (are_types_identical(t, src_type)) { + return value; + } + + lbValue res = {}; + res.type = t; + + + Type *src = base_type(src_type); + Type *dst = base_type(t); + + lbModule *m = p->module; + + i64 sz = type_size_of(src); + i64 dz = type_size_of(dst); + + GB_ASSERT_MSG(sz == dz, "Invalid transmute conversion: '%s' to '%s'", type_to_string(src_type), type_to_string(t)); + + // NOTE(bill): Casting between an integer and a pointer cannot be done through a bitcast + if (is_type_uintptr(src) && is_type_pointer(dst)) { + res.value = LLVMBuildIntToPtr(p->builder, value.value, lb_type(m, t), ""); + return res; + } + if (is_type_pointer(src) && is_type_uintptr(dst)) { + res.value = LLVMBuildPtrToInt(p->builder, value.value, lb_type(m, t), ""); + return res; + } + if (is_type_uintptr(src) && is_type_proc(dst)) { + res.value = LLVMBuildIntToPtr(p->builder, value.value, lb_type(m, t), ""); + return res; + } + if (is_type_proc(src) && is_type_uintptr(dst)) { + res.value = LLVMBuildPtrToInt(p->builder, value.value, lb_type(m, t), ""); + return res; + } + + if (is_type_integer(src) && (is_type_pointer(dst) || is_type_cstring(dst))) { + res.value = LLVMBuildIntToPtr(p->builder, value.value, lb_type(m, t), ""); + return res; + } else if ((is_type_pointer(src) || is_type_cstring(src)) && is_type_integer(dst)) { + res.value = LLVMBuildPtrToInt(p->builder, value.value, lb_type(m, t), ""); + return res; + } + + if (is_type_pointer(src) && is_type_pointer(dst)) { + res.value = LLVMBuildPointerCast(p->builder, value.value, lb_type(p->module, t), ""); + return res; + } + + if (lb_is_type_aggregate(src) || lb_is_type_aggregate(dst)) { + lbValue s = lb_address_from_load_or_generate_local(p, value); + lbValue d = lb_emit_transmute(p, s, alloc_type_pointer(t)); + return lb_emit_load(p, d); + } + + + res.value = LLVMBuildBitCast(p->builder, value.value, lb_type(p->module, t), ""); + // GB_PANIC("lb_emit_transmute"); + return res; +} + + +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] = 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); +} + + +lbAddr lb_find_or_generate_context_ptr(lbProcedure *p) { + if (p->context_stack.count > 0) { + return p->context_stack[p->context_stack.count-1].ctx; + } + + Type *pt = base_type(p->type); + GB_ASSERT(pt->kind == Type_Proc); + if (pt->Proc.calling_convention != ProcCC_Odin) { + return p->module->global_default_context; + } else { + lbAddr c = lb_add_local_generated(p, t_context, false); + 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); + return c; + } +} + +lbValue lb_address_from_load_or_generate_local(lbProcedure *p, lbValue value) { + if (LLVMIsALoadInst(value.value)) { + lbValue res = {}; + res.value = LLVMGetOperand(value.value, 0); + res.type = alloc_type_pointer(value.type); + return res; + } + + GB_ASSERT(is_type_typed(value.type)); + + lbAddr res = lb_add_local_generated(p, value.type, false); + lb_addr_store(p, res, value); + return res.addr; +} + +lbValue lb_copy_value_to_ptr(lbProcedure *p, lbValue val, Type *new_type, i64 alignment) { + i64 type_alignment = type_align_of(new_type); + if (alignment < type_alignment) { + alignment = type_alignment; + } + GB_ASSERT_MSG(are_types_identical(new_type, val.type), "%s %s", type_to_string(new_type), type_to_string(val.type)); + + lbAddr ptr = lb_add_local_generated(p, new_type, false); + LLVMSetAlignment(ptr.addr.value, cast(unsigned)alignment); + lb_addr_store(p, ptr, val); + ptr.kind = lbAddr_Context; + return ptr.addr; +} + +lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index) { + gbAllocator a = heap_allocator(); + GB_ASSERT(is_type_pointer(s.type)); + Type *t = base_type(type_deref(s.type)); + Type *result_type = nullptr; + + if (t->kind == Type_Opaque) { + t = t->Opaque.elem; + } + + if (is_type_struct(t)) { + result_type = get_struct_field_type(t, index); + } else if (is_type_union(t)) { + GB_ASSERT(index == -1); + return lb_emit_union_tag_ptr(p, s); + } else if (is_type_tuple(t)) { + GB_ASSERT(t->Tuple.variables.count > 0); + result_type = t->Tuple.variables[index]->type; + } else if (is_type_complex(t)) { + Type *ft = base_complex_elem_type(t); + switch (index) { + case 0: result_type = ft; break; + case 1: result_type = ft; break; + } + } else if (is_type_quaternion(t)) { + Type *ft = base_complex_elem_type(t); + switch (index) { + case 0: result_type = ft; break; + case 1: result_type = ft; break; + case 2: result_type = ft; break; + case 3: result_type = ft; break; + } + } else if (is_type_slice(t)) { + switch (index) { + case 0: result_type = alloc_type_pointer(t->Slice.elem); break; + case 1: result_type = t_int; break; + } + } else if (is_type_string(t)) { + switch (index) { + case 0: result_type = t_u8_ptr; break; + case 1: result_type = t_int; break; + } + } else if (is_type_any(t)) { + switch (index) { + case 0: result_type = t_rawptr; break; + case 1: result_type = t_typeid; break; + } + } else if (is_type_dynamic_array(t)) { + switch (index) { + case 0: result_type = alloc_type_pointer(t->DynamicArray.elem); break; + case 1: result_type = t_int; break; + case 2: result_type = t_int; break; + case 3: result_type = t_allocator; break; + } + } else if (is_type_map(t)) { + init_map_internal_types(t); + Type *itp = alloc_type_pointer(t->Map.internal_type); + s = lb_emit_transmute(p, s, itp); + + Type *gst = t->Map.internal_type; + GB_ASSERT(gst->kind == Type_Struct); + switch (index) { + case 0: result_type = get_struct_field_type(gst, 0); break; + case 1: result_type = get_struct_field_type(gst, 1); break; + } + } else if (is_type_array(t)) { + return lb_emit_array_epi(p, s, index); + } else { + GB_PANIC("TODO(bill): struct_gep type: %s, %d", type_to_string(s.type), index); + } + + GB_ASSERT_MSG(result_type != nullptr, "%s %d", type_to_string(t), index); + + if (lb_is_const(s)) { + lbModule *m = p->module; + lbValue res = {}; + LLVMValueRef indices[2] = {llvm_zero32(m), LLVMConstInt(lb_type(m, t_i32), index, false)}; + res.value = LLVMConstGEP(s.value, indices, gb_count_of(indices)); + res.type = alloc_type_pointer(result_type); + return res; + } else { + lbValue res = {}; + res.value = LLVMBuildStructGEP(p->builder, s.value, cast(unsigned)index, ""); + res.type = alloc_type_pointer(result_type); + return res; + } +} + +lbValue lb_emit_struct_ev(lbProcedure *p, lbValue s, i32 index) { + if (LLVMIsALoadInst(s.value)) { + lbValue res = {}; + res.value = LLVMGetOperand(s.value, 0); + res.type = alloc_type_pointer(s.type); + lbValue ptr = lb_emit_struct_ep(p, res, index); + return lb_emit_load(p, ptr); + } + + gbAllocator a = heap_allocator(); + Type *t = base_type(s.type); + Type *result_type = nullptr; + + switch (t->kind) { + case Type_Basic: + switch (t->Basic.kind) { + case Basic_string: + switch (index) { + case 0: result_type = t_u8_ptr; break; + case 1: result_type = t_int; break; + } + break; + case Basic_any: + switch (index) { + case 0: result_type = t_rawptr; break; + case 1: result_type = t_typeid; break; + } + break; + case Basic_complex64: case Basic_complex128: + { + Type *ft = base_complex_elem_type(t); + switch (index) { + case 0: result_type = ft; break; + case 1: result_type = ft; break; + } + break; + } + case Basic_quaternion128: case Basic_quaternion256: + { + Type *ft = base_complex_elem_type(t); + switch (index) { + case 0: result_type = ft; break; + case 1: result_type = ft; break; + case 2: result_type = ft; break; + case 3: result_type = ft; break; + } + break; + } + } + break; + case Type_Struct: + result_type = get_struct_field_type(t, index); + break; + case Type_Union: + GB_ASSERT(index == -1); + // return lb_emit_union_tag_value(p, s); + GB_PANIC("lb_emit_union_tag_value"); + + case Type_Tuple: + GB_ASSERT(t->Tuple.variables.count > 0); + result_type = t->Tuple.variables[index]->type; + if (t->Tuple.variables.count == 1) { + return s; + } + break; + case Type_Slice: + switch (index) { + case 0: result_type = alloc_type_pointer(t->Slice.elem); break; + case 1: result_type = t_int; break; + } + break; + case Type_DynamicArray: + switch (index) { + case 0: result_type = alloc_type_pointer(t->DynamicArray.elem); break; + case 1: result_type = t_int; break; + case 2: result_type = t_int; break; + case 3: result_type = t_allocator; break; + } + break; + + case Type_Map: + { + init_map_internal_types(t); + Type *gst = t->Map.generated_struct_type; + switch (index) { + case 0: result_type = get_struct_field_type(gst, 0); break; + case 1: result_type = get_struct_field_type(gst, 1); break; + } + } + break; + + case Type_Array: + result_type = t->Array.elem; + break; + + default: + GB_PANIC("TODO(bill): struct_ev type: %s, %d", type_to_string(s.type), index); + break; + } + + GB_ASSERT_MSG(result_type != nullptr, "%s, %d", type_to_string(s.type), index); + + + lbValue res = {}; + res.value = LLVMBuildExtractValue(p->builder, s.value, cast(unsigned)index, ""); + res.type = result_type; + return res; +} + +lbValue lb_emit_deep_field_gep(lbProcedure *p, lbValue e, Selection sel) { + GB_ASSERT(sel.index.count > 0); + Type *type = type_deref(e.type); + gbAllocator a = heap_allocator(); + + for_array(i, sel.index) { + i32 index = cast(i32)sel.index[i]; + if (is_type_pointer(type)) { + type = type_deref(type); + e = lb_emit_load(p, e); + } + type = core_type(type); + if (type->kind == Type_Opaque) { + type = type->Opaque.elem; + } + + if (is_type_quaternion(type)) { + e = lb_emit_struct_ep(p, e, index); + } else if (is_type_raw_union(type)) { + type = get_struct_field_type(type, index); + GB_ASSERT(is_type_pointer(e.type)); + e = lb_emit_transmute(p, e, alloc_type_pointer(type)); + } else if (is_type_struct(type)) { + type = get_struct_field_type(type, index); + e = lb_emit_struct_ep(p, e, index); + } else if (type->kind == Type_Union) { + GB_ASSERT(index == -1); + type = t_type_info_ptr; + e = lb_emit_struct_ep(p, e, index); + } else if (type->kind == Type_Tuple) { + type = type->Tuple.variables[index]->type; + e = lb_emit_struct_ep(p, e, index); + } else if (type->kind == Type_Basic) { + switch (type->Basic.kind) { + case Basic_any: { + if (index == 0) { + type = t_rawptr; + } else if (index == 1) { + type = t_type_info_ptr; + } + e = lb_emit_struct_ep(p, e, index); + break; + } + + case Basic_string: + e = lb_emit_struct_ep(p, e, index); + break; + + default: + GB_PANIC("un-gep-able type"); + break; + } + } else if (type->kind == Type_Slice) { + e = lb_emit_struct_ep(p, e, index); + } else if (type->kind == Type_DynamicArray) { + e = lb_emit_struct_ep(p, e, index); + } else if (type->kind == Type_Array) { + e = lb_emit_array_epi(p, e, index); + } else if (type->kind == Type_Map) { + e = lb_emit_struct_ep(p, e, index); + } else { + GB_PANIC("un-gep-able type %s", type_to_string(type)); + } + } + + return e; +} + + +lbValue lb_emit_deep_field_ev(lbProcedure *p, lbValue e, Selection sel) { + lbValue ptr = lb_address_from_load_or_generate_local(p, e); + lbValue res = lb_emit_deep_field_gep(p, ptr, sel); + return lb_emit_load(p, res); +} + + + +void lb_build_defer_stmt(lbProcedure *p, lbDefer d) { + // NOTE(bill): The prev block may defer injection before it's terminator + LLVMValueRef last_instr = LLVMGetLastInstruction(p->curr_block->block); + if (last_instr != nullptr && LLVMIsAReturnInst(last_instr)) { + // NOTE(bill): ReturnStmt defer stuff will be handled previously + return; + } + + lbBlock *b = lb_create_block(p, "defer"); + if (last_instr == nullptr || !LLVMIsATerminatorInst(last_instr)) { + lb_emit_jump(p, b); + } + + if (last_instr == nullptr || !LLVMIsATerminatorInst(last_instr)) { + lb_emit_jump(p, b); + } + lb_start_block(p, b); + if (d.kind == lbDefer_Node) { + lb_build_stmt(p, d.stmt); + } else if (d.kind == lbDefer_Instr) { + // NOTE(bill): Need to make a new copy + LLVMValueRef instr = LLVMInstructionClone(d.instr.value); + LLVMInsertIntoBuilder(p->builder, instr); + } else if (d.kind == lbDefer_Proc) { + lb_emit_call(p, d.proc.deferred, d.proc.result_as_args); + } +} + +void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlock *block) { + isize count = p->defer_stmts.count; + isize i = count; + while (i --> 0) { + lbDefer d = p->defer_stmts[i]; + + if (kind == lbDeferExit_Default) { + if (p->scope_index == d.scope_index && + d.scope_index > 0) { // TODO(bill): Which is correct: > 0 or > 1? + lb_build_defer_stmt(p, d); + array_pop(&p->defer_stmts); + continue; + } else { + break; + } + } else if (kind == lbDeferExit_Return) { + lb_build_defer_stmt(p, d); + } else if (kind == lbDeferExit_Branch) { + GB_ASSERT(block != nullptr); + isize lower_limit = block->scope_index; + if (lower_limit < d.scope_index) { + lb_build_defer_stmt(p, d); + } + } + } +} + +lbDefer lb_add_defer_node(lbProcedure *p, isize scope_index, Ast *stmt) { + lbDefer d = {lbDefer_Node}; + d.scope_index = scope_index; + d.context_stack_count = p->context_stack.count; + d.block = p->curr_block; + d.stmt = stmt; + array_add(&p->defer_stmts, d); + return d; +} + +lbDefer lb_add_defer_proc(lbProcedure *p, isize scope_index, lbValue deferred, Array const &result_as_args) { + lbDefer d = {lbDefer_Proc}; + d.scope_index = p->scope_index; + d.block = p->curr_block; + d.proc.deferred = deferred; + d.proc.result_as_args = result_as_args; + array_add(&p->defer_stmts, d); + return d; +} + + + +Array lb_value_to_array(lbProcedure *p, lbValue value) { + Array array = {}; + Type *t = base_type(value.type); + if (t == nullptr) { + // Do nothing + } else if (is_type_tuple(t)) { + GB_ASSERT(t->kind == Type_Tuple); + auto *rt = &t->Tuple; + if (rt->variables.count > 0) { + array = array_make(heap_allocator(), rt->variables.count); + for_array(i, rt->variables) { + lbValue elem = lb_emit_struct_ev(p, value, cast(i32)i); + array[i] = elem; + } + } + } else { + array = array_make(heap_allocator(), 1); + array[0] = value; + } + return array; +} + + + +lbValue lb_emit_call_internal(lbProcedure *p, lbValue value, lbValue return_ptr, Array const &processed_args, Type *abi_rt, lbAddr context_ptr, ProcInlining inlining) { + unsigned arg_count = cast(unsigned)processed_args.count; + if (return_ptr.value != nullptr) { + arg_count += 1; + } + if (context_ptr.addr.value != nullptr) { + arg_count += 1; + } + + LLVMValueRef *args = gb_alloc_array(heap_allocator(), LLVMValueRef, arg_count); + isize arg_index = 0; + if (return_ptr.value != nullptr) { + args[arg_index++] = return_ptr.value; + } + for_array(i, processed_args) { + lbValue arg = processed_args[i]; + args[arg_index++] = arg.value; + } + if (context_ptr.addr.value != nullptr) { + args[arg_index++] = context_ptr.addr.value; + } + + LLVMBasicBlockRef curr_block = LLVMGetInsertBlock(p->builder); + GB_ASSERT(curr_block != p->decl_block->block); + + 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; + return res; +} + +lbValue lb_emit_runtime_call(lbProcedure *p, char const *c_name, Array const &args) { + String name = make_string_c(c_name); + + + AstPackage *pkg = p->module->info->runtime_package; + Entity *e = scope_lookup_current(pkg->scope, name); + + lbValue *found = nullptr; + if (p->module != e->code_gen_module) { + gb_mutex_lock(&p->module->mutex); + } + found = map_get(&e->code_gen_module->values, hash_entity(e)); + if (p->module != e->code_gen_module) { + gb_mutex_unlock(&p->module->mutex); + } + + GB_ASSERT_MSG(found != nullptr, "%s", c_name); + return lb_emit_call(p, *found, args); +} + +lbValue lb_emit_call(lbProcedure *p, lbValue value, Array const &args, ProcInlining inlining, bool use_return_ptr_hint) { + lbModule *m = p->module; + + Type *pt = base_type(value.type); + GB_ASSERT(pt->kind == Type_Proc); + Type *results = pt->Proc.results; + + if (p->entity != nullptr) { + if (p->entity->flags & EntityFlag_Disabled) { + return {}; + } + } + + lbAddr context_ptr = {}; + if (pt->Proc.calling_convention == ProcCC_Odin) { + context_ptr = lb_find_or_generate_context_ptr(p); + } + + set_procedure_abi_types(heap_allocator(), pt); + + bool is_c_vararg = pt->Proc.c_vararg; + isize param_count = pt->Proc.param_count; + if (is_c_vararg) { + GB_ASSERT(param_count-1 <= args.count); + param_count -= 1; + } else { + GB_ASSERT_MSG(param_count == args.count, "%td == %td", param_count, args.count); + } + + auto processed_args = array_make(heap_allocator(), 0, args.count); + + for (isize i = 0; i < param_count; i++) { + Entity *e = pt->Proc.params->Tuple.variables[i]; + if (e->kind != Entity_Variable) { + // array_add(&processed_args, args[i]); + continue; + } + GB_ASSERT(e->flags & EntityFlag_Param); + + Type *original_type = e->type; + Type *new_type = pt->Proc.abi_compat_params[i]; + Type *arg_type = args[i].type; + + if (are_types_identical(arg_type, new_type)) { + // NOTE(bill): Done + array_add(&processed_args, args[i]); + } else if (!are_types_identical(original_type, new_type)) { + if (is_type_pointer(new_type) && !is_type_pointer(original_type)) { + if (e->flags&EntityFlag_ImplicitReference) { + array_add(&processed_args, lb_address_from_load_or_generate_local(p, args[i])); + } else if (!is_type_pointer(arg_type)) { + array_add(&processed_args, lb_copy_value_to_ptr(p, args[i], original_type, 16)); + } + } else if (is_type_integer(new_type) || is_type_float(new_type)) { + array_add(&processed_args, lb_emit_transmute(p, args[i], new_type)); + } else if (new_type == t_llvm_bool) { + array_add(&processed_args, lb_emit_conv(p, args[i], new_type)); + } else if (is_type_simd_vector(new_type)) { + array_add(&processed_args, lb_emit_transmute(p, args[i], new_type)); + } else if (is_type_tuple(new_type)) { + Type *abi_type = pt->Proc.abi_compat_params[i]; + Type *st = struct_type_from_systemv_distribute_struct_fields(abi_type); + lbValue x = lb_emit_transmute(p, args[i], st); + for (isize j = 0; j < new_type->Tuple.variables.count; j++) { + lbValue xx = lb_emit_struct_ev(p, x, cast(i32)j); + array_add(&processed_args, xx); + } + } + } else { + lbValue x = lb_emit_conv(p, args[i], new_type); + array_add(&processed_args, x); + } + } + + if (inlining == ProcInlining_none) { + inlining = p->inlining; + } + + lbValue result = {}; + + Type *abi_rt = reduce_tuple_to_single_type(pt->Proc.abi_compat_result_type); + Type *rt = reduce_tuple_to_single_type(results); + if (pt->Proc.return_by_pointer) { + lbValue return_ptr = {}; + if (use_return_ptr_hint && p->return_ptr_hint_value.value != nullptr) { + if (are_types_identical(type_deref(p->return_ptr_hint_value.type), rt)) { + return_ptr = p->return_ptr_hint_value; + p->return_ptr_hint_used = true; + } + } + if (return_ptr.value == nullptr) { + lbAddr r = lb_add_local_generated(p, rt, true); + return_ptr = r.addr; + } + GB_ASSERT(is_type_pointer(return_ptr.type)); + lb_emit_call_internal(p, value, return_ptr, processed_args, nullptr, context_ptr, inlining); + result = lb_emit_load(p, return_ptr); + } else { + result = lb_emit_call_internal(p, value, {}, processed_args, abi_rt, context_ptr, inlining); + if (abi_rt != rt) { + result = lb_emit_transmute(p, result, rt); + } + } + + Entity **found = map_get(&p->module->procedure_values, hash_pointer(value.value)); + if (found != nullptr) { + Entity *e = *found; + if (e != nullptr && entity_has_deferred_procedure(e)) { + DeferredProcedureKind kind = e->Procedure.deferred_procedure.kind; + Entity *deferred_entity = e->Procedure.deferred_procedure.entity; + lbValue *deferred_found = map_get(&p->module->values, hash_entity(deferred_entity)); + GB_ASSERT(deferred_found != nullptr); + lbValue deferred = *deferred_found; + + + auto in_args = args; + Array result_as_args = {}; + switch (kind) { + case DeferredProcedure_none: + break; + case DeferredProcedure_in: + result_as_args = in_args; + break; + case DeferredProcedure_out: + result_as_args = lb_value_to_array(p, result); + break; + } + + lb_add_defer_proc(p, p->scope_index, deferred, result_as_args); + } + } + + return result; +} + +lbValue lb_emit_array_ep(lbProcedure *p, lbValue s, lbValue index) { + Type *t = s.type; + GB_ASSERT(is_type_pointer(t)); + Type *st = base_type(type_deref(t)); + GB_ASSERT_MSG(is_type_array(st) || is_type_enumerated_array(st), "%s", type_to_string(st)); + GB_ASSERT_MSG(is_type_integer(index.type), "%s", type_to_string(index.type)); + + LLVMValueRef indices[2] = {}; + indices[0] = llvm_zero32(p->module); + indices[1] = lb_emit_conv(p, index, t_int).value; + + Type *ptr = base_array_type(st); + lbValue res = {}; + res.value = LLVMBuildGEP(p->builder, s.value, indices, 2, ""); + res.type = alloc_type_pointer(ptr); + return res; +} + +lbValue lb_emit_array_epi(lbProcedure *p, lbValue s, isize index) { + Type *t = s.type; + GB_ASSERT(is_type_pointer(t)); + Type *st = base_type(type_deref(t)); + GB_ASSERT_MSG(is_type_array(st) || is_type_enumerated_array(st), "%s", type_to_string(st)); + + GB_ASSERT(0 <= index); + Type *ptr = base_array_type(st); + + + LLVMValueRef indices[2] = { + LLVMConstInt(lb_type(p->module, t_int), 0, false), + LLVMConstInt(lb_type(p->module, t_int), cast(unsigned)index, false), + }; + + lbValue res = {}; + if (lb_is_const(s)) { + res.value = LLVMConstGEP(s.value, indices, gb_count_of(indices)); + } else { + res.value = LLVMBuildGEP(p->builder, s.value, indices, gb_count_of(indices), ""); + } + res.type = alloc_type_pointer(ptr); + return res; +} + +lbValue lb_emit_ptr_offset(lbProcedure *p, lbValue ptr, lbValue index) { + LLVMValueRef indices[1] = {index.value}; + lbValue res = {}; + res.type = ptr.type; + + if (lb_is_const(ptr) && lb_is_const(index)) { + res.value = LLVMConstGEP(ptr.value, indices, 1); + } else { + res.value = LLVMBuildGEP(p->builder, ptr.value, indices, 1, ""); + } + return res; +} + +LLVMValueRef llvm_const_slice(lbValue data, lbValue len) { + GB_ASSERT(is_type_pointer(data.type)); + GB_ASSERT(are_types_identical(len.type, t_int)); + LLVMValueRef vals[2] = { + data.value, + len.value, + }; + return LLVMConstStruct(vals, gb_count_of(vals), false); +} + + +void lb_fill_slice(lbProcedure *p, lbAddr const &slice, lbValue base_elem, lbValue len) { + Type *t = lb_addr_type(slice); + GB_ASSERT(is_type_slice(t)); + lbValue ptr = lb_addr_get_ptr(p, slice); + lb_emit_store(p, lb_emit_struct_ep(p, ptr, 0), base_elem); + lb_emit_store(p, lb_emit_struct_ep(p, ptr, 1), len); +} +void lb_fill_string(lbProcedure *p, lbAddr const &string, lbValue base_elem, lbValue len) { + Type *t = lb_addr_type(string); + GB_ASSERT(is_type_string(t)); + lbValue ptr = lb_addr_get_ptr(p, string); + lb_emit_store(p, lb_emit_struct_ep(p, ptr, 0), base_elem); + lb_emit_store(p, lb_emit_struct_ep(p, ptr, 1), len); +} + +lbValue lb_string_elem(lbProcedure *p, lbValue string) { + Type *t = base_type(string.type); + GB_ASSERT(t->kind == Type_Basic && t->Basic.kind == Basic_string); + return lb_emit_struct_ev(p, string, 0); +} +lbValue lb_string_len(lbProcedure *p, lbValue string) { + Type *t = base_type(string.type); + GB_ASSERT_MSG(t->kind == Type_Basic && t->Basic.kind == Basic_string, "%s", type_to_string(t)); + return lb_emit_struct_ev(p, string, 1); +} + +lbValue lb_cstring_len(lbProcedure *p, lbValue value) { + GB_ASSERT(is_type_cstring(value.type)); + auto args = array_make(heap_allocator(), 1); + args[0] = lb_emit_conv(p, value, t_cstring); + return lb_emit_runtime_call(p, "cstring_len", args); +} + + +lbValue lb_array_elem(lbProcedure *p, lbValue array_ptr) { + Type *t = type_deref(array_ptr.type); + GB_ASSERT(is_type_array(t)); + return lb_emit_struct_ep(p, array_ptr, 0); +} + +lbValue lb_slice_elem(lbProcedure *p, lbValue slice) { + GB_ASSERT(is_type_slice(slice.type)); + return lb_emit_struct_ev(p, slice, 0); +} +lbValue lb_slice_len(lbProcedure *p, lbValue slice) { + GB_ASSERT(is_type_slice(slice.type)); + return lb_emit_struct_ev(p, slice, 1); +} +lbValue lb_dynamic_array_elem(lbProcedure *p, lbValue da) { + GB_ASSERT(is_type_dynamic_array(da.type)); + return lb_emit_struct_ev(p, da, 0); +} +lbValue lb_dynamic_array_len(lbProcedure *p, lbValue da) { + GB_ASSERT(is_type_dynamic_array(da.type)); + return lb_emit_struct_ev(p, da, 1); +} +lbValue lb_dynamic_array_cap(lbProcedure *p, lbValue da) { + GB_ASSERT(is_type_dynamic_array(da.type)); + return lb_emit_struct_ev(p, da, 2); +} +lbValue lb_dynamic_array_allocator(lbProcedure *p, lbValue da) { + GB_ASSERT(is_type_dynamic_array(da.type)); + return lb_emit_struct_ev(p, da, 3); +} + +lbValue lb_map_entries(lbProcedure *p, lbValue value) { + gbAllocator a = heap_allocator(); + Type *t = base_type(value.type); + GB_ASSERT_MSG(t->kind == Type_Map, "%s", type_to_string(t)); + init_map_internal_types(t); + Type *gst = t->Map.generated_struct_type; + i32 index = 1; + lbValue entries = lb_emit_struct_ev(p, value, index); + return entries; +} + +lbValue lb_map_entries_ptr(lbProcedure *p, lbValue value) { + gbAllocator a = heap_allocator(); + Type *t = base_type(type_deref(value.type)); + GB_ASSERT_MSG(t->kind == Type_Map, "%s", type_to_string(t)); + init_map_internal_types(t); + Type *gst = t->Map.generated_struct_type; + i32 index = 1; + lbValue entries = lb_emit_struct_ep(p, value, index); + return entries; +} + +lbValue lb_map_len(lbProcedure *p, lbValue value) { + lbValue entries = lb_map_entries(p, value); + return lb_dynamic_array_len(p, entries); +} + +lbValue lb_map_cap(lbProcedure *p, lbValue value) { + lbValue entries = lb_map_entries(p, value); + return lb_dynamic_array_cap(p, entries); +} + +lbValue lb_soa_struct_len(lbProcedure *p, lbValue value) { + Type *t = base_type(value.type); + bool is_ptr = false; + if (is_type_pointer(t)) { + is_ptr = true; + t = base_type(type_deref(t)); + } + + + if (t->Struct.soa_kind == StructSoa_Fixed) { + return lb_const_int(p->module, t_int, t->Struct.soa_count); + } + + GB_ASSERT(t->Struct.soa_kind == StructSoa_Slice || + t->Struct.soa_kind == StructSoa_Dynamic); + + isize n = 0; + Type *elem = base_type(t->Struct.soa_elem); + if (elem->kind == Type_Struct) { + n = elem->Struct.fields.count; + } else if (elem->kind == Type_Array) { + n = elem->Array.count; + } else { + GB_PANIC("Unreachable"); + } + + if (is_ptr) { + lbValue v = lb_emit_struct_ep(p, value, cast(i32)n); + return lb_emit_load(p, v); + } + return lb_emit_struct_ev(p, value, cast(i32)n); +} + +lbValue lb_soa_struct_cap(lbProcedure *p, lbValue value) { + Type *t = base_type(value.type); + + bool is_ptr = false; + if (is_type_pointer(t)) { + is_ptr = true; + t = base_type(type_deref(t)); + } + + if (t->Struct.soa_kind == StructSoa_Fixed) { + return lb_const_int(p->module, t_int, t->Struct.soa_count); + } + + GB_ASSERT(t->Struct.soa_kind == StructSoa_Dynamic); + + isize n = 0; + Type *elem = base_type(t->Struct.soa_elem); + if (elem->kind == Type_Struct) { + n = elem->Struct.fields.count+1; + } else if (elem->kind == Type_Array) { + n = elem->Array.count+1; + } else { + GB_PANIC("Unreachable"); + } + + if (is_ptr) { + lbValue v = lb_emit_struct_ep(p, value, cast(i32)n); + return lb_emit_load(p, v); + } + return lb_emit_struct_ev(p, value, cast(i32)n); +} + + + + +lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, BuiltinProcId id) { + ast_node(ce, CallExpr, expr); + + switch (id) { + case BuiltinProc_DIRECTIVE: { + ast_node(bd, BasicDirective, ce->proc); + String name = bd->name; + GB_ASSERT(name == "location"); + String procedure = p->entity->token.string; + TokenPos pos = ast_token(ce->proc).pos; + if (ce->args.count > 0) { + Ast *ident = unselector_expr(ce->args[0]); + GB_ASSERT(ident->kind == Ast_Ident); + Entity *e = entity_of_ident(ident); + GB_ASSERT(e != nullptr); + + if (e->parent_proc_decl != nullptr && e->parent_proc_decl->entity != nullptr) { + procedure = e->parent_proc_decl->entity->token.string; + } else { + procedure = str_lit(""); + } + pos = e->token.pos; + + } + return lb_emit_source_code_location(p, procedure, pos); + } + + case BuiltinProc_type_info_of: { + Ast *arg = ce->args[0]; + TypeAndValue tav = type_and_value_of_expr(arg); + if (tav.mode == Addressing_Type) { + Type *t = default_type(type_of_expr(arg)); + return lb_type_info(p->module, t); + } + GB_ASSERT(is_type_typeid(tav.type)); + + auto args = array_make(heap_allocator(), 1); + args[0] = lb_build_expr(p, arg); + return lb_emit_runtime_call(p, "__type_info_of", args); + } + + case BuiltinProc_typeid_of: { + Ast *arg = ce->args[0]; + TypeAndValue tav = type_and_value_of_expr(arg); + if (tav.mode == Addressing_Type) { + Type *t = default_type(type_of_expr(arg)); + return lb_typeid(p->module, t); + } + Type *t = base_type(tav.type); + GB_ASSERT(are_types_identical(t, t_type_info_ptr)); + + auto args = array_make(heap_allocator(), 1); + args[0] = lb_emit_conv(p, lb_build_expr(p, arg), t_type_info_ptr); + return lb_emit_runtime_call(p, "__typeid_of", args); + } + + case BuiltinProc_len: { + lbValue v = lb_build_expr(p, ce->args[0]); + Type *t = base_type(v.type); + if (is_type_pointer(t)) { + // IMPORTANT TODO(bill): Should there be a nil pointer check? + v = lb_emit_load(p, v); + t = type_deref(t); + } + if (is_type_cstring(t)) { + return lb_cstring_len(p, v); + } else if (is_type_string(t)) { + return lb_string_len(p, v); + } else if (is_type_array(t)) { + GB_PANIC("Array lengths are constant"); + } else if (is_type_slice(t)) { + return lb_slice_len(p, v); + } else if (is_type_dynamic_array(t)) { + return lb_dynamic_array_len(p, v); + } else if (is_type_map(t)) { + return lb_map_len(p, v); + } else if (is_type_soa_struct(t)) { + return lb_soa_struct_len(p, v); + } + + GB_PANIC("Unreachable"); + break; + } + + case BuiltinProc_cap: { + lbValue v = lb_build_expr(p, ce->args[0]); + Type *t = base_type(v.type); + if (is_type_pointer(t)) { + // IMPORTANT TODO(bill): Should there be a nil pointer check? + v = lb_emit_load(p, v); + t = type_deref(t); + } + if (is_type_string(t)) { + GB_PANIC("Unreachable"); + } else if (is_type_array(t)) { + GB_PANIC("Array lengths are constant"); + } else if (is_type_slice(t)) { + return lb_slice_len(p, v); + } else if (is_type_dynamic_array(t)) { + return lb_dynamic_array_cap(p, v); + } else if (is_type_map(t)) { + return lb_map_cap(p, v); + } else if (is_type_soa_struct(t)) { + return lb_soa_struct_cap(p, v); + } + + GB_PANIC("Unreachable"); + + break; + } + + case BuiltinProc_swizzle: { + lbAddr addr = lb_build_addr(p, ce->args[0]); + isize index_count = ce->args.count-1; + if (index_count == 0) { + return lb_addr_load(p, addr); + } + lbValue src = lb_addr_get_ptr(p, addr); + // TODO(bill): Should this be zeroed or not? + lbAddr dst = lb_add_local_generated(p, tv.type, true); + lbValue dst_ptr = lb_addr_get_ptr(p, dst); + + for (i32 i = 1; i < ce->args.count; i++) { + TypeAndValue tv = type_and_value_of_expr(ce->args[i]); + GB_ASSERT(is_type_integer(tv.type)); + GB_ASSERT(tv.value.kind == ExactValue_Integer); + + i32 src_index = cast(i32)big_int_to_i64(&tv.value.value_integer); + i32 dst_index = i-1; + + lbValue src_elem = lb_emit_array_epi(p, src, src_index); + lbValue dst_elem = lb_emit_array_epi(p, dst_ptr, dst_index); + + lb_emit_store(p, dst_elem, lb_emit_load(p, src_elem)); + } + return lb_addr_load(p, dst); + } + + case BuiltinProc_complex: { + lbValue real = lb_build_expr(p, ce->args[0]); + lbValue imag = lb_build_expr(p, ce->args[1]); + lbAddr dst_addr = lb_add_local_generated(p, tv.type, false); + lbValue dst = lb_addr_get_ptr(p, dst_addr); + + Type *ft = base_complex_elem_type(tv.type); + real = lb_emit_conv(p, real, ft); + imag = lb_emit_conv(p, imag, ft); + lb_emit_store(p, lb_emit_struct_ep(p, dst, 0), real); + lb_emit_store(p, lb_emit_struct_ep(p, dst, 1), imag); + + return lb_emit_load(p, dst); + } + + case BuiltinProc_quaternion: { + lbValue real = lb_build_expr(p, ce->args[0]); + lbValue imag = lb_build_expr(p, ce->args[1]); + lbValue jmag = lb_build_expr(p, ce->args[2]); + lbValue kmag = lb_build_expr(p, ce->args[3]); + + // @QuaternionLayout + lbAddr dst_addr = lb_add_local_generated(p, tv.type, false); + lbValue dst = lb_addr_get_ptr(p, dst_addr); + + Type *ft = base_complex_elem_type(tv.type); + real = lb_emit_conv(p, real, ft); + imag = lb_emit_conv(p, imag, ft); + jmag = lb_emit_conv(p, jmag, ft); + kmag = lb_emit_conv(p, kmag, ft); + lb_emit_store(p, lb_emit_struct_ep(p, dst, 3), real); + lb_emit_store(p, lb_emit_struct_ep(p, dst, 0), imag); + lb_emit_store(p, lb_emit_struct_ep(p, dst, 1), jmag); + lb_emit_store(p, lb_emit_struct_ep(p, dst, 2), kmag); + + return lb_emit_load(p, dst); + } + + case BuiltinProc_real: { + lbValue val = lb_build_expr(p, ce->args[0]); + if (is_type_complex(val.type)) { + lbValue real = lb_emit_struct_ev(p, val, 0); + return lb_emit_conv(p, real, tv.type); + } else if (is_type_quaternion(val.type)) { + // @QuaternionLayout + lbValue real = lb_emit_struct_ev(p, val, 3); + return lb_emit_conv(p, real, tv.type); + } + GB_PANIC("invalid type for real"); + return {}; + } + case BuiltinProc_imag: { + lbValue val = lb_build_expr(p, ce->args[0]); + if (is_type_complex(val.type)) { + lbValue imag = lb_emit_struct_ev(p, val, 1); + return lb_emit_conv(p, imag, tv.type); + } else if (is_type_quaternion(val.type)) { + // @QuaternionLayout + lbValue imag = lb_emit_struct_ev(p, val, 0); + return lb_emit_conv(p, imag, tv.type); + } + GB_PANIC("invalid type for imag"); + return {}; + } + case BuiltinProc_jmag: { + lbValue val = lb_build_expr(p, ce->args[0]); + if (is_type_quaternion(val.type)) { + // @QuaternionLayout + lbValue imag = lb_emit_struct_ev(p, val, 1); + return lb_emit_conv(p, imag, tv.type); + } + GB_PANIC("invalid type for jmag"); + return {}; + } + case BuiltinProc_kmag: { + lbValue val = lb_build_expr(p, ce->args[0]); + if (is_type_quaternion(val.type)) { + // @QuaternionLayout + lbValue imag = lb_emit_struct_ev(p, val, 2); + return lb_emit_conv(p, imag, tv.type); + } + GB_PANIC("invalid type for kmag"); + return {}; + } + + case BuiltinProc_conj: { + lbValue val = lb_build_expr(p, ce->args[0]); + lbValue res = {}; + Type *t = val.type; + if (is_type_complex(t)) { + res = lb_addr_get_ptr(p, lb_add_local_generated(p, tv.type, false)); + lbValue real = lb_emit_struct_ev(p, val, 0); + lbValue imag = lb_emit_struct_ev(p, val, 1); + imag = lb_emit_unary_arith(p, Token_Sub, imag, imag.type); + lb_emit_store(p, lb_emit_struct_ep(p, res, 0), real); + lb_emit_store(p, lb_emit_struct_ep(p, res, 1), imag); + } else if (is_type_quaternion(t)) { + // @QuaternionLayout + res = lb_addr_get_ptr(p, lb_add_local_generated(p, tv.type, false)); + lbValue real = lb_emit_struct_ev(p, val, 3); + lbValue imag = lb_emit_struct_ev(p, val, 0); + lbValue jmag = lb_emit_struct_ev(p, val, 1); + lbValue kmag = lb_emit_struct_ev(p, val, 2); + imag = lb_emit_unary_arith(p, Token_Sub, imag, imag.type); + jmag = lb_emit_unary_arith(p, Token_Sub, jmag, jmag.type); + kmag = lb_emit_unary_arith(p, Token_Sub, kmag, kmag.type); + lb_emit_store(p, lb_emit_struct_ep(p, res, 3), real); + lb_emit_store(p, lb_emit_struct_ep(p, res, 0), imag); + lb_emit_store(p, lb_emit_struct_ep(p, res, 1), jmag); + lb_emit_store(p, lb_emit_struct_ep(p, res, 2), kmag); + } + return lb_emit_load(p, res); + } + + case BuiltinProc_expand_to_tuple: { + lbValue val = lb_build_expr(p, ce->args[0]); + Type *t = base_type(val.type); + + if (!is_type_tuple(tv.type)) { + if (t->kind == Type_Struct) { + GB_ASSERT(t->Struct.fields.count == 1); + return lb_emit_struct_ev(p, val, 0); + } else if (t->kind == Type_Array) { + GB_ASSERT(t->Array.count == 1); + return lb_emit_array_epi(p, val, 0); + } else { + GB_PANIC("Unknown type of expand_to_tuple"); + } + + } + + GB_ASSERT(is_type_tuple(tv.type)); + // NOTE(bill): Doesn't need to be zero because it will be initialized in the loops + lbValue tuple = lb_addr_get_ptr(p, lb_add_local_generated(p, tv.type, false)); + if (t->kind == Type_Struct) { + for_array(src_index, t->Struct.fields) { + Entity *field = t->Struct.fields[src_index]; + i32 field_index = field->Variable.field_index; + lbValue f = lb_emit_struct_ev(p, val, field_index); + lbValue ep = lb_emit_struct_ep(p, tuple, cast(i32)src_index); + lb_emit_store(p, ep, f); + } + } else if (t->kind == Type_Array) { + // TODO(bill): Clean-up this code + lbValue ap = lb_address_from_load_or_generate_local(p, val); + for (i32 i = 0; i < cast(i32)t->Array.count; i++) { + lbValue f = lb_emit_load(p, lb_emit_array_epi(p, ap, i)); + lbValue ep = lb_emit_struct_ep(p, tuple, i); + lb_emit_store(p, ep, f); + } + } else { + GB_PANIC("Unknown type of expand_to_tuple"); + } + return lb_emit_load(p, tuple); + } + + case BuiltinProc_min: { + Type *t = type_of_expr(expr); + if (ce->args.count == 2) { + return lb_emit_min(p, t, lb_build_expr(p, ce->args[0]), lb_build_expr(p, ce->args[1])); + } else { + lbValue x = lb_build_expr(p, ce->args[0]); + for (isize i = 1; i < ce->args.count; i++) { + x = lb_emit_min(p, t, x, lb_build_expr(p, ce->args[i])); + } + return x; + } + } + + case BuiltinProc_max: { + Type *t = type_of_expr(expr); + if (ce->args.count == 2) { + return lb_emit_max(p, t, lb_build_expr(p, ce->args[0]), lb_build_expr(p, ce->args[1])); + } else { + lbValue x = lb_build_expr(p, ce->args[0]); + for (isize i = 1; i < ce->args.count; i++) { + x = lb_emit_max(p, t, x, lb_build_expr(p, ce->args[i])); + } + return x; + } + } + + case BuiltinProc_abs: { + gbAllocator a = heap_allocator(); + lbValue x = lb_build_expr(p, ce->args[0]); + Type *t = x.type; + if (is_type_unsigned(t)) { + return x; + } + if (is_type_quaternion(t)) { + i64 sz = 8*type_size_of(t); + auto args = array_make(heap_allocator(), 1); + args[0] = x; + switch (sz) { + case 128: return lb_emit_runtime_call(p, "abs_quaternion128", args); + case 256: return lb_emit_runtime_call(p, "abs_quaternion256", args); + } + GB_PANIC("Unknown complex type"); + } else if (is_type_complex(t)) { + i64 sz = 8*type_size_of(t); + auto args = array_make(heap_allocator(), 1); + args[0] = x; + switch (sz) { + case 64: return lb_emit_runtime_call(p, "abs_complex64", args); + case 128: return lb_emit_runtime_call(p, "abs_complex128", args); + } + GB_PANIC("Unknown complex type"); + } else if (is_type_float(t)) { + i64 sz = 8*type_size_of(t); + auto args = array_make(heap_allocator(), 1); + args[0] = x; + switch (sz) { + case 32: return lb_emit_runtime_call(p, "abs_f32", args); + case 64: return lb_emit_runtime_call(p, "abs_f64", args); + } + GB_PANIC("Unknown float type"); + } + lbValue zero = lb_const_nil(p->module, t); + lbValue cond = lb_emit_comp(p, Token_Lt, x, zero); + lbValue neg = lb_emit_unary_arith(p, Token_Sub, x, t); + return lb_emit_select(p, cond, neg, x); + } + + case BuiltinProc_clamp: + return lb_emit_clamp(p, type_of_expr(expr), + lb_build_expr(p, ce->args[0]), + lb_build_expr(p, ce->args[1]), + lb_build_expr(p, ce->args[2])); + + + + // "Intrinsics" + case BuiltinProc_cpu_relax: + // TODO(bill): BuiltinProc_cpu_relax + // ir_write_str_lit(f, "call void asm sideeffect \"pause\", \"\"()"); + return {}; + + case BuiltinProc_atomic_fence: + LLVMBuildFence(p->builder, LLVMAtomicOrderingSequentiallyConsistent, false, ""); + return {}; + case BuiltinProc_atomic_fence_acq: + LLVMBuildFence(p->builder, LLVMAtomicOrderingAcquire, false, ""); + return {}; + case BuiltinProc_atomic_fence_rel: + LLVMBuildFence(p->builder, LLVMAtomicOrderingRelease, false, ""); + return {}; + case BuiltinProc_atomic_fence_acqrel: + LLVMBuildFence(p->builder, LLVMAtomicOrderingAcquireRelease, false, ""); + return {}; + + case BuiltinProc_atomic_store: + case BuiltinProc_atomic_store_rel: + case BuiltinProc_atomic_store_relaxed: + case BuiltinProc_atomic_store_unordered: { + lbValue dst = lb_build_expr(p, ce->args[0]); + lbValue val = lb_build_expr(p, ce->args[1]); + val = lb_emit_conv(p, val, type_deref(dst.type)); + + LLVMValueRef instr = LLVMBuildStore(p->builder, val.value, dst.value); + switch (id) { + case BuiltinProc_atomic_store: LLVMSetOrdering(instr, LLVMAtomicOrderingSequentiallyConsistent); break; + case BuiltinProc_atomic_store_rel: LLVMSetOrdering(instr, LLVMAtomicOrderingRelease); break; + case BuiltinProc_atomic_store_relaxed: LLVMSetOrdering(instr, LLVMAtomicOrderingMonotonic); break; + case BuiltinProc_atomic_store_unordered: LLVMSetOrdering(instr, LLVMAtomicOrderingUnordered); break; + } + + LLVMSetAlignment(instr, cast(unsigned)type_align_of(type_deref(dst.type))); + + return {}; + } + + case BuiltinProc_atomic_load: + case BuiltinProc_atomic_load_acq: + case BuiltinProc_atomic_load_relaxed: + case BuiltinProc_atomic_load_unordered: { + lbValue dst = lb_build_expr(p, ce->args[0]); + + LLVMValueRef instr = LLVMBuildLoad(p->builder, dst.value, ""); + switch (id) { + case BuiltinProc_atomic_load: LLVMSetOrdering(instr, LLVMAtomicOrderingSequentiallyConsistent); break; + case BuiltinProc_atomic_load_acq: LLVMSetOrdering(instr, LLVMAtomicOrderingAcquire); break; + case BuiltinProc_atomic_load_relaxed: LLVMSetOrdering(instr, LLVMAtomicOrderingMonotonic); break; + case BuiltinProc_atomic_load_unordered: LLVMSetOrdering(instr, LLVMAtomicOrderingUnordered); break; + } + LLVMSetAlignment(instr, cast(unsigned)type_align_of(type_deref(dst.type))); + + lbValue res = {}; + res.value = instr; + res.type = type_deref(dst.type); + return res; + } + + case BuiltinProc_atomic_add: + case BuiltinProc_atomic_add_acq: + case BuiltinProc_atomic_add_rel: + case BuiltinProc_atomic_add_acqrel: + case BuiltinProc_atomic_add_relaxed: + case BuiltinProc_atomic_sub: + case BuiltinProc_atomic_sub_acq: + case BuiltinProc_atomic_sub_rel: + case BuiltinProc_atomic_sub_acqrel: + case BuiltinProc_atomic_sub_relaxed: + case BuiltinProc_atomic_and: + case BuiltinProc_atomic_and_acq: + case BuiltinProc_atomic_and_rel: + case BuiltinProc_atomic_and_acqrel: + case BuiltinProc_atomic_and_relaxed: + case BuiltinProc_atomic_nand: + case BuiltinProc_atomic_nand_acq: + case BuiltinProc_atomic_nand_rel: + case BuiltinProc_atomic_nand_acqrel: + case BuiltinProc_atomic_nand_relaxed: + case BuiltinProc_atomic_or: + case BuiltinProc_atomic_or_acq: + case BuiltinProc_atomic_or_rel: + case BuiltinProc_atomic_or_acqrel: + case BuiltinProc_atomic_or_relaxed: + case BuiltinProc_atomic_xor: + case BuiltinProc_atomic_xor_acq: + case BuiltinProc_atomic_xor_rel: + case BuiltinProc_atomic_xor_acqrel: + case BuiltinProc_atomic_xor_relaxed: + case BuiltinProc_atomic_xchg: + case BuiltinProc_atomic_xchg_acq: + case BuiltinProc_atomic_xchg_rel: + case BuiltinProc_atomic_xchg_acqrel: + case BuiltinProc_atomic_xchg_relaxed: { + lbValue dst = lb_build_expr(p, ce->args[0]); + lbValue val = lb_build_expr(p, ce->args[1]); + val = lb_emit_conv(p, val, type_deref(dst.type)); + + LLVMAtomicRMWBinOp op = {}; + LLVMAtomicOrdering ordering = {}; + + switch (id) { + case BuiltinProc_atomic_add: op = LLVMAtomicRMWBinOpAdd; ordering = LLVMAtomicOrderingSequentiallyConsistent; break; + case BuiltinProc_atomic_add_acq: op = LLVMAtomicRMWBinOpAdd; ordering = LLVMAtomicOrderingAcquire; break; + case BuiltinProc_atomic_add_rel: op = LLVMAtomicRMWBinOpAdd; ordering = LLVMAtomicOrderingRelease; break; + case BuiltinProc_atomic_add_acqrel: op = LLVMAtomicRMWBinOpAdd; ordering = LLVMAtomicOrderingAcquireRelease; break; + case BuiltinProc_atomic_add_relaxed: op = LLVMAtomicRMWBinOpAdd; ordering = LLVMAtomicOrderingMonotonic; break; + case BuiltinProc_atomic_sub: op = LLVMAtomicRMWBinOpSub; ordering = LLVMAtomicOrderingSequentiallyConsistent; break; + case BuiltinProc_atomic_sub_acq: op = LLVMAtomicRMWBinOpSub; ordering = LLVMAtomicOrderingAcquire; break; + case BuiltinProc_atomic_sub_rel: op = LLVMAtomicRMWBinOpSub; ordering = LLVMAtomicOrderingRelease; break; + case BuiltinProc_atomic_sub_acqrel: op = LLVMAtomicRMWBinOpSub; ordering = LLVMAtomicOrderingAcquireRelease; break; + case BuiltinProc_atomic_sub_relaxed: op = LLVMAtomicRMWBinOpSub; ordering = LLVMAtomicOrderingMonotonic; break; + case BuiltinProc_atomic_and: op = LLVMAtomicRMWBinOpAnd; ordering = LLVMAtomicOrderingSequentiallyConsistent; break; + case BuiltinProc_atomic_and_acq: op = LLVMAtomicRMWBinOpAnd; ordering = LLVMAtomicOrderingAcquire; break; + case BuiltinProc_atomic_and_rel: op = LLVMAtomicRMWBinOpAnd; ordering = LLVMAtomicOrderingRelease; break; + case BuiltinProc_atomic_and_acqrel: op = LLVMAtomicRMWBinOpAnd; ordering = LLVMAtomicOrderingAcquireRelease; break; + case BuiltinProc_atomic_and_relaxed: op = LLVMAtomicRMWBinOpAnd; ordering = LLVMAtomicOrderingMonotonic; break; + case BuiltinProc_atomic_nand: op = LLVMAtomicRMWBinOpNand; ordering = LLVMAtomicOrderingSequentiallyConsistent; break; + case BuiltinProc_atomic_nand_acq: op = LLVMAtomicRMWBinOpNand; ordering = LLVMAtomicOrderingAcquire; break; + case BuiltinProc_atomic_nand_rel: op = LLVMAtomicRMWBinOpNand; ordering = LLVMAtomicOrderingRelease; break; + case BuiltinProc_atomic_nand_acqrel: op = LLVMAtomicRMWBinOpNand; ordering = LLVMAtomicOrderingAcquireRelease; break; + case BuiltinProc_atomic_nand_relaxed: op = LLVMAtomicRMWBinOpNand; ordering = LLVMAtomicOrderingMonotonic; break; + case BuiltinProc_atomic_or: op = LLVMAtomicRMWBinOpOr; ordering = LLVMAtomicOrderingSequentiallyConsistent; break; + case BuiltinProc_atomic_or_acq: op = LLVMAtomicRMWBinOpOr; ordering = LLVMAtomicOrderingAcquire; break; + case BuiltinProc_atomic_or_rel: op = LLVMAtomicRMWBinOpOr; ordering = LLVMAtomicOrderingRelease; break; + case BuiltinProc_atomic_or_acqrel: op = LLVMAtomicRMWBinOpOr; ordering = LLVMAtomicOrderingAcquireRelease; break; + case BuiltinProc_atomic_or_relaxed: op = LLVMAtomicRMWBinOpOr; ordering = LLVMAtomicOrderingMonotonic; break; + case BuiltinProc_atomic_xor: op = LLVMAtomicRMWBinOpXor; ordering = LLVMAtomicOrderingSequentiallyConsistent; break; + case BuiltinProc_atomic_xor_acq: op = LLVMAtomicRMWBinOpXor; ordering = LLVMAtomicOrderingAcquire; break; + case BuiltinProc_atomic_xor_rel: op = LLVMAtomicRMWBinOpXor; ordering = LLVMAtomicOrderingRelease; break; + case BuiltinProc_atomic_xor_acqrel: op = LLVMAtomicRMWBinOpXor; ordering = LLVMAtomicOrderingAcquireRelease; break; + case BuiltinProc_atomic_xor_relaxed: op = LLVMAtomicRMWBinOpXor; ordering = LLVMAtomicOrderingMonotonic; break; + case BuiltinProc_atomic_xchg: op = LLVMAtomicRMWBinOpXchg; ordering = LLVMAtomicOrderingSequentiallyConsistent; break; + case BuiltinProc_atomic_xchg_acq: op = LLVMAtomicRMWBinOpXchg; ordering = LLVMAtomicOrderingAcquire; break; + case BuiltinProc_atomic_xchg_rel: op = LLVMAtomicRMWBinOpXchg; ordering = LLVMAtomicOrderingRelease; break; + case BuiltinProc_atomic_xchg_acqrel: op = LLVMAtomicRMWBinOpXchg; ordering = LLVMAtomicOrderingAcquireRelease; break; + case BuiltinProc_atomic_xchg_relaxed: op = LLVMAtomicRMWBinOpXchg; ordering = LLVMAtomicOrderingMonotonic; break; + } + + LLVMValueRef instr = LLVMBuildAtomicRMW(p->builder, op, dst.value, val.value, ordering, false); + return {}; + } + + case BuiltinProc_atomic_cxchg: + case BuiltinProc_atomic_cxchg_acq: + case BuiltinProc_atomic_cxchg_rel: + case BuiltinProc_atomic_cxchg_acqrel: + case BuiltinProc_atomic_cxchg_relaxed: + case BuiltinProc_atomic_cxchg_failrelaxed: + case BuiltinProc_atomic_cxchg_failacq: + case BuiltinProc_atomic_cxchg_acq_failrelaxed: + case BuiltinProc_atomic_cxchg_acqrel_failrelaxed: + case BuiltinProc_atomic_cxchgweak: + case BuiltinProc_atomic_cxchgweak_acq: + case BuiltinProc_atomic_cxchgweak_rel: + case BuiltinProc_atomic_cxchgweak_acqrel: + case BuiltinProc_atomic_cxchgweak_relaxed: + case BuiltinProc_atomic_cxchgweak_failrelaxed: + case BuiltinProc_atomic_cxchgweak_failacq: + case BuiltinProc_atomic_cxchgweak_acq_failrelaxed: + case BuiltinProc_atomic_cxchgweak_acqrel_failrelaxed: { + Type *type = expr->tav.type; + + lbValue address = lb_build_expr(p, ce->args[0]); + Type *elem = type_deref(address.type); + lbValue old_value = lb_build_expr(p, ce->args[1]); + lbValue new_value = lb_build_expr(p, ce->args[2]); + old_value = lb_emit_conv(p, old_value, elem); + new_value = lb_emit_conv(p, new_value, elem); + + LLVMAtomicOrdering success_ordering = {}; + LLVMAtomicOrdering failure_ordering = {}; + LLVMBool weak = false; + + switch (id) { + case BuiltinProc_atomic_cxchg: success_ordering = LLVMAtomicOrderingSequentiallyConsistent; failure_ordering = LLVMAtomicOrderingSequentiallyConsistent; weak = false; break; + case BuiltinProc_atomic_cxchg_acq: success_ordering = LLVMAtomicOrderingAcquire; failure_ordering = LLVMAtomicOrderingSequentiallyConsistent; weak = false; break; + case BuiltinProc_atomic_cxchg_rel: success_ordering = LLVMAtomicOrderingRelease; failure_ordering = LLVMAtomicOrderingSequentiallyConsistent; weak = false; break; + case BuiltinProc_atomic_cxchg_acqrel: success_ordering = LLVMAtomicOrderingAcquireRelease; failure_ordering = LLVMAtomicOrderingSequentiallyConsistent; weak = false; break; + case BuiltinProc_atomic_cxchg_relaxed: success_ordering = LLVMAtomicOrderingMonotonic; failure_ordering = LLVMAtomicOrderingMonotonic; weak = false; break; + case BuiltinProc_atomic_cxchg_failrelaxed: success_ordering = LLVMAtomicOrderingSequentiallyConsistent; failure_ordering = LLVMAtomicOrderingMonotonic; weak = false; break; + case BuiltinProc_atomic_cxchg_failacq: success_ordering = LLVMAtomicOrderingSequentiallyConsistent; failure_ordering = LLVMAtomicOrderingAcquire; weak = false; break; + case BuiltinProc_atomic_cxchg_acq_failrelaxed: success_ordering = LLVMAtomicOrderingAcquire; failure_ordering = LLVMAtomicOrderingMonotonic; weak = false; break; + case BuiltinProc_atomic_cxchg_acqrel_failrelaxed: success_ordering = LLVMAtomicOrderingAcquireRelease; failure_ordering = LLVMAtomicOrderingMonotonic; weak = false; break; + case BuiltinProc_atomic_cxchgweak: success_ordering = LLVMAtomicOrderingSequentiallyConsistent; failure_ordering = LLVMAtomicOrderingSequentiallyConsistent; weak = false; break; + case BuiltinProc_atomic_cxchgweak_acq: success_ordering = LLVMAtomicOrderingAcquire; failure_ordering = LLVMAtomicOrderingSequentiallyConsistent; weak = true; break; + case BuiltinProc_atomic_cxchgweak_rel: success_ordering = LLVMAtomicOrderingRelease; failure_ordering = LLVMAtomicOrderingSequentiallyConsistent; weak = true; break; + case BuiltinProc_atomic_cxchgweak_acqrel: success_ordering = LLVMAtomicOrderingAcquireRelease; failure_ordering = LLVMAtomicOrderingSequentiallyConsistent; weak = true; break; + case BuiltinProc_atomic_cxchgweak_relaxed: success_ordering = LLVMAtomicOrderingMonotonic; failure_ordering = LLVMAtomicOrderingMonotonic; weak = true; break; + case BuiltinProc_atomic_cxchgweak_failrelaxed: success_ordering = LLVMAtomicOrderingSequentiallyConsistent; failure_ordering = LLVMAtomicOrderingMonotonic; weak = true; break; + case BuiltinProc_atomic_cxchgweak_failacq: success_ordering = LLVMAtomicOrderingSequentiallyConsistent; failure_ordering = LLVMAtomicOrderingAcquire; weak = true; break; + case BuiltinProc_atomic_cxchgweak_acq_failrelaxed: success_ordering = LLVMAtomicOrderingAcquire; failure_ordering = LLVMAtomicOrderingMonotonic; weak = true; break; + case BuiltinProc_atomic_cxchgweak_acqrel_failrelaxed: success_ordering = LLVMAtomicOrderingAcquireRelease; failure_ordering = LLVMAtomicOrderingMonotonic; weak = true; break; + } + + // TODO(bill): Figure out how to make it weak + LLVMBool single_threaded = !weak; + + LLVMValueRef instr = LLVMBuildAtomicCmpXchg(p->builder, address.value, + old_value.value, new_value.value, + success_ordering, + failure_ordering, + single_threaded); + + return {}; + } + } + + GB_PANIC("Unhandled built-in procedure %.*s", LIT(builtin_procs[id].name)); + return {}; +} + + +lbValue lb_build_call_expr(lbProcedure *p, Ast *expr) { + lbModule *m = p->module; + + TypeAndValue tv = type_and_value_of_expr(expr); + + ast_node(ce, CallExpr, expr); + + TypeAndValue proc_tv = type_and_value_of_expr(ce->proc); + AddressingMode proc_mode = proc_tv.mode; + if (proc_mode == Addressing_Type) { + GB_ASSERT(ce->args.count == 1); + lbValue x = lb_build_expr(p, ce->args[0]); + lbValue y = lb_emit_conv(p, x, tv.type); + return y; + } + + Ast *pexpr = unparen_expr(ce->proc); + if (proc_mode == Addressing_Builtin) { + Entity *e = entity_of_node(pexpr); + BuiltinProcId id = BuiltinProc_Invalid; + if (e != nullptr) { + id = cast(BuiltinProcId)e->Builtin.id; + } else { + id = BuiltinProc_DIRECTIVE; + } + return lb_build_builtin_proc(p, expr, tv, id); + } + + // NOTE(bill): Regular call + lbValue value = {}; + Ast *proc_expr = unparen_expr(ce->proc); + if (proc_expr->tav.mode == Addressing_Constant) { + ExactValue v = proc_expr->tav.value; + switch (v.kind) { + case ExactValue_Integer: + { + u64 u = big_int_to_u64(&v.value_integer); + lbValue x = {}; + x.value = LLVMConstInt(lb_type(m, t_uintptr), u, false); + x.type = t_uintptr; + x = lb_emit_conv(p, x, t_rawptr); + value = lb_emit_conv(p, x, proc_expr->tav.type); + break; + } + case ExactValue_Pointer: + { + u64 u = cast(u64)v.value_pointer; + lbValue x = {}; + x.value = LLVMConstInt(lb_type(m, t_uintptr), u, false); + x.type = t_uintptr; + x = lb_emit_conv(p, x, t_rawptr); + value = lb_emit_conv(p, x, proc_expr->tav.type); + break; + } + } + } + + if (value.value == nullptr) { + value = lb_build_expr(p, proc_expr); + } + + GB_ASSERT(value.value != nullptr); + Type *proc_type_ = base_type(value.type); + GB_ASSERT(proc_type_->kind == Type_Proc); + TypeProc *pt = &proc_type_->Proc; + set_procedure_abi_types(heap_allocator(), proc_type_); + + if (is_call_expr_field_value(ce)) { + auto args = array_make(heap_allocator(), pt->param_count); + + for_array(arg_index, ce->args) { + Ast *arg = ce->args[arg_index]; + ast_node(fv, FieldValue, arg); + GB_ASSERT(fv->field->kind == Ast_Ident); + String name = fv->field->Ident.token.string; + isize index = lookup_procedure_parameter(pt, name); + GB_ASSERT(index >= 0); + TypeAndValue tav = type_and_value_of_expr(fv->value); + if (tav.mode == Addressing_Type) { + args[index] = lb_const_nil(m, tav.type); + } else { + args[index] = lb_build_expr(p, fv->value); + } + } + TypeTuple *params = &pt->params->Tuple; + for (isize i = 0; i < args.count; i++) { + Entity *e = params->variables[i]; + if (e->kind == Entity_TypeName) { + args[i] = lb_const_nil(m, e->type); + } else if (e->kind == Entity_Constant) { + continue; + } else { + GB_ASSERT(e->kind == Entity_Variable); + if (args[i].value == nullptr) { + switch (e->Variable.param_value.kind) { + case ParameterValue_Constant: + args[i] = lb_const_value(p->module, e->type, e->Variable.param_value.value); + break; + case ParameterValue_Nil: + args[i] = lb_const_nil(m, e->type); + break; + case ParameterValue_Location: + args[i] = lb_emit_source_code_location(p, p->entity->token.string, ast_token(expr).pos); + break; + case ParameterValue_Value: + args[i] = lb_build_expr(p, e->Variable.param_value.ast_value); + break; + } + } else { + args[i] = lb_emit_conv(p, args[i], e->type); + } + } + } + + for (isize i = 0; i < args.count; i++) { + Entity *e = params->variables[i]; + if (args[i].type == nullptr) { + continue; + } else if (is_type_untyped_nil(args[i].type)) { + args[i] = lb_const_nil(m, e->type); + } else if (is_type_untyped_undef(args[i].type)) { + args[i] = lb_const_undef(m, e->type); + } + } + + return lb_emit_call(p, value, args, ce->inlining, p->return_ptr_hint_ast == expr); + } + + isize arg_index = 0; + + isize arg_count = 0; + for_array(i, ce->args) { + Ast *arg = ce->args[i]; + TypeAndValue tav = type_and_value_of_expr(arg); + GB_ASSERT_MSG(tav.mode != Addressing_Invalid, "%s %s", expr_to_string(arg), expr_to_string(expr)); + GB_ASSERT_MSG(tav.mode != Addressing_ProcGroup, "%s", expr_to_string(arg)); + Type *at = tav.type; + if (at->kind == Type_Tuple) { + arg_count += at->Tuple.variables.count; + } else { + arg_count++; + } + } + + isize param_count = 0; + if (pt->params) { + GB_ASSERT(pt->params->kind == Type_Tuple); + param_count = pt->params->Tuple.variables.count; + } + + auto args = array_make(heap_allocator(), cast(isize)gb_max(param_count, arg_count)); + isize variadic_index = pt->variadic_index; + bool variadic = pt->variadic && variadic_index >= 0; + bool vari_expand = ce->ellipsis.pos.line != 0; + bool is_c_vararg = pt->c_vararg; + + String proc_name = {}; + if (p->entity != nullptr) { + proc_name = p->entity->token.string; + } + TokenPos pos = ast_token(ce->proc).pos; + + TypeTuple *param_tuple = nullptr; + if (pt->params) { + GB_ASSERT(pt->params->kind == Type_Tuple); + param_tuple = &pt->params->Tuple; + } + + for_array(i, ce->args) { + Ast *arg = ce->args[i]; + TypeAndValue arg_tv = type_and_value_of_expr(arg); + if (arg_tv.mode == Addressing_Type) { + args[arg_index++] = lb_const_nil(m, arg_tv.type); + } else { + lbValue a = lb_build_expr(p, arg); + Type *at = a.type; + if (at->kind == Type_Tuple) { + for_array(i, at->Tuple.variables) { + Entity *e = at->Tuple.variables[i]; + lbValue v = lb_emit_struct_ev(p, a, cast(i32)i); + args[arg_index++] = v; + } + } else { + args[arg_index++] = a; + } + } + } + + + if (param_count > 0) { + GB_ASSERT_MSG(pt->params != nullptr, "%s %td", expr_to_string(expr), pt->param_count); + GB_ASSERT(param_count < 1000000); + + if (arg_count < param_count) { + isize end = cast(isize)param_count; + if (variadic) { + end = variadic_index; + } + while (arg_index < end) { + Entity *e = param_tuple->variables[arg_index]; + GB_ASSERT(e->kind == Entity_Variable); + + switch (e->Variable.param_value.kind) { + case ParameterValue_Constant: + args[arg_index++] = lb_const_value(p->module, e->type, e->Variable.param_value.value); + break; + case ParameterValue_Nil: + args[arg_index++] = lb_const_nil(m, e->type); + break; + case ParameterValue_Location: + args[arg_index++] = lb_emit_source_code_location(p, proc_name, pos); + break; + case ParameterValue_Value: + args[arg_index++] = lb_build_expr(p, e->Variable.param_value.ast_value); + break; + } + } + } + + if (is_c_vararg) { + GB_ASSERT(variadic); + GB_ASSERT(!vari_expand); + isize i = 0; + for (; i < variadic_index; i++) { + Entity *e = param_tuple->variables[i]; + if (e->kind == Entity_Variable) { + args[i] = lb_emit_conv(p, args[i], e->type); + } + } + Type *variadic_type = param_tuple->variables[i]->type; + GB_ASSERT(is_type_slice(variadic_type)); + variadic_type = base_type(variadic_type)->Slice.elem; + if (!is_type_any(variadic_type)) { + for (; i < arg_count; i++) { + args[i] = lb_emit_conv(p, args[i], variadic_type); + } + } else { + for (; i < arg_count; i++) { + args[i] = lb_emit_conv(p, args[i], default_type(args[i].type)); + } + } + } else if (variadic) { + isize i = 0; + for (; i < variadic_index; i++) { + Entity *e = param_tuple->variables[i]; + if (e->kind == Entity_Variable) { + args[i] = lb_emit_conv(p, args[i], e->type); + } + } + if (!vari_expand) { + Type *variadic_type = param_tuple->variables[i]->type; + GB_ASSERT(is_type_slice(variadic_type)); + variadic_type = base_type(variadic_type)->Slice.elem; + for (; i < arg_count; i++) { + args[i] = lb_emit_conv(p, args[i], variadic_type); + } + } + } else { + for (isize i = 0; i < param_count; i++) { + Entity *e = param_tuple->variables[i]; + if (e->kind == Entity_Variable) { + if (args[i].value == nullptr) { + continue; + } + GB_ASSERT_MSG(args[i].value != nullptr, "%.*s", LIT(e->token.string)); + args[i] = lb_emit_conv(p, args[i], e->type); + } + } + } + + if (variadic && !vari_expand && !is_c_vararg) { + // variadic call argument generation + gbAllocator allocator = heap_allocator(); + Type *slice_type = param_tuple->variables[variadic_index]->type; + Type *elem_type = base_type(slice_type)->Slice.elem; + lbAddr slice = lb_add_local_generated(p, slice_type, true); + isize slice_len = arg_count+1 - (variadic_index+1); + + if (slice_len > 0) { + lbAddr base_array = lb_add_local_generated(p, alloc_type_array(elem_type, slice_len), true); + + for (isize i = variadic_index, j = 0; i < arg_count; i++, j++) { + lbValue addr = lb_emit_array_epi(p, base_array.addr, cast(i32)j); + lb_emit_store(p, addr, args[i]); + } + + lbValue base_elem = lb_emit_array_epi(p, base_array.addr, 0); + lbValue len = lb_const_int(m, t_int, slice_len); + lb_fill_slice(p, slice, base_elem, len); + } + + arg_count = param_count; + args[variadic_index] = lb_addr_load(p, slice); + } + } + + if (variadic && variadic_index+1 < param_count) { + for (isize i = variadic_index+1; i < param_count; i++) { + Entity *e = param_tuple->variables[i]; + switch (e->Variable.param_value.kind) { + case ParameterValue_Constant: + args[i] = lb_const_value(p->module, e->type, e->Variable.param_value.value); + break; + case ParameterValue_Nil: + args[i] = lb_const_nil(m, e->type); + break; + case ParameterValue_Location: + args[i] = lb_emit_source_code_location(p, proc_name, pos); + break; + case ParameterValue_Value: + args[i] = lb_build_expr(p, e->Variable.param_value.ast_value); + break; + } + } + } + + isize final_count = param_count; + if (is_c_vararg) { + final_count = arg_count; + } + + if (param_tuple != nullptr) { + for (isize i = 0; i < gb_min(args.count, param_tuple->variables.count); i++) { + Entity *e = param_tuple->variables[i]; + if (args[i].type == nullptr) { + continue; + } else if (is_type_untyped_nil(args[i].type)) { + args[i] = lb_const_nil(m, e->type); + } else if (is_type_untyped_undef(args[i].type)) { + args[i] = lb_const_undef(m, e->type); + } + } + } + + auto call_args = array_slice(args, 0, final_count); + return lb_emit_call(p, value, call_args, ce->inlining, p->return_ptr_hint_ast == expr); +} + +bool lb_is_const(lbValue value) { + LLVMValueRef v = value.value; + if (is_type_untyped_nil(value.type) || is_type_untyped_undef(value.type)) { + // TODO(bill): Is this correct behaviour? + return true; + } + if (LLVMIsConstant(v)) { + return true; + } + return false; +} +bool lb_is_const_nil(lbValue value) { + LLVMValueRef v = value.value; + if (LLVMIsConstant(v)) { + if (LLVMIsAConstantAggregateZero(v)) { + return true; + } else if (LLVMIsAConstantPointerNull(v)) { + return true; + } + } + return false; +} + +String lb_get_const_string(lbModule *m, lbValue value) { + GB_ASSERT(lb_is_const(value)); + + Type *t = base_type(value.type); + GB_ASSERT(are_types_identical(t, t_string)); + + + + unsigned ptr_indices[1] = {0}; + unsigned len_indices[1] = {1}; + LLVMValueRef underlying_ptr = LLVMConstExtractValue(value.value, ptr_indices, gb_count_of(ptr_indices)); + LLVMValueRef underlying_len = LLVMConstExtractValue(value.value, len_indices, gb_count_of(len_indices)); + + GB_ASSERT(LLVMGetConstOpcode(underlying_ptr) == LLVMGetElementPtr); + underlying_ptr = LLVMGetOperand(underlying_ptr, 0); + GB_ASSERT(LLVMIsAGlobalVariable(underlying_ptr)); + underlying_ptr = LLVMGetInitializer(underlying_ptr); + + size_t length = 0; + char const *text = LLVMGetAsString(underlying_ptr, &length); + + isize real_length = cast(isize)LLVMConstIntGetSExtValue(underlying_len); + + return make_string(cast(u8 const *)text, real_length); +} + + +void lb_emit_increment(lbProcedure *p, lbValue addr) { + GB_ASSERT(is_type_pointer(addr.type)); + Type *type = type_deref(addr.type); + lbValue v_one = lb_const_value(p->module, type, exact_value_i64(1)); + lb_emit_store(p, addr, lb_emit_arith(p, Token_Add, lb_emit_load(p, addr), v_one, type)); + +} + +lbValue lb_emit_byte_swap(lbProcedure *p, lbValue value, Type *platform_type) { + Type *vt = core_type(value.type); + GB_ASSERT(type_size_of(vt) == type_size_of(platform_type)); + GB_ASSERT(is_type_integer(vt)); + + // TODO(bill): lb_emit_byte_swap + lbValue res = {}; + res.type = platform_type; + res.value = value.value; + + // int sz = cast(int)type_size_of(vt); + // if (sz > 1) { + // char buf[32] = {}; + // gb_snprintf(buf, gb_count_of(buf), "llvm.bswap.i%d", sz*8); + // unsigned id = LLVMLookupIntrinsicID(buf, gb_strlen(buf)); + // gb_printf(">>> %s %u\n", buf, id); + + // LLVMTypeRef types[2] = {}; + // types[0] = lb_type(p->module, value.type); + // types[1] = lb_type(p->module, value.type); + + // LLVMValueRef fn = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types)); + + // res.value = LLVMBuildCall(p->builder, fn, &value.value, 1, ""); + // } + + return res; +} + + +lbLoopData lb_loop_start(lbProcedure *p, isize count, Type *index_type) { + lbLoopData data = {}; + + lbValue max = lb_const_int(p->module, t_int, count); + + data.idx_addr = lb_add_local_generated(p, index_type, true); + + data.body = lb_create_block(p, "loop.body"); + data.done = lb_create_block(p, "loop.done"); + data.loop = lb_create_block(p, "loop.loop"); + + lb_emit_jump(p, data.loop); + lb_start_block(p, data.loop); + + data.idx = lb_addr_load(p, data.idx_addr); + + lbValue cond = lb_emit_comp(p, Token_Lt, data.idx, max); + lb_emit_if(p, cond, data.body, data.done); + lb_start_block(p, data.body); + + return data; +} + +void lb_loop_end(lbProcedure *p, lbLoopData const &data) { + if (data.idx_addr.addr.value != nullptr) { + lb_emit_increment(p, data.idx_addr.addr); + lb_emit_jump(p, data.loop); + lb_start_block(p, data.done); + } +} + +lbValue lb_emit_comp_against_nil(lbProcedure *p, TokenKind op_kind, lbValue x) { + lbValue res = {}; + res.type = t_llvm_bool; + Type *t = x.type; + if (is_type_pointer(t)) { + if (op_kind == Token_CmpEq) { + res.value = LLVMBuildIsNull(p->builder, x.value, ""); + } else if (op_kind == Token_NotEq) { + res.value = LLVMBuildIsNotNull(p->builder, x.value, ""); + } + return res; + } else if (is_type_cstring(t)) { + lbValue ptr = lb_emit_conv(p, x, t_u8_ptr); + if (op_kind == Token_CmpEq) { + res.value = LLVMBuildIsNull(p->builder, ptr.value, ""); + } else if (op_kind == Token_NotEq) { + res.value = LLVMBuildIsNotNull(p->builder, ptr.value, ""); + } + return res; + } else if (is_type_any(t)) { + lbValue data = lb_emit_struct_ev(p, x, 0); + lbValue ti = lb_emit_struct_ev(p, x, 1); + if (op_kind == Token_CmpEq) { + LLVMValueRef a = LLVMBuildIsNull(p->builder, data.value, ""); + LLVMValueRef b = LLVMBuildIsNull(p->builder, ti.value, ""); + res.value = LLVMBuildOr(p->builder, a, b, ""); + return res; + } else if (op_kind == Token_NotEq) { + LLVMValueRef a = LLVMBuildIsNotNull(p->builder, data.value, ""); + LLVMValueRef b = LLVMBuildIsNotNull(p->builder, ti.value, ""); + res.value = LLVMBuildAnd(p->builder, a, b, ""); + return res; + } + } else if (is_type_slice(t)) { + lbValue data = lb_emit_struct_ev(p, x, 0); + lbValue cap = lb_emit_struct_ev(p, x, 1); + if (op_kind == Token_CmpEq) { + LLVMValueRef a = LLVMBuildIsNull(p->builder, data.value, ""); + LLVMValueRef b = LLVMBuildIsNull(p->builder, cap.value, ""); + res.value = LLVMBuildOr(p->builder, a, b, ""); + return res; + } else if (op_kind == Token_NotEq) { + LLVMValueRef a = LLVMBuildIsNotNull(p->builder, data.value, ""); + LLVMValueRef b = LLVMBuildIsNotNull(p->builder, cap.value, ""); + res.value = LLVMBuildAnd(p->builder, a, b, ""); + return res; + } + } else if (is_type_dynamic_array(t)) { + lbValue data = lb_emit_struct_ev(p, x, 0); + lbValue cap = lb_emit_struct_ev(p, x, 2); + if (op_kind == Token_CmpEq) { + LLVMValueRef a = LLVMBuildIsNull(p->builder, data.value, ""); + LLVMValueRef b = LLVMBuildIsNull(p->builder, cap.value, ""); + res.value = LLVMBuildOr(p->builder, a, b, ""); + return res; + } else if (op_kind == Token_NotEq) { + LLVMValueRef a = LLVMBuildIsNotNull(p->builder, data.value, ""); + LLVMValueRef b = LLVMBuildIsNotNull(p->builder, cap.value, ""); + res.value = LLVMBuildAnd(p->builder, a, b, ""); + return res; + } + } else if (is_type_map(t)) { + lbValue cap = lb_map_cap(p, x); + return lb_emit_comp(p, op_kind, cap, lb_zero(p->module, cap.type)); + } else if (is_type_union(t)) { + if (type_size_of(t) == 0) { + if (op_kind == Token_CmpEq) { + return lb_const_bool(p->module, t_llvm_bool, true); + } else if (op_kind == Token_NotEq) { + return lb_const_bool(p->module, t_llvm_bool, false); + } + } else { + lbValue tag = lb_emit_union_tag_value(p, x); + return lb_emit_comp(p, op_kind, tag, lb_zero(p->module, tag.type)); + } + } else if (is_type_typeid(t)) { + lbValue invalid_typeid = lb_const_value(p->module, t_typeid, exact_value_i64(0)); + return lb_emit_comp(p, op_kind, x, invalid_typeid); + } else if (is_type_bit_field(t)) { + auto args = array_make(heap_allocator(), 2); + lbValue lhs = lb_address_from_load_or_generate_local(p, x); + args[0] = lb_emit_conv(p, lhs, t_rawptr); + args[1] = lb_const_int(p->module, t_int, type_size_of(t)); + lbValue val = lb_emit_runtime_call(p, "memory_compare_zero", args); + lbValue res = lb_emit_comp(p, op_kind, val, lb_const_int(p->module, t_int, 0)); + return res; + } else if (is_type_soa_struct(t)) { + GB_PANIC("#soa struct nil comparison"); + // Type *bt = base_type(t); + // if (bt->Struct.soa_kind == StructSoa_Slice) { + // lbValue len = lb_soa_struct_len(p, x); + // if (bt->Struct.fields.count > 1) { + // lbValue data = lb_emit_struct_ev(p, x, 0); + // if (op_kind == Token_CmpEq) { + // lbValue a = lb_emit_comp(p, Token_CmpEq, data, v_raw_nil); + // lbValue b = lb_emit_comp(p, Token_CmpEq, len, v_zero); + // return lb_emit_arith(p, Token_Or, a, b, t_bool); + // } else if (op_kind == Token_NotEq) { + // lbValue a = lb_emit_comp(p, Token_NotEq, data, v_raw_nil); + // lbValue b = lb_emit_comp(p, Token_NotEq, len, v_zero); + // return lb_emit_arith(p, Token_And, a, b, t_bool); + // } + // } else { + // return lb_emit_comp(p, op_kind, len, v_zero); + // } + // } else if (bt->Struct.soa_kind == StructSoa_Dynamic) { + // lbValue cap = lb_soa_struct_len(p, x); + // if (bt->Struct.fields.count > 1) { + // lbValue data = lb_emit_struct_ev(p, x, 0); + // if (op_kind == Token_CmpEq) { + // lbValue a = lb_emit_comp(p, Token_CmpEq, data, v_raw_nil); + // lbValue b = lb_emit_comp(p, Token_CmpEq, cap, v_zero); + // return lb_emit_arith(p, Token_Or, a, b, t_bool); + // } else if (op_kind == Token_NotEq) { + // lbValue a = lb_emit_comp(p, Token_NotEq, data, v_raw_nil); + // lbValue b = lb_emit_comp(p, Token_NotEq, cap, v_zero); + // return lb_emit_arith(p, Token_And, a, b, t_bool); + // } + // } else { + // return lb_emit_comp(p, op_kind, cap, v_zero); + // } + // } + } + return {}; +} + + +lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue right) { + Type *a = base_type(left.type); + Type *b = base_type(right.type); + + GB_ASSERT(gb_is_between(op_kind, Token__ComparisonBegin+1, Token__ComparisonEnd-1)); + + lbValue nil_check = {}; + if (is_type_untyped_nil(left.type)) { + nil_check = lb_emit_comp_against_nil(p, op_kind, right); + } else if (is_type_untyped_nil(right.type)) { + nil_check = lb_emit_comp_against_nil(p, op_kind, left); + } + if (nil_check.value != nullptr) { + return nil_check; + } + + if (are_types_identical(a, b)) { + // NOTE(bill): No need for a conversion + } else if (lb_is_const(left) || lb_is_const_nil(left)) { + left = lb_emit_conv(p, left, right.type); + } else if (lb_is_const(right) || lb_is_const_nil(right)) { + right = lb_emit_conv(p, right, left.type); + } else { + gbAllocator a = heap_allocator(); + + Type *lt = left.type; + Type *rt = right.type; + + if (is_type_bit_set(lt) && is_type_bit_set(rt)) { + Type *blt = base_type(lt); + Type *brt = base_type(rt); + GB_ASSERT(is_type_bit_field_value(blt)); + GB_ASSERT(is_type_bit_field_value(brt)); + i64 bits = gb_max(blt->BitFieldValue.bits, brt->BitFieldValue.bits); + i64 bytes = bits / 8; + switch (bytes) { + case 1: + left = lb_emit_conv(p, left, t_u8); + right = lb_emit_conv(p, right, t_u8); + break; + case 2: + left = lb_emit_conv(p, left, t_u16); + right = lb_emit_conv(p, right, t_u16); + break; + case 4: + left = lb_emit_conv(p, left, t_u32); + right = lb_emit_conv(p, right, t_u32); + break; + case 8: + left = lb_emit_conv(p, left, t_u64); + right = lb_emit_conv(p, right, t_u64); + break; + default: GB_PANIC("Unknown integer size"); break; + } + } + + lt = left.type; + rt = right.type; + i64 ls = type_size_of(lt); + i64 rs = type_size_of(rt); + if (ls < rs) { + left = lb_emit_conv(p, left, rt); + } else if (ls > rs) { + right = lb_emit_conv(p, right, lt); + } else { + right = lb_emit_conv(p, right, lt); + } + } + + if (is_type_array(a)) { + Type *tl = base_type(a); + lbValue lhs = lb_address_from_load_or_generate_local(p, left); + lbValue rhs = lb_address_from_load_or_generate_local(p, right); + + + TokenKind cmp_op = Token_And; + lbValue res = lb_const_bool(p->module, t_llvm_bool, true); + if (op_kind == Token_NotEq) { + res = lb_const_bool(p->module, t_llvm_bool, false); + cmp_op = Token_Or; + } else if (op_kind == Token_CmpEq) { + res = lb_const_bool(p->module, t_llvm_bool, true); + cmp_op = Token_And; + } + + bool inline_array_arith = type_size_of(tl) <= build_context.max_align; + i32 count = cast(i32)tl->Array.count; + + if (inline_array_arith) { + // inline + lbAddr val = lb_add_local_generated(p, t_bool, false); + lb_addr_store(p, val, res); + for (i32 i = 0; i < count; i++) { + lbValue x = lb_emit_load(p, lb_emit_array_epi(p, lhs, i)); + lbValue y = lb_emit_load(p, lb_emit_array_epi(p, rhs, i)); + lbValue cmp = lb_emit_comp(p, op_kind, x, y); + lbValue new_res = lb_emit_arith(p, cmp_op, lb_addr_load(p, val), cmp, t_bool); + lb_addr_store(p, val, lb_emit_conv(p, new_res, t_bool)); + } + + return lb_addr_load(p, val); + } else { + if (is_type_simple_compare(tl) && (op_kind == Token_CmpEq || op_kind == Token_NotEq)) { + // TODO(bill): Test to see if this is actually faster!!!! + auto args = array_make(heap_allocator(), 3); + args[0] = lb_emit_conv(p, lhs, t_rawptr); + args[1] = lb_emit_conv(p, rhs, t_rawptr); + args[2] = lb_const_int(p->module, t_int, type_size_of(tl)); + lbValue val = lb_emit_runtime_call(p, "memory_compare", args); + lbValue res = lb_emit_comp(p, op_kind, val, lb_const_nil(p->module, val.type)); + return lb_emit_conv(p, res, t_bool); + } else { + lbAddr val = lb_add_local_generated(p, t_bool, false); + lb_addr_store(p, val, res); + auto loop_data = lb_loop_start(p, count, t_i32); + { + lbValue i = loop_data.idx; + lbValue x = lb_emit_load(p, lb_emit_array_ep(p, lhs, i)); + lbValue y = lb_emit_load(p, lb_emit_array_ep(p, rhs, i)); + lbValue cmp = lb_emit_comp(p, op_kind, x, y); + lbValue new_res = lb_emit_arith(p, cmp_op, lb_addr_load(p, val), cmp, t_bool); + lb_addr_store(p, val, lb_emit_conv(p, new_res, t_bool)); + } + lb_loop_end(p, loop_data); + + return lb_addr_load(p, val); + } + } + } + + if (is_type_string(a)) { + if (is_type_cstring(a)) { + left = lb_emit_conv(p, left, t_string); + right = lb_emit_conv(p, right, t_string); + } + + char const *runtime_procedure = nullptr; + switch (op_kind) { + case Token_CmpEq: runtime_procedure = "string_eq"; break; + case Token_NotEq: runtime_procedure = "string_ne"; break; + case Token_Lt: runtime_procedure = "string_lt"; break; + case Token_Gt: runtime_procedure = "string_gt"; break; + case Token_LtEq: runtime_procedure = "string_le"; break; + case Token_GtEq: runtime_procedure = "string_gt"; break; + } + GB_ASSERT(runtime_procedure != nullptr); + + auto args = array_make(heap_allocator(), 2); + args[0] = left; + args[1] = right; + return lb_emit_runtime_call(p, runtime_procedure, args); + } + + if (is_type_complex(a)) { + char const *runtime_procedure = ""; + i64 sz = 8*type_size_of(a); + switch (sz) { + case 64: + switch (op_kind) { + case Token_CmpEq: runtime_procedure = "complex64_eq"; break; + case Token_NotEq: runtime_procedure = "complex64_ne"; break; + } + break; + case 128: + switch (op_kind) { + case Token_CmpEq: runtime_procedure = "complex128_eq"; break; + case Token_NotEq: runtime_procedure = "complex128_ne"; break; + } + break; + } + GB_ASSERT(runtime_procedure != nullptr); + + auto args = array_make(heap_allocator(), 2); + args[0] = left; + args[1] = right; + return lb_emit_runtime_call(p, runtime_procedure, args); + } + + if (is_type_quaternion(a)) { + char const *runtime_procedure = ""; + i64 sz = 8*type_size_of(a); + switch (sz) { + case 128: + switch (op_kind) { + case Token_CmpEq: runtime_procedure = "quaternion128_eq"; break; + case Token_NotEq: runtime_procedure = "quaternion128_ne"; break; + } + break; + case 256: + switch (op_kind) { + case Token_CmpEq: runtime_procedure = "quaternion256_eq"; break; + case Token_NotEq: runtime_procedure = "quaternion256_ne"; break; + } + break; + } + GB_ASSERT(runtime_procedure != nullptr); + + auto args = array_make(heap_allocator(), 2); + args[0] = left; + args[1] = right; + return lb_emit_runtime_call(p, runtime_procedure, args); + } + + if (is_type_bit_set(a)) { + switch (op_kind) { + case Token_Lt: + case Token_LtEq: + case Token_Gt: + case Token_GtEq: + { + Type *it = bit_set_to_int(a); + lbValue lhs = lb_emit_transmute(p, left, it); + lbValue rhs = lb_emit_transmute(p, right, it); + lbValue res = lb_emit_arith(p, Token_And, lhs, rhs, it); + + if (op_kind == Token_Lt || op_kind == Token_LtEq) { + // (lhs & rhs) == lhs + res.value = LLVMBuildICmp(p->builder, LLVMIntEQ, res.value, lhs.value, ""); + res.type = t_llvm_bool; + } else if (op_kind == Token_Gt || op_kind == Token_GtEq) { + // (lhs & rhs) == rhs + res.value = LLVMBuildICmp(p->builder, LLVMIntEQ, res.value, rhs.value, ""); + res.type = t_llvm_bool; + } + + // NOTE(bill): Strict subsets + if (op_kind == Token_Lt || op_kind == Token_Gt) { + // res &~ (lhs == rhs) + lbValue eq = {}; + eq.value = LLVMBuildICmp(p->builder, LLVMIntEQ, lhs.value, rhs.value, ""); + eq.type = t_llvm_bool; + res = lb_emit_arith(p, Token_AndNot, res, eq, t_llvm_bool); + } + + return res; + } + + case Token_CmpEq: + case Token_NotEq: + { + LLVMIntPredicate pred = {}; + switch (op_kind) { + case Token_CmpEq: pred = LLVMIntEQ; break; + case Token_NotEq: pred = LLVMIntNE; break; + } + lbValue res = {}; + res.type = t_llvm_bool; + res.value = LLVMBuildICmp(p->builder, pred, left.value, right.value, ""); + return res; + } + } + } + + if (op_kind != Token_CmpEq && op_kind != Token_NotEq) { + Type *t = left.type; + if (is_type_integer(t) && is_type_different_to_arch_endianness(t)) { + Type *platform_type = integer_endian_type_to_platform_type(t); + lbValue x = lb_emit_byte_swap(p, left, platform_type); + lbValue y = lb_emit_byte_swap(p, right, platform_type); + left = x; + right = y; + } + } + + + lbValue res = {}; + res.type = t_llvm_bool; + if (is_type_integer(left.type) || + is_type_boolean(left.type) || + is_type_pointer(left.type) || + is_type_proc(left.type) || + is_type_enum(left.type)) { + LLVMIntPredicate pred = {}; + if (is_type_unsigned(left.type)) { + switch (op_kind) { + case Token_Gt: pred = LLVMIntUGT; break; + case Token_GtEq: pred = LLVMIntUGE; break; + case Token_Lt: pred = LLVMIntULT; break; + case Token_LtEq: pred = LLVMIntULE; break; + } + } else { + switch (op_kind) { + case Token_Gt: pred = LLVMIntSGT; break; + case Token_GtEq: pred = LLVMIntSGE; break; + case Token_Lt: pred = LLVMIntSLT; break; + case Token_LtEq: pred = LLVMIntSLE; break; + } + } + switch (op_kind) { + case Token_CmpEq: pred = LLVMIntEQ; break; + case Token_NotEq: pred = LLVMIntNE; break; + } + res.value = LLVMBuildICmp(p->builder, pred, left.value, right.value, ""); + } else if (is_type_float(left.type)) { + LLVMRealPredicate pred = {}; + switch (op_kind) { + case Token_CmpEq: pred = LLVMRealOEQ; break; + case Token_Gt: pred = LLVMRealOGT; break; + case Token_GtEq: pred = LLVMRealOGE; break; + case Token_Lt: pred = LLVMRealOLT; break; + case Token_LtEq: pred = LLVMRealOLE; break; + case Token_NotEq: pred = LLVMRealONE; break; + } + res.value = LLVMBuildFCmp(p->builder, pred, left.value, right.value, ""); + } else if (is_type_typeid(left.type)) { + LLVMIntPredicate pred = {}; + switch (op_kind) { + case Token_Gt: pred = LLVMIntUGT; break; + case Token_GtEq: pred = LLVMIntUGE; break; + case Token_Lt: pred = LLVMIntULT; break; + case Token_LtEq: pred = LLVMIntULE; break; + case Token_CmpEq: pred = LLVMIntEQ; break; + case Token_NotEq: pred = LLVMIntNE; break; + } + res.value = LLVMBuildICmp(p->builder, pred, left.value, right.value, ""); + } else { + GB_PANIC("Unhandled comparison kind %s %.*s %s", type_to_string(left.type), LIT(token_strings[op_kind]), type_to_string(right.type)); + } + + return res; +} + + +lbValue lb_generate_anonymous_proc_lit(lbModule *m, String const &prefix_name, Ast *expr, lbProcedure *parent) { + ast_node(pl, ProcLit, expr); + + // NOTE(bill): Generate a new name + // parent$count + isize name_len = prefix_name.len + 1 + 8 + 1; + char *name_text = gb_alloc_array(heap_allocator(), char, name_len); + i32 name_id = cast(i32)m->anonymous_proc_lits.entries.count; + + name_len = gb_snprintf(name_text, name_len, "%.*s$anon-%d", LIT(prefix_name), name_id); + String name = make_string((u8 *)name_text, name_len-1); + + Type *type = type_of_expr(expr); + set_procedure_abi_types(heap_allocator(), type); + + + Token token = {}; + token.pos = ast_token(expr).pos; + token.kind = Token_Ident; + token.string = name; + Entity *e = alloc_entity_procedure(nullptr, token, type, pl->tags); + e->decl_info = pl->decl; + lbProcedure *p = lb_create_procedure(m, e); + + lbValue value = {}; + value.value = p->value; + value.type = p->type; + + array_add(&m->procedures_to_generate, p); + if (parent != nullptr) { + array_add(&parent->children, p); + } else { + map_set(&m->members, hash_string(name), value); + } + + map_set(&m->anonymous_proc_lits, hash_pointer(expr), p); + + return value; +} + +lbValue lb_emit_union_cast(lbProcedure *p, lbValue value, Type *type, TokenPos pos, bool do_conversion_check=true) { + lbModule *m = p->module; + + Type *src_type = value.type; + bool is_ptr = is_type_pointer(src_type); + + bool is_tuple = true; + Type *tuple = type; + if (type->kind != Type_Tuple) { + is_tuple = false; + tuple = make_optional_ok_type(type); + } + + lbAddr v = lb_add_local_generated(p, tuple, true); + + if (is_ptr) { + value = lb_emit_load(p, value); + } + Type *src = base_type(type_deref(src_type)); + GB_ASSERT_MSG(is_type_union(src), "%s", type_to_string(src_type)); + Type *dst = tuple->Tuple.variables[0]->type; + + lbValue value_ = lb_address_from_load_or_generate_local(p, value); + + lbValue tag = {}; + lbValue dst_tag = {}; + lbValue cond = {}; + lbValue data = {}; + + lbValue gep0 = lb_emit_struct_ep(p, v.addr, 0); + lbValue gep1 = lb_emit_struct_ep(p, v.addr, 1); + + if (is_type_union_maybe_pointer(src)) { + data = lb_emit_load(p, lb_emit_conv(p, value_, gep0.type)); + } else { + tag = lb_emit_load(p, lb_emit_union_tag_ptr(p, value_)); + dst_tag = lb_const_union_tag(m, src, dst); + } + + lbBlock *ok_block = lb_create_block(p, "union_cast.ok"); + lbBlock *end_block = lb_create_block(p, "union_cast.end"); + + if (data.value != nullptr) { + GB_ASSERT(is_type_union_maybe_pointer(src)); + cond = lb_emit_comp_against_nil(p, Token_NotEq, data); + } else { + cond = lb_emit_comp(p, Token_CmpEq, tag, dst_tag); + } + + lb_emit_if(p, cond, ok_block, end_block); + lb_start_block(p, ok_block); + + + + if (data.value == nullptr) { + data = lb_emit_load(p, lb_emit_conv(p, value_, gep0.type)); + } + lb_emit_store(p, gep0, data); + lb_emit_store(p, gep1, lb_const_bool(m, t_bool, true)); + + lb_emit_jump(p, end_block); + lb_start_block(p, end_block); + + if (!is_tuple) { + if (do_conversion_check) { + // NOTE(bill): Panic on invalid conversion + Type *dst_type = tuple->Tuple.variables[0]->type; + + lbValue ok = lb_emit_load(p, lb_emit_struct_ep(p, v.addr, 1)); + auto args = array_make(heap_allocator(), 6); + args[0] = ok; + + args[1] = lb_const_string(m, pos.file); + args[2] = lb_const_int(m, t_int, pos.line); + args[3] = lb_const_int(m, t_int, pos.column); + + args[4] = lb_typeid(m, src_type); + args[5] = lb_typeid(m, dst_type); + lb_emit_runtime_call(p, "type_assertion_check", args); + } + + return lb_emit_load(p, lb_emit_struct_ep(p, v.addr, 0)); + } + return lb_addr_load(p, v); +} + +lbAddr lb_emit_any_cast_addr(lbProcedure *p, lbValue value, Type *type, TokenPos pos) { + lbModule *m = p->module; + + Type *src_type = value.type; + + if (is_type_pointer(src_type)) { + value = lb_emit_load(p, value); + } + + bool is_tuple = true; + Type *tuple = type; + if (type->kind != Type_Tuple) { + is_tuple = false; + tuple = make_optional_ok_type(type); + } + Type *dst_type = tuple->Tuple.variables[0]->type; + + lbAddr v = lb_add_local_generated(p, tuple, true); + + lbValue dst_typeid = lb_typeid(m, dst_type); + lbValue any_typeid = lb_emit_struct_ev(p, value, 1); + + + lbBlock *ok_block = lb_create_block(p, "any_cast.ok"); + lbBlock *end_block = lb_create_block(p, "any_cast.end"); + lbValue cond = lb_emit_comp(p, Token_CmpEq, any_typeid, dst_typeid); + lb_emit_if(p, cond, ok_block, end_block); + lb_start_block(p, ok_block); + + lbValue gep0 = lb_emit_struct_ep(p, v.addr, 0); + lbValue gep1 = lb_emit_struct_ep(p, v.addr, 1); + + lbValue any_data = lb_emit_struct_ev(p, value, 0); + lbValue ptr = lb_emit_conv(p, any_data, alloc_type_pointer(dst_type)); + lb_emit_store(p, gep0, lb_emit_load(p, ptr)); + lb_emit_store(p, gep1, lb_const_bool(m, t_bool, true)); + + lb_emit_jump(p, end_block); + lb_start_block(p, end_block); + + if (!is_tuple) { + // NOTE(bill): Panic on invalid conversion + + lbValue ok = lb_emit_load(p, lb_emit_struct_ep(p, v.addr, 1)); + auto args = array_make(heap_allocator(), 6); + args[0] = ok; + + args[1] = lb_const_string(m, pos.file); + args[2] = lb_const_int(m, t_int, pos.line); + args[3] = lb_const_int(m, t_int, pos.column); + + args[4] = any_typeid; + args[5] = dst_typeid; + lb_emit_runtime_call(p, "type_assertion_check", args); + + return lb_addr(lb_emit_struct_ep(p, v.addr, 0)); + } + return v; +} +lbValue lb_emit_any_cast(lbProcedure *p, lbValue value, Type *type, TokenPos pos) { + return lb_addr_load(p, lb_emit_any_cast_addr(p, value, type, pos)); +} + + +lbValue lb_build_expr(lbProcedure *p, Ast *expr) { + lbModule *m = p->module; + + expr = unparen_expr(expr); + + TypeAndValue tv = type_and_value_of_expr(expr); + GB_ASSERT(tv.mode != Addressing_Invalid); + GB_ASSERT(tv.mode != Addressing_Type); + + if (tv.value.kind != ExactValue_Invalid) { + // NOTE(bill): Short on constant values + return lb_const_value(p->module, tv.type, tv.value); + } + + + + switch (expr->kind) { + case_ast_node(bl, BasicLit, expr); + TokenPos pos = bl->token.pos; + GB_PANIC("Non-constant basic literal %.*s(%td:%td) - %.*s", LIT(pos.file), pos.line, pos.column, LIT(token_strings[bl->token.kind])); + case_end; + + case_ast_node(bd, BasicDirective, expr); + TokenPos pos = bd->token.pos; + GB_PANIC("Non-constant basic literal %.*s(%td:%td) - %.*s", LIT(pos.file), pos.line, pos.column, LIT(bd->name)); + case_end; + + case_ast_node(i, Implicit, expr); + return lb_addr_load(p, lb_build_addr(p, expr)); + case_end; + + case_ast_node(u, Undef, expr) + lbValue res = {}; + if (is_type_untyped(tv.type)) { + res.value = nullptr; + res.type = t_untyped_undef; + } else { + res.value = LLVMGetUndef(lb_type(m, tv.type)); + res.type = tv.type; + } + return res; + case_end; + + case_ast_node(i, Ident, expr); + Entity *e = entity_of_ident(expr); + GB_ASSERT_MSG(e != nullptr, "%s", expr_to_string(expr)); + if (e->kind == Entity_Builtin) { + Token token = ast_token(expr); + GB_PANIC("TODO(bill): lb_build_expr Entity_Builtin '%.*s'\n" + "\t at %.*s(%td:%td)", LIT(builtin_procs[e->Builtin.id].name), + LIT(token.pos.file), token.pos.line, token.pos.column); + return {}; + } else if (e->kind == Entity_Nil) { + lbValue res = {}; + res.value = nullptr; + res.type = e->type; + return res; + } + GB_ASSERT(e->kind != Entity_ProcGroup); + + auto *found = map_get(&p->module->values, hash_entity(e)); + if (found) { + auto v = *found; + // NOTE(bill): This is because pointers are already pointers in LLVM + if (is_type_proc(v.type)) { + return v; + } + return lb_emit_load(p, v); + } else if (e != nullptr && e->kind == Entity_Variable) { + return lb_addr_load(p, lb_build_addr(p, expr)); + } + gb_printf_err("Error in: %.*s(%td:%td)\n", LIT(p->name), i->token.pos.line, i->token.pos.column); + GB_PANIC("nullptr value for expression from identifier: %.*s.%.*s (%p) : %s @ %p", LIT(e->pkg->name), LIT(e->token.string), e, type_to_string(e->type), expr); + return {}; + case_end; + + case_ast_node(de, DerefExpr, expr); + return lb_addr_load(p, lb_build_addr(p, expr)); + case_end; + + case_ast_node(se, SelectorExpr, expr); + TypeAndValue tav = type_and_value_of_expr(expr); + GB_ASSERT(tav.mode != Addressing_Invalid); + return lb_addr_load(p, lb_build_addr(p, expr)); + case_end; + + case_ast_node(ise, ImplicitSelectorExpr, expr); + TypeAndValue tav = type_and_value_of_expr(expr); + GB_ASSERT(tav.mode == Addressing_Constant); + + return lb_const_value(p->module, tv.type, tv.value); + case_end; + + case_ast_node(te, TernaryExpr, expr); + LLVMValueRef incoming_values[2] = {}; + LLVMBasicBlockRef incoming_blocks[2] = {}; + + GB_ASSERT(te->y != nullptr); + lbBlock *then = lb_create_block(p, "if.then"); + lbBlock *done = lb_create_block(p, "if.done"); // NOTE(bill): Append later + lbBlock *else_ = lb_create_block(p, "if.else"); + + lbValue cond = lb_build_cond(p, te->cond, then, else_); + lb_start_block(p, then); + + Type *type = default_type(type_of_expr(expr)); + + lb_open_scope(p); + incoming_values[0] = lb_emit_conv(p, lb_build_expr(p, te->x), type).value; + lb_close_scope(p, lbDeferExit_Default, nullptr); + + lb_emit_jump(p, done); + lb_start_block(p, else_); + + lb_open_scope(p); + incoming_values[1] = lb_emit_conv(p, lb_build_expr(p, te->y), type).value; + lb_close_scope(p, lbDeferExit_Default, nullptr); + + lb_emit_jump(p, done); + lb_start_block(p, done); + + lbValue res = {}; + res.value = LLVMBuildPhi(p->builder, lb_type(p->module, type), ""); + res.type = type; + + GB_ASSERT(p->curr_block->preds.count >= 2); + incoming_blocks[0] = p->curr_block->preds[0]->block; + incoming_blocks[1] = p->curr_block->preds[1]->block; + + LLVMAddIncoming(res.value, incoming_values, incoming_blocks, 2); + + return res; + case_end; + + case_ast_node(te, TernaryIfExpr, expr); + LLVMValueRef incoming_values[2] = {}; + LLVMBasicBlockRef incoming_blocks[2] = {}; + + GB_ASSERT(te->y != nullptr); + lbBlock *then = lb_create_block(p, "if.then"); + lbBlock *done = lb_create_block(p, "if.done"); // NOTE(bill): Append later + lbBlock *else_ = lb_create_block(p, "if.else"); + + lbValue cond = lb_build_cond(p, te->cond, then, else_); + lb_start_block(p, then); + + Type *type = default_type(type_of_expr(expr)); + + lb_open_scope(p); + incoming_values[0] = lb_emit_conv(p, lb_build_expr(p, te->x), type).value; + lb_close_scope(p, lbDeferExit_Default, nullptr); + + lb_emit_jump(p, done); + lb_start_block(p, else_); + + lb_open_scope(p); + incoming_values[1] = lb_emit_conv(p, lb_build_expr(p, te->y), type).value; + lb_close_scope(p, lbDeferExit_Default, nullptr); + + lb_emit_jump(p, done); + lb_start_block(p, done); + + lbValue res = {}; + res.value = LLVMBuildPhi(p->builder, lb_type(p->module, type), ""); + res.type = type; + + GB_ASSERT(p->curr_block->preds.count >= 2); + incoming_blocks[0] = p->curr_block->preds[0]->block; + incoming_blocks[1] = p->curr_block->preds[1]->block; + + LLVMAddIncoming(res.value, incoming_values, incoming_blocks, 2); + + return res; + case_end; + + case_ast_node(te, TernaryWhenExpr, expr); + TypeAndValue tav = type_and_value_of_expr(te->cond); + GB_ASSERT(tav.mode == Addressing_Constant); + GB_ASSERT(tav.value.kind == ExactValue_Bool); + if (tav.value.value_bool) { + return lb_build_expr(p, te->x); + } else { + return lb_build_expr(p, te->y); + } + case_end; + + case_ast_node(ta, TypeAssertion, expr); + TokenPos pos = ast_token(expr).pos; + Type *type = tv.type; + lbValue e = lb_build_expr(p, ta->expr); + Type *t = type_deref(e.type); + if (is_type_union(t)) { + return lb_emit_union_cast(p, e, type, pos); + } else if (is_type_any(t)) { + return lb_emit_any_cast(p, e, type, pos); + } else { + GB_PANIC("TODO(bill): type assertion %s", type_to_string(e.type)); + } + case_end; + + case_ast_node(tc, TypeCast, expr); + lbValue e = lb_build_expr(p, tc->expr); + switch (tc->token.kind) { + case Token_cast: + return lb_emit_conv(p, e, tv.type); + case Token_transmute: + return lb_emit_transmute(p, e, tv.type); + } + GB_PANIC("Invalid AST TypeCast"); + case_end; + + case_ast_node(ac, AutoCast, expr); + return lb_build_expr(p, ac->expr); + case_end; + + case_ast_node(ue, UnaryExpr, expr); + switch (ue->op.kind) { + case Token_And: { + Ast *ue_expr = unparen_expr(ue->expr); + if (ue_expr->kind == Ast_CompoundLit) { + lbValue v = lb_build_expr(p, ue->expr); + + Type *type = v.type; + lbAddr addr = {}; + if (p->is_startup) { + addr = lb_add_global_generated(p->module, type, v); + } else { + addr = lb_add_local_generated(p, type, false); + } + lb_addr_store(p, addr, v); + return addr.addr; + + } else if (ue_expr->kind == Ast_TypeAssertion) { + gbAllocator a = heap_allocator(); + GB_ASSERT(is_type_pointer(tv.type)); + + ast_node(ta, TypeAssertion, ue_expr); + TokenPos pos = ast_token(expr).pos; + Type *type = type_of_expr(ue_expr); + GB_ASSERT(!is_type_tuple(type)); + + lbValue e = lb_build_expr(p, ta->expr); + Type *t = type_deref(e.type); + if (is_type_union(t)) { + lbValue v = e; + if (!is_type_pointer(v.type)) { + v = lb_address_from_load_or_generate_local(p, v); + } + Type *src_type = type_deref(v.type); + Type *dst_type = type; + + lbValue src_tag = lb_emit_load(p, lb_emit_union_tag_ptr(p, v)); + lbValue dst_tag = lb_const_union_tag(p->module, src_type, dst_type); + + lbValue ok = lb_emit_comp(p, Token_CmpEq, src_tag, dst_tag); + auto args = array_make(heap_allocator(), 6); + args[0] = ok; + + args[1] = lb_find_or_add_entity_string(p->module, pos.file); + args[2] = lb_const_int(p->module, t_int, pos.line); + args[3] = lb_const_int(p->module, t_int, pos.column); + + args[4] = lb_typeid(p->module, src_type); + args[5] = lb_typeid(p->module, dst_type); + lb_emit_runtime_call(p, "type_assertion_check", args); + + lbValue data_ptr = v; + return lb_emit_conv(p, data_ptr, tv.type); + } else if (is_type_any(t)) { + lbValue v = e; + if (is_type_pointer(v.type)) { + v = lb_emit_load(p, v); + } + + lbValue data_ptr = lb_emit_struct_ev(p, v, 0); + lbValue any_id = lb_emit_struct_ev(p, v, 1); + lbValue id = lb_typeid(p->module, type); + + + lbValue ok = lb_emit_comp(p, Token_CmpEq, any_id, id); + auto args = array_make(heap_allocator(), 6); + args[0] = ok; + + args[1] = lb_find_or_add_entity_string(p->module, pos.file); + args[2] = lb_const_int(p->module, t_int, pos.line); + args[3] = lb_const_int(p->module, t_int, pos.column); + + args[4] = any_id; + args[5] = id; + lb_emit_runtime_call(p, "type_assertion_check", args); + + return lb_emit_conv(p, data_ptr, tv.type); + } else { + GB_PANIC("TODO(bill): type assertion %s", type_to_string(type)); + } + } + + return lb_build_addr_ptr(p, ue->expr); + } + default: + { + lbValue v = lb_build_expr(p, ue->expr); + return lb_emit_unary_arith(p, ue->op.kind, v, tv.type); + } + } + case_end; + + case_ast_node(be, BinaryExpr, expr); + return lb_build_binary_expr(p, expr); + case_end; + + case_ast_node(pl, ProcLit, expr); + return lb_generate_anonymous_proc_lit(p->module, p->name, expr, p); + case_end; + + case_ast_node(cl, CompoundLit, expr); + return lb_addr_load(p, lb_build_addr(p, expr)); + case_end; + + case_ast_node(ce, CallExpr, expr); + return lb_build_call_expr(p, expr); + case_end; + + case_ast_node(se, SliceExpr, expr); + return lb_addr_load(p, lb_build_addr(p, expr)); + case_end; + + case_ast_node(ie, IndexExpr, expr); + return lb_addr_load(p, lb_build_addr(p, expr)); + case_end; + } + + GB_PANIC("lb_build_expr: %.*s", LIT(ast_strings[expr->kind])); + + return {}; +} + +lbValue lb_get_using_variable(lbProcedure *p, Entity *e) { + GB_ASSERT(e->kind == Entity_Variable && e->flags & EntityFlag_Using); + String name = e->token.string; + Entity *parent = e->using_parent; + Selection sel = lookup_field(parent->type, name, false); + GB_ASSERT(sel.entity != nullptr); + lbValue *pv = map_get(&p->module->values, hash_entity(parent)); + lbValue v = {}; + if (pv != nullptr) { + v = *pv; + } else { + GB_ASSERT_MSG(e->using_expr != nullptr, "%.*s", LIT(name)); + v = lb_build_addr_ptr(p, e->using_expr); + } + GB_ASSERT(v.value != nullptr); + GB_ASSERT(parent->type == type_deref(v.type)); + return lb_emit_deep_field_gep(p, v, sel); +} + + +lbAddr lb_build_addr_from_entity(lbProcedure *p, Entity *e, Ast *expr) { + GB_ASSERT(e != nullptr); + if (e->kind == Entity_Constant) { + Type *t = default_type(type_of_expr(expr)); + lbValue v = lb_const_value(p->module, t, e->Constant.value); + lbAddr g = lb_add_global_generated(p->module, t, v); + return g; + } + + + lbValue v = {}; + lbValue *found = map_get(&p->module->values, hash_entity(e)); + if (found) { + v = *found; + } else if (e->kind == Entity_Variable && e->flags & EntityFlag_Using) { + // NOTE(bill): Calculate the using variable every time + v = lb_get_using_variable(p, e); + } + + if (v.value == nullptr) { + error(expr, "%.*s Unknown value: %.*s, entity: %p %.*s", + LIT(p->name), + LIT(e->token.string), e, LIT(entity_strings[e->kind])); + GB_PANIC("Unknown value"); + } + + return lb_addr(v); +} + +lbValue lb_gen_map_header(lbProcedure *p, lbValue map_val_ptr, Type *map_type) { + GB_ASSERT_MSG(is_type_pointer(map_val_ptr.type), "%s", type_to_string(map_val_ptr.type)); + gbAllocator a = heap_allocator(); + lbAddr h = lb_add_local_generated(p, t_map_header, false); // all the values will be initialzed later + map_type = base_type(map_type); + GB_ASSERT(map_type->kind == Type_Map); + + Type *key_type = map_type->Map.key; + Type *val_type = map_type->Map.value; + + // NOTE(bill): Removes unnecessary allocation if split gep + lbValue gep0 = lb_emit_struct_ep(p, h.addr, 0); + lbValue m = lb_emit_conv(p, map_val_ptr, type_deref(gep0.type)); + lb_emit_store(p, gep0, m); + + lb_emit_store(p, lb_emit_struct_ep(p, h.addr, 1), lb_const_bool(p->module, t_bool, is_type_string(key_type))); + + i64 entry_size = type_size_of (map_type->Map.entry_type); + i64 entry_align = type_align_of (map_type->Map.entry_type); + i64 value_offset = type_offset_of(map_type->Map.entry_type, 2); + i64 value_size = type_size_of (map_type->Map.value); + + lb_emit_store(p, lb_emit_struct_ep(p, h.addr, 2), lb_const_int(p->module, t_int, entry_size)); + lb_emit_store(p, lb_emit_struct_ep(p, h.addr, 3), lb_const_int(p->module, t_int, entry_align)); + lb_emit_store(p, lb_emit_struct_ep(p, h.addr, 4), lb_const_int(p->module, t_uintptr, value_offset)); + lb_emit_store(p, lb_emit_struct_ep(p, h.addr, 5), lb_const_int(p->module, t_int, value_size)); + + return lb_addr_load(p, h); +} + +lbValue lb_gen_map_key(lbProcedure *p, lbValue key, Type *key_type) { + Type *hash_type = t_u64; + lbAddr v = lb_add_local_generated(p, t_map_key, true); + Type *t = base_type(key.type); + key = lb_emit_conv(p, key, key_type); + if (is_type_integer(t)) { + lb_emit_store(p, lb_emit_struct_ep(p, v.addr, 0), lb_emit_conv(p, key, hash_type)); + } else if (is_type_enum(t)) { + lb_emit_store(p, lb_emit_struct_ep(p, v.addr, 0), lb_emit_conv(p, key, hash_type)); + } else if (is_type_typeid(t)) { + lbValue i = lb_emit_transmute(p, key, t_uint); + lb_emit_store(p, lb_emit_struct_ep(p, v.addr, 0), lb_emit_conv(p, i, hash_type)); + } else if (is_type_pointer(t)) { + lbValue ptr = lb_emit_conv(p, key, t_uintptr); + lb_emit_store(p, lb_emit_struct_ep(p, v.addr, 0), lb_emit_conv(p, ptr, hash_type)); + } else if (is_type_float(t)) { + lbValue bits = {}; + i64 size = type_size_of(t); + switch (8*size) { + case 32: bits = lb_emit_transmute(p, key, t_u32); break; + case 64: bits = lb_emit_transmute(p, key, t_u64); break; + default: GB_PANIC("Unhandled float size: %lld bits", size); break; + } + + lb_emit_store(p, lb_emit_struct_ep(p, v.addr, 0), lb_emit_conv(p, bits, hash_type)); + } else if (is_type_string(t)) { + lbValue str = lb_emit_conv(p, key, t_string); + lbValue hashed_str = {}; + + if (false && lb_is_const(str)) { + String value = lb_get_const_string(p->module, str); + u64 hs = fnv64a(value.text, value.len); + hashed_str = lb_const_value(p->module, t_u64, exact_value_u64(hs)); + } else { + auto args = array_make(heap_allocator(), 1); + args[0] = str; + hashed_str = lb_emit_runtime_call(p, "default_hash_string", args); + } + lb_emit_store(p, lb_emit_struct_ep(p, v.addr, 0), hashed_str); + lb_emit_store(p, lb_emit_struct_ep(p, v.addr, 1), str); + } else { + GB_PANIC("Unhandled map key type"); + } + + return lb_addr_load(p, v); +} + +void lb_insert_dynamic_map_key_and_value(lbProcedure *p, lbAddr addr, Type *map_type, + lbValue map_key, lbValue map_value) { + map_type = base_type(map_type); + GB_ASSERT(map_type->kind == Type_Map); + + lbValue h = lb_gen_map_header(p, addr.addr, map_type); + lbValue key = lb_gen_map_key(p, map_key, map_type->Map.key); + lbValue v = lb_emit_conv(p, map_value, map_type->Map.value); + + lbAddr value_addr = lb_add_local_generated(p, v.type, false); + lb_addr_store(p, value_addr, v); + + auto args = array_make(heap_allocator(), 4); + args[0] = h; + args[1] = key; + args[2] = lb_emit_conv(p, value_addr.addr, t_rawptr); + args[3] = lb_emit_source_code_location(p, nullptr); + lb_emit_runtime_call(p, "__dynamic_map_set", args); +} + + +lbAddr lb_build_addr(lbProcedure *p, Ast *expr) { + expr = unparen_expr(expr); + + switch (expr->kind) { + case_ast_node(i, Implicit, expr); + lbAddr v = {}; + switch (i->kind) { + case Token_context: + v = lb_find_or_generate_context_ptr(p); + break; + } + + GB_ASSERT(v.addr.value != nullptr); + return v; + case_end; + + case_ast_node(i, Ident, expr); + if (is_blank_ident(expr)) { + lbAddr val = {}; + return val; + } + String name = i->token.string; + Entity *e = entity_of_ident(expr); + return lb_build_addr_from_entity(p, e, expr); + case_end; + + case_ast_node(se, SelectorExpr, expr); + Ast *sel = unparen_expr(se->selector); + if (sel->kind == Ast_Ident) { + String selector = sel->Ident.token.string; + TypeAndValue tav = type_and_value_of_expr(se->expr); + + if (tav.mode == Addressing_Invalid) { + // NOTE(bill): Imports + Entity *imp = entity_of_ident(se->expr); + if (imp != nullptr) { + GB_ASSERT(imp->kind == Entity_ImportName); + } + return lb_build_addr(p, unparen_expr(se->selector)); + } + + + Type *type = base_type(tav.type); + if (tav.mode == Addressing_Type) { // Addressing_Type + Selection sel = lookup_field(type, selector, true); + Entity *e = sel.entity; + GB_ASSERT(e->kind == Entity_Variable); + GB_ASSERT(e->flags & EntityFlag_TypeField); + String name = e->token.string; + /*if (name == "names") { + lbValue ti_ptr = lb_type_info(m, type); + lbValue variant = lb_emit_struct_ep(p, ti_ptr, 2); + + lbValue names_ptr = nullptr; + + if (is_type_enum(type)) { + lbValue enum_info = lb_emit_conv(p, variant, t_type_info_enum_ptr); + names_ptr = lb_emit_struct_ep(p, enum_info, 1); + } else if (type->kind == Type_Struct) { + lbValue struct_info = lb_emit_conv(p, variant, t_type_info_struct_ptr); + names_ptr = lb_emit_struct_ep(p, struct_info, 1); + } + return ir_addr(names_ptr); + } else */{ + GB_PANIC("Unhandled TypeField %.*s", LIT(name)); + } + GB_PANIC("Unreachable"); + } + + Selection sel = lookup_field(type, selector, false); + GB_ASSERT(sel.entity != nullptr); + + + if (sel.entity->type->kind == Type_BitFieldValue) { + lbAddr addr = lb_build_addr(p, se->expr); + Type *bft = type_deref(lb_addr_type(addr)); + if (sel.index.count == 1) { + GB_ASSERT(is_type_bit_field(bft)); + i32 index = sel.index[0]; + return lb_addr_bit_field(lb_addr_get_ptr(p, addr), index); + } else { + Selection s = sel; + s.index.count--; + i32 index = s.index[s.index.count-1]; + lbValue a = lb_addr_get_ptr(p, addr); + a = lb_emit_deep_field_gep(p, a, s); + return lb_addr_bit_field(a, index); + } + } else { + lbAddr addr = lb_build_addr(p, se->expr); + if (addr.kind == lbAddr_Context) { + GB_ASSERT(sel.index.count > 0); + if (addr.ctx.sel.index.count >= 0) { + 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; + i32 first_index = sel.index[0]; + Selection sub_sel = sel; + sub_sel.index.data += 1; + sub_sel.index.count -= 1; + + lbValue arr = lb_emit_struct_ep(p, addr.addr, first_index); + + Type *t = base_type(type_deref(addr.addr.type)); + GB_ASSERT(is_type_soa_struct(t)); + + // TODO(bill): Bounds check + if (!lb_is_const(addr.soa.index) || t->Struct.soa_kind != StructSoa_Fixed) { + lbValue len = lb_soa_struct_len(p, addr.addr); + // lb_emit_bounds_check(p, ast_token(addr.soa.index_expr), addr.soa.index, len); + } + + lbValue item = {}; + + if (t->Struct.soa_kind == StructSoa_Fixed) { + item = lb_emit_array_ep(p, arr, index); + } else { + item = lb_emit_load(p, lb_emit_ptr_offset(p, arr, index)); + } + if (sub_sel.index.count > 0) { + item = lb_emit_deep_field_gep(p, item, sub_sel); + } + return lb_addr(item); + } + lbValue a = lb_addr_get_ptr(p, addr); + a = lb_emit_deep_field_gep(p, a, sel); + return lb_addr(a); + } + } else { + GB_PANIC("Unsupported selector expression"); + } + case_end; + + case_ast_node(ta, TypeAssertion, expr); + gbAllocator a = heap_allocator(); + TokenPos pos = ast_token(expr).pos; + lbValue e = lb_build_expr(p, ta->expr); + Type *t = type_deref(e.type); + if (is_type_union(t)) { + Type *type = type_of_expr(expr); + lbAddr v = lb_add_local_generated(p, type, false); + lb_addr_store(p, v, lb_emit_union_cast(p, lb_build_expr(p, ta->expr), type, pos)); + return v; + } else if (is_type_any(t)) { + Type *type = type_of_expr(expr); + return lb_emit_any_cast_addr(p, lb_build_expr(p, ta->expr), type, pos); + } else { + GB_PANIC("TODO(bill): type assertion %s", type_to_string(e.type)); + } + case_end; + + case_ast_node(ue, UnaryExpr, expr); + switch (ue->op.kind) { + case Token_And: { + return lb_build_addr(p, ue->expr); + } + default: + GB_PANIC("Invalid unary expression for lb_build_addr"); + } + case_end; + case_ast_node(be, BinaryExpr, expr); + lbValue v = lb_build_expr(p, expr); + Type *t = v.type; + if (is_type_pointer(t)) { + return lb_addr(v); + } + return lb_addr(lb_address_from_load_or_generate_local(p, v)); + case_end; + + case_ast_node(ie, IndexExpr, expr); + Type *t = base_type(type_of_expr(ie->expr)); + gbAllocator a = heap_allocator(); + + bool deref = is_type_pointer(t); + t = base_type(type_deref(t)); + if (is_type_soa_struct(t)) { + // SOA STRUCTURES!!!! + lbValue val = lb_build_addr_ptr(p, ie->expr); + if (deref) { + val = lb_emit_load(p, val); + } + + lbValue index = lb_build_expr(p, ie->index); + return lb_addr_soa_variable(val, index, ie->index); + } + + if (ie->expr->tav.mode == Addressing_SoaVariable) { + // SOA Structures for slices/dynamic arrays + GB_ASSERT(is_type_pointer(type_of_expr(ie->expr))); + + lbValue field = lb_build_expr(p, ie->expr); + lbValue index = lb_build_expr(p, ie->index); + + + if (!build_context.no_bounds_check) { + // // TODO HACK(bill): Clean up this hack to get the length for bounds checking + // GB_ASSERT(LLVMIsALoadInst(field.value)); + + // lbValue a = {}; + // a.value = LLVMGetOperand(field.value, 0); + // a.type = alloc_type_pointer(field.type); + + // irInstr *b = &a->Instr; + // GB_ASSERT(b->kind == irInstr_StructElementPtr); + // lbValue base_struct = b->StructElementPtr.address; + + // GB_ASSERT(is_type_soa_struct(type_deref(ir_type(base_struct)))); + // lbValue len = ir_soa_struct_len(p, base_struct); + // ir_emit_bounds_check(p, ast_token(ie->index), index, len); + } + + lbValue val = lb_emit_ptr_offset(p, field, index); + return lb_addr(val); + } + + GB_ASSERT_MSG(is_type_indexable(t), "%s %s", type_to_string(t), expr_to_string(expr)); + + if (is_type_map(t)) { + lbValue map_val = lb_build_addr_ptr(p, ie->expr); + if (deref) { + map_val = lb_emit_load(p, map_val); + } + + lbValue key = lb_build_expr(p, ie->index); + key = lb_emit_conv(p, key, t->Map.key); + + Type *result_type = type_of_expr(expr); + return lb_addr_map(map_val, key, t, result_type); + } + + lbValue using_addr = {}; + + switch (t->kind) { + case Type_Array: { + lbValue array = {}; + if (using_addr.value != nullptr) { + array = using_addr; + } else { + array = lb_build_addr_ptr(p, ie->expr); + if (deref) { + array = lb_emit_load(p, array); + } + } + lbValue index = lb_build_expr(p, ie->index); + index = lb_emit_conv(p, index, t_int); + lbValue elem = lb_emit_array_ep(p, array, index); + + auto index_tv = type_and_value_of_expr(ie->index); + if (index_tv.mode != Addressing_Constant) { + // lbValue len = lb_const_int(p->module, t_int, t->Array.count); + // ir_emit_bounds_check(p, ast_token(ie->index), index, len); + } + return lb_addr(elem); + } + + case Type_EnumeratedArray: { + lbValue array = {}; + if (using_addr.value != nullptr) { + array = using_addr; + } else { + array = lb_build_addr_ptr(p, ie->expr); + if (deref) { + array = lb_emit_load(p, array); + } + } + + Type *index_type = t->EnumeratedArray.index; + + auto index_tv = type_and_value_of_expr(ie->index); + + lbValue index = {}; + if (compare_exact_values(Token_NotEq, t->EnumeratedArray.min_value, exact_value_i64(0))) { + if (index_tv.mode == Addressing_Constant) { + ExactValue idx = exact_value_sub(index_tv.value, t->EnumeratedArray.min_value); + index = lb_const_value(p->module, index_type, idx); + } else { + index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int); + index = lb_emit_arith(p, Token_Sub, index, lb_const_value(p->module, index_type, t->EnumeratedArray.min_value), index_type); + } + } else { + index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int); + } + + lbValue elem = lb_emit_array_ep(p, array, index); + + if (index_tv.mode != Addressing_Constant) { + // lbValue len = ir_const_int(t->EnumeratedArray.count); + // ir_emit_bounds_check(p, ast_token(ie->index), index, len); + } + return lb_addr(elem); + } + + case Type_Slice: { + lbValue slice = {}; + if (using_addr.value != nullptr) { + slice = lb_emit_load(p, using_addr); + } else { + slice = lb_build_expr(p, ie->expr); + if (deref) { + slice = lb_emit_load(p, slice); + } + } + lbValue elem = lb_slice_elem(p, slice); + lbValue index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int); + lbValue len = lb_slice_len(p, slice); + // ir_emit_bounds_check(p, ast_token(ie->index), index, len); + lbValue v = lb_emit_ptr_offset(p, elem, index); + return lb_addr(v); + } + + case Type_DynamicArray: { + lbValue dynamic_array = {}; + if (using_addr.value != nullptr) { + dynamic_array = lb_emit_load(p, using_addr); + } else { + dynamic_array = lb_build_expr(p, ie->expr); + if (deref) { + dynamic_array = lb_emit_load(p, dynamic_array); + } + } + lbValue elem = lb_dynamic_array_elem(p, dynamic_array); + lbValue len = lb_dynamic_array_len(p, dynamic_array); + lbValue index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int); + // lb_emit_bounds_check(p, ast_token(ie->index), index, len); + lbValue v = lb_emit_ptr_offset(p, elem, index); + return lb_addr(v); + } + + + case Type_Basic: { // Basic_string + lbValue str; + lbValue elem; + lbValue len; + lbValue index; + + if (using_addr.value != nullptr) { + str = lb_emit_load(p, using_addr); + } else { + str = lb_build_expr(p, ie->expr); + if (deref) { + str = lb_emit_load(p, str); + } + } + elem = lb_string_elem(p, str); + len = lb_string_len(p, str); + + index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int); + // lb_emit_bounds_check(p, ast_token(ie->index), index, len); + + return lb_addr(lb_emit_ptr_offset(p, elem, index)); + } + } + case_end; + + case_ast_node(se, SliceExpr, expr); + gbAllocator a = heap_allocator(); + lbValue low = lb_const_int(p->module, t_int, 0); + lbValue high = {}; + + if (se->low != nullptr) low = lb_build_expr(p, se->low); + if (se->high != nullptr) high = lb_build_expr(p, se->high); + + bool no_indices = se->low == nullptr && se->high == nullptr; + + lbValue addr = lb_build_addr_ptr(p, se->expr); + lbValue base = lb_emit_load(p, addr); + Type *type = base_type(base.type); + + if (is_type_pointer(type)) { + type = base_type(type_deref(type)); + addr = base; + base = lb_emit_load(p, base); + } + // TODO(bill): Cleanup like mad! + + switch (type->kind) { + case Type_Slice: { + Type *slice_type = type; + lbValue len = lb_slice_len(p, base); + if (high.value == nullptr) high = len; + + if (!no_indices) { + // ir_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr); + } + + lbValue elem = lb_emit_ptr_offset(p, lb_slice_elem(p, base), low); + lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); + + lbAddr slice = lb_add_local_generated(p, slice_type, false); + lb_fill_slice(p, slice, elem, new_len); + return slice; + } + + case Type_DynamicArray: { + Type *elem_type = type->DynamicArray.elem; + Type *slice_type = alloc_type_slice(elem_type); + + lbValue len = lb_dynamic_array_len(p, base); + if (high.value == nullptr) high = len; + + if (!no_indices) { + // lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr); + } + + lbValue elem = lb_emit_ptr_offset(p, lb_dynamic_array_elem(p, base), low); + lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); + + lbAddr slice = lb_add_local_generated(p, slice_type, false); + lb_fill_slice(p, slice, elem, new_len); + return slice; + } + + + case Type_Array: { + Type *slice_type = alloc_type_slice(type->Array.elem); + lbValue len = lb_const_int(p->module, t_int, type->Array.count); + + if (high.value == nullptr) high = len; + + bool low_const = type_and_value_of_expr(se->low).mode == Addressing_Constant; + bool high_const = type_and_value_of_expr(se->high).mode == Addressing_Constant; + + if (!low_const || !high_const) { + if (!no_indices) { + // lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr); + } + } + lbValue elem = lb_emit_ptr_offset(p, lb_array_elem(p, addr), low); + lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); + + lbAddr slice = lb_add_local_generated(p, slice_type, false); + lb_fill_slice(p, slice, elem, new_len); + return slice; + } + + case Type_Basic: { + GB_ASSERT(type == t_string); + lbValue len = lb_string_len(p, base); + if (high.value == nullptr) high = len; + + if (!no_indices) { + // lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr); + } + + lbValue elem = lb_emit_ptr_offset(p, lb_string_elem(p, base), low); + lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); + + lbAddr str = lb_add_local_generated(p, t_string, false); + lb_fill_string(p, str, elem, new_len); + return str; + } + + + case Type_Struct: + if (is_type_soa_struct(type)) { + lbValue len = lb_soa_struct_len(p, addr); + if (high.value == nullptr) high = len; + + if (!no_indices) { + // lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr); + } + #if 1 + + lbAddr dst = lb_add_local_generated(p, type_of_expr(expr), true); + if (type->Struct.soa_kind == StructSoa_Fixed) { + i32 field_count = cast(i32)type->Struct.fields.count; + for (i32 i = 0; i < field_count; i++) { + lbValue field_dst = lb_emit_struct_ep(p, dst.addr, i); + lbValue field_src = lb_emit_struct_ep(p, addr, i); + field_src = lb_emit_array_ep(p, field_src, low); + lb_emit_store(p, field_dst, field_src); + } + + lbValue len_dst = lb_emit_struct_ep(p, dst.addr, field_count); + lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); + lb_emit_store(p, len_dst, new_len); + } else if (type->Struct.soa_kind == StructSoa_Slice) { + if (no_indices) { + lb_addr_store(p, dst, base); + } else { + i32 field_count = cast(i32)type->Struct.fields.count - 1; + for (i32 i = 0; i < field_count; i++) { + lbValue field_dst = lb_emit_struct_ep(p, dst.addr, i); + lbValue field_src = lb_emit_struct_ev(p, base, i); + field_src = lb_emit_ptr_offset(p, field_src, low); + lb_emit_store(p, field_dst, field_src); + } + + + lbValue len_dst = lb_emit_struct_ep(p, dst.addr, field_count); + lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); + lb_emit_store(p, len_dst, new_len); + } + } else if (type->Struct.soa_kind == StructSoa_Dynamic) { + i32 field_count = cast(i32)type->Struct.fields.count - 3; + for (i32 i = 0; i < field_count; i++) { + lbValue field_dst = lb_emit_struct_ep(p, dst.addr, i); + lbValue field_src = lb_emit_struct_ev(p, base, i); + field_src = lb_emit_ptr_offset(p, field_src, low); + lb_emit_store(p, field_dst, field_src); + } + + + lbValue len_dst = lb_emit_struct_ep(p, dst.addr, field_count); + lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); + lb_emit_store(p, len_dst, new_len); + } + + return dst; + #endif + } + break; + + } + + GB_PANIC("Unknown slicable type"); + case_end; + + case_ast_node(de, DerefExpr, expr); + lbValue addr = lb_build_expr(p, de->expr); + return lb_addr(addr); + case_end; + + case_ast_node(ce, CallExpr, expr); + // NOTE(bill): This is make sure you never need to have an 'array_ev' + lbValue e = lb_build_expr(p, expr); + lbAddr v = lb_add_local_generated(p, e.type, false); + lb_addr_store(p, v, e); + return v; + case_end; + + case_ast_node(cl, CompoundLit, expr); + Type *type = type_of_expr(expr); + Type *bt = base_type(type); + + lbAddr v = lb_add_local_generated(p, type, true); + + Type *et = nullptr; + switch (bt->kind) { + case Type_Array: et = bt->Array.elem; break; + case Type_EnumeratedArray: et = bt->EnumeratedArray.elem; break; + case Type_Slice: et = bt->Slice.elem; break; + case Type_BitSet: et = bt->BitSet.elem; break; + case Type_SimdVector: et = bt->SimdVector.elem; break; + } + + String proc_name = {}; + if (p->entity) { + proc_name = p->entity->token.string; + } + TokenPos pos = ast_token(expr).pos; + + switch (bt->kind) { + default: GB_PANIC("Unknown CompoundLit type: %s", type_to_string(type)); break; + + case Type_Struct: { + + // TODO(bill): "constant" '#raw_union's are not initialized constantly at the moment. + // NOTE(bill): This is due to the layout of the unions when printed to LLVM-IR + bool is_raw_union = is_type_raw_union(bt); + GB_ASSERT(is_type_struct(bt) || is_raw_union); + TypeStruct *st = &bt->Struct; + if (cl->elems.count > 0) { + lb_addr_store(p, v, lb_const_value(p->module, type, exact_value_compound(expr))); + for_array(field_index, cl->elems) { + Ast *elem = cl->elems[field_index]; + + lbValue field_expr = {}; + Entity *field = nullptr; + isize index = field_index; + + if (elem->kind == Ast_FieldValue) { + ast_node(fv, FieldValue, elem); + String name = fv->field->Ident.token.string; + Selection sel = lookup_field(bt, name, false); + index = sel.index[0]; + elem = fv->value; + TypeAndValue tav = type_and_value_of_expr(elem); + } else { + TypeAndValue tav = type_and_value_of_expr(elem); + Selection sel = lookup_field_from_index(bt, st->fields[field_index]->Variable.field_src_index); + index = sel.index[0]; + } + + field = st->fields[index]; + Type *ft = field->type; + if (!is_raw_union && !is_type_typeid(ft) && lb_is_elem_const(elem, ft)) { + continue; + } + + field_expr = lb_build_expr(p, elem); + + + Type *fet = field_expr.type; + GB_ASSERT(fet->kind != Type_Tuple); + + // HACK TODO(bill): THIS IS A MASSIVE HACK!!!! + if (is_type_union(ft) && !are_types_identical(fet, ft) && !is_type_untyped(fet)) { + GB_ASSERT_MSG(union_variant_index(ft, fet) > 0, "%s", type_to_string(fet)); + + lbValue gep = lb_emit_struct_ep(p, lb_addr_get_ptr(p, v), cast(i32)index); + lb_emit_store_union_variant(p, gep, field_expr, fet); + } else { + lbValue fv = lb_emit_conv(p, field_expr, ft); + lbValue gep = lb_emit_struct_ep(p, lb_addr_get_ptr(p, v), cast(i32)index); + lb_emit_store(p, gep, fv); + } + } + } + break; + } + + case Type_Map: { + if (cl->elems.count == 0) { + break; + } + gbAllocator a = heap_allocator(); + { + auto args = array_make(a, 3); + args[0] = lb_gen_map_header(p, v.addr, type); + args[1] = lb_const_int(p->module, t_int, 2*cl->elems.count); + args[2] = lb_emit_source_code_location(p, proc_name, pos); + lb_emit_runtime_call(p, "__dynamic_map_reserve", args); + } + for_array(field_index, cl->elems) { + Ast *elem = cl->elems[field_index]; + ast_node(fv, FieldValue, elem); + + lbValue key = lb_build_expr(p, fv->field); + lbValue value = lb_build_expr(p, fv->value); + lb_insert_dynamic_map_key_and_value(p, v, type, key, value); + } + break; + } + + case Type_Array: { + if (cl->elems.count > 0) { + lb_addr_store(p, v, lb_const_value(p->module, type, exact_value_compound(expr))); + + auto temp_data = array_make(heap_allocator(), 0, cl->elems.count); + defer (array_free(&temp_data)); + + // NOTE(bill): Separate value, gep, store into their own chunks + for_array(i, cl->elems) { + Ast *elem = cl->elems[i]; + if (elem->kind == Ast_FieldValue) { + ast_node(fv, FieldValue, elem); + if (lb_is_elem_const(fv->value, et)) { + continue; + } + if (is_ast_range(fv->field)) { + ast_node(ie, BinaryExpr, fv->field); + TypeAndValue lo_tav = ie->left->tav; + TypeAndValue hi_tav = ie->right->tav; + GB_ASSERT(lo_tav.mode == Addressing_Constant); + GB_ASSERT(hi_tav.mode == Addressing_Constant); + + TokenKind op = ie->op.kind; + i64 lo = exact_value_to_i64(lo_tav.value); + i64 hi = exact_value_to_i64(hi_tav.value); + if (op == Token_Ellipsis) { + hi += 1; + } + + lbValue value = lb_build_expr(p, fv->value); + + for (i64 k = lo; k < hi; k++) { + lbCompoundLitElemTempData data = {}; + data.value = value; + data.elem_index = cast(i32)k; + array_add(&temp_data, data); + } + + } else { + auto tav = fv->field->tav; + GB_ASSERT(tav.mode == Addressing_Constant); + i64 index = exact_value_to_i64(tav.value); + + lbValue value = lb_build_expr(p, fv->value); + lbCompoundLitElemTempData data = {}; + data.value = lb_emit_conv(p, value, et); + data.expr = fv->value; + data.elem_index = cast(i32)index; + array_add(&temp_data, data); + } + + } else { + if (lb_is_elem_const(elem, et)) { + continue; + } + lbCompoundLitElemTempData data = {}; + data.expr = elem; + data.elem_index = cast(i32)i; + array_add(&temp_data, data); + } + } + + for_array(i, temp_data) { + temp_data[i].gep = lb_emit_array_epi(p, lb_addr_get_ptr(p, v), temp_data[i].elem_index); + } + + for_array(i, temp_data) { + auto return_ptr_hint_ast = p->return_ptr_hint_ast; + auto return_ptr_hint_value = p->return_ptr_hint_value; + auto return_ptr_hint_used = p->return_ptr_hint_used; + defer (p->return_ptr_hint_ast = return_ptr_hint_ast); + defer (p->return_ptr_hint_value = return_ptr_hint_value); + defer (p->return_ptr_hint_used = return_ptr_hint_used); + + lbValue field_expr = temp_data[i].value; + Ast *expr = temp_data[i].expr; + + p->return_ptr_hint_value = temp_data[i].gep; + p->return_ptr_hint_ast = unparen_expr(expr); + + if (field_expr.value == nullptr) { + field_expr = lb_build_expr(p, expr); + } + Type *t = field_expr.type; + GB_ASSERT(t->kind != Type_Tuple); + lbValue ev = lb_emit_conv(p, field_expr, et); + + if (!p->return_ptr_hint_used) { + temp_data[i].value = ev; + } + } + + for_array(i, temp_data) { + if (temp_data[i].value.value != nullptr) { + lb_emit_store(p, temp_data[i].gep, temp_data[i].value); + } + } + } + break; + } + case Type_EnumeratedArray: { + if (cl->elems.count > 0) { + lb_addr_store(p, v, lb_const_value(p->module, type, exact_value_compound(expr))); + + auto temp_data = array_make(heap_allocator(), 0, cl->elems.count); + defer (array_free(&temp_data)); + + // NOTE(bill): Separate value, gep, store into their own chunks + for_array(i, cl->elems) { + Ast *elem = cl->elems[i]; + if (elem->kind == Ast_FieldValue) { + ast_node(fv, FieldValue, elem); + if (lb_is_elem_const(fv->value, et)) { + continue; + } + if (is_ast_range(fv->field)) { + ast_node(ie, BinaryExpr, fv->field); + TypeAndValue lo_tav = ie->left->tav; + TypeAndValue hi_tav = ie->right->tav; + GB_ASSERT(lo_tav.mode == Addressing_Constant); + GB_ASSERT(hi_tav.mode == Addressing_Constant); + + TokenKind op = ie->op.kind; + i64 lo = exact_value_to_i64(lo_tav.value); + i64 hi = exact_value_to_i64(hi_tav.value); + if (op == Token_Ellipsis) { + hi += 1; + } + + lbValue value = lb_build_expr(p, fv->value); + + for (i64 k = lo; k < hi; k++) { + lbCompoundLitElemTempData data = {}; + data.value = value; + data.elem_index = cast(i32)k; + array_add(&temp_data, data); + } + + } else { + auto tav = fv->field->tav; + GB_ASSERT(tav.mode == Addressing_Constant); + i64 index = exact_value_to_i64(tav.value); + + lbValue value = lb_build_expr(p, fv->value); + lbCompoundLitElemTempData data = {}; + data.value = lb_emit_conv(p, value, et); + data.expr = fv->value; + data.elem_index = cast(i32)index; + array_add(&temp_data, data); + } + + } else { + if (lb_is_elem_const(elem, et)) { + continue; + } + lbCompoundLitElemTempData data = {}; + data.expr = elem; + data.elem_index = cast(i32)i; + array_add(&temp_data, data); + } + } + + + i32 index_offset = cast(i32)exact_value_to_i64(bt->EnumeratedArray.min_value); + + for_array(i, temp_data) { + i32 index = temp_data[i].elem_index - index_offset; + temp_data[i].gep = lb_emit_array_epi(p, lb_addr_get_ptr(p, v), index); + } + + for_array(i, temp_data) { + auto return_ptr_hint_ast = p->return_ptr_hint_ast; + auto return_ptr_hint_value = p->return_ptr_hint_value; + auto return_ptr_hint_used = p->return_ptr_hint_used; + defer (p->return_ptr_hint_ast = return_ptr_hint_ast); + defer (p->return_ptr_hint_value = return_ptr_hint_value); + defer (p->return_ptr_hint_used = return_ptr_hint_used); + + lbValue field_expr = temp_data[i].value; + Ast *expr = temp_data[i].expr; + + p->return_ptr_hint_value = temp_data[i].gep; + p->return_ptr_hint_ast = unparen_expr(expr); + + if (field_expr.value == nullptr) { + field_expr = lb_build_expr(p, expr); + } + Type *t = field_expr.type; + GB_ASSERT(t->kind != Type_Tuple); + lbValue ev = lb_emit_conv(p, field_expr, et); + + if (!p->return_ptr_hint_used) { + temp_data[i].value = ev; + } + } + + for_array(i, temp_data) { + if (temp_data[i].value.value != nullptr) { + lb_emit_store(p, temp_data[i].gep, temp_data[i].value); + } + } + } + break; + } + case Type_Slice: { + if (cl->elems.count > 0) { + Type *elem_type = bt->Slice.elem; + Type *elem_ptr_type = alloc_type_pointer(elem_type); + Type *elem_ptr_ptr_type = alloc_type_pointer(elem_ptr_type); + lbValue slice = lb_const_value(p->module, type, exact_value_compound(expr)); + + lbValue data = lb_slice_elem(p, slice); + + auto temp_data = array_make(heap_allocator(), 0, cl->elems.count); + defer (array_free(&temp_data)); + + for_array(i, cl->elems) { + Ast *elem = cl->elems[i]; + if (elem->kind == Ast_FieldValue) { + ast_node(fv, FieldValue, elem); + + if (lb_is_elem_const(fv->value, et)) { + continue; + } + + if (is_ast_range(fv->field)) { + ast_node(ie, BinaryExpr, fv->field); + TypeAndValue lo_tav = ie->left->tav; + TypeAndValue hi_tav = ie->right->tav; + GB_ASSERT(lo_tav.mode == Addressing_Constant); + GB_ASSERT(hi_tav.mode == Addressing_Constant); + + TokenKind op = ie->op.kind; + i64 lo = exact_value_to_i64(lo_tav.value); + i64 hi = exact_value_to_i64(hi_tav.value); + if (op == Token_Ellipsis) { + hi += 1; + } + + lbValue value = lb_emit_conv(p, lb_build_expr(p, fv->value), et); + + for (i64 k = lo; k < hi; k++) { + lbCompoundLitElemTempData data = {}; + data.value = value; + data.elem_index = cast(i32)k; + array_add(&temp_data, data); + } + + } else { + GB_ASSERT(fv->field->tav.mode == Addressing_Constant); + i64 index = exact_value_to_i64(fv->field->tav.value); + + lbValue field_expr = lb_build_expr(p, fv->value); + GB_ASSERT(!is_type_tuple(field_expr.type)); + + lbValue ev = lb_emit_conv(p, field_expr, et); + + lbCompoundLitElemTempData data = {}; + data.value = ev; + data.elem_index = cast(i32)index; + array_add(&temp_data, data); + } + } else { + if (lb_is_elem_const(elem, et)) { + continue; + } + lbValue field_expr = lb_build_expr(p, elem); + GB_ASSERT(!is_type_tuple(field_expr.type)); + + lbValue ev = lb_emit_conv(p, field_expr, et); + + lbCompoundLitElemTempData data = {}; + data.value = ev; + data.elem_index = cast(i32)i; + array_add(&temp_data, data); + } + } + + for_array(i, temp_data) { + temp_data[i].gep = lb_emit_ptr_offset(p, data, lb_const_int(p->module, t_int, temp_data[i].elem_index)); + } + + for_array(i, temp_data) { + lb_emit_store(p, temp_data[i].gep, temp_data[i].value); + } + + { + GB_ASSERT(lb_is_const(slice)); + unsigned indices[1] = {1}; + + lbValue count = {}; + count.type = t_int; + count.value = LLVMConstExtractValue(slice.value, indices, gb_count_of(indices)); + lb_fill_slice(p, v, data, count); + } + } + break; + } + + case Type_DynamicArray: { + if (cl->elems.count == 0) { + break; + } + Type *et = bt->DynamicArray.elem; + gbAllocator a = heap_allocator(); + lbValue size = lb_const_int(p->module, t_int, type_size_of(et)); + lbValue align = lb_const_int(p->module, t_int, type_align_of(et)); + + i64 item_count = gb_max(cl->max_count, cl->elems.count); + { + + auto args = array_make(a, 5); + args[0] = lb_emit_conv(p, lb_addr_get_ptr(p, v), t_rawptr); + args[1] = size; + args[2] = align; + args[3] = lb_const_int(p->module, t_int, 2*item_count); // TODO(bill): Is this too much waste? + args[4] = lb_emit_source_code_location(p, proc_name, pos); + lb_emit_runtime_call(p, "__dynamic_array_reserve", args); + } + + lbValue items = lb_generate_array(p->module, et, item_count, str_lit("dacl$"), cast(i64)cast(intptr)expr); + + for_array(i, cl->elems) { + Ast *elem = cl->elems[i]; + if (elem->kind == Ast_FieldValue) { + ast_node(fv, FieldValue, elem); + if (is_ast_range(fv->field)) { + ast_node(ie, BinaryExpr, fv->field); + TypeAndValue lo_tav = ie->left->tav; + TypeAndValue hi_tav = ie->right->tav; + GB_ASSERT(lo_tav.mode == Addressing_Constant); + GB_ASSERT(hi_tav.mode == Addressing_Constant); + + TokenKind op = ie->op.kind; + i64 lo = exact_value_to_i64(lo_tav.value); + i64 hi = exact_value_to_i64(hi_tav.value); + if (op == Token_Ellipsis) { + hi += 1; + } + + lbValue value = lb_emit_conv(p, lb_build_expr(p, fv->value), et); + + for (i64 k = lo; k < hi; k++) { + lbValue ep = lb_emit_array_epi(p, items, cast(i32)k); + lb_emit_store(p, ep, value); + } + } else { + GB_ASSERT(fv->field->tav.mode == Addressing_Constant); + + i64 field_index = exact_value_to_i64(fv->field->tav.value); + + lbValue ev = lb_build_expr(p, fv->value); + lbValue value = lb_emit_conv(p, ev, et); + lbValue ep = lb_emit_array_epi(p, items, cast(i32)field_index); + lb_emit_store(p, ep, value); + } + } else { + lbValue value = lb_emit_conv(p, lb_build_expr(p, elem), et); + lbValue ep = lb_emit_array_epi(p, items, cast(i32)i); + lb_emit_store(p, ep, value); + } + } + + { + auto args = array_make(a, 6); + args[0] = lb_emit_conv(p, v.addr, t_rawptr); + args[1] = size; + args[2] = align; + args[3] = lb_emit_conv(p, items, t_rawptr); + args[4] = lb_const_int(p->module, t_int, item_count); + args[5] = lb_emit_source_code_location(p, proc_name, pos); + lb_emit_runtime_call(p, "__dynamic_array_append", args); + } + break; + } + + case Type_Basic: { + GB_ASSERT(is_type_any(bt)); + if (cl->elems.count > 0) { + lb_addr_store(p, v, lb_const_value(p->module, type, exact_value_compound(expr))); + String field_names[2] = { + str_lit("data"), + str_lit("id"), + }; + Type *field_types[2] = { + t_rawptr, + t_typeid, + }; + + for_array(field_index, cl->elems) { + Ast *elem = cl->elems[field_index]; + + lbValue field_expr = {}; + isize index = field_index; + + if (elem->kind == Ast_FieldValue) { + ast_node(fv, FieldValue, elem); + Selection sel = lookup_field(bt, fv->field->Ident.token.string, false); + index = sel.index[0]; + elem = fv->value; + } else { + TypeAndValue tav = type_and_value_of_expr(elem); + Selection sel = lookup_field(bt, field_names[field_index], false); + index = sel.index[0]; + } + + field_expr = lb_build_expr(p, elem); + + GB_ASSERT(field_expr.type->kind != Type_Tuple); + + Type *ft = field_types[index]; + lbValue fv = lb_emit_conv(p, field_expr, ft); + lbValue gep = lb_emit_struct_ep(p, lb_addr_get_ptr(p, v), cast(i32)index); + lb_emit_store(p, gep, fv); + } + } + + break; + } + + case Type_BitSet: { + i64 sz = type_size_of(type); + if (cl->elems.count > 0 && sz > 0) { + lb_addr_store(p, v, lb_const_value(p->module, type, exact_value_compound(expr))); + + lbValue lower = lb_const_value(p->module, t_int, exact_value_i64(bt->BitSet.lower)); + for_array(i, cl->elems) { + Ast *elem = cl->elems[i]; + GB_ASSERT(elem->kind != Ast_FieldValue); + + if (lb_is_elem_const(elem, et)) { + continue; + } + + lbValue expr = lb_build_expr(p, elem); + GB_ASSERT(expr.type->kind != Type_Tuple); + + Type *it = bit_set_to_int(bt); + lbValue one = lb_const_value(p->module, it, exact_value_i64(1)); + lbValue e = lb_emit_conv(p, expr, it); + e = lb_emit_arith(p, Token_Sub, e, lower, it); + e = lb_emit_arith(p, Token_Shl, one, e, it); + + lbValue old_value = lb_emit_transmute(p, lb_addr_load(p, v), it); + lbValue new_value = lb_emit_arith(p, Token_Or, old_value, e, it); + new_value = lb_emit_transmute(p, new_value, type); + lb_addr_store(p, v, new_value); + } + } + break; + } + + } + + return v; + case_end; + + case_ast_node(tc, TypeCast, expr); + Type *type = type_of_expr(expr); + lbValue x = lb_build_expr(p, tc->expr); + lbValue e = {}; + switch (tc->token.kind) { + case Token_cast: + e = lb_emit_conv(p, x, type); + break; + case Token_transmute: + e = lb_emit_transmute(p, x, type); + break; + default: + GB_PANIC("Invalid AST TypeCast"); + } + lbAddr v = lb_add_local_generated(p, type, false); + lb_addr_store(p, v, e); + return v; + case_end; + + case_ast_node(ac, AutoCast, expr); + return lb_build_addr(p, ac->expr); + case_end; + } + + TokenPos token_pos = ast_token(expr).pos; + GB_PANIC("Unexpected address expression\n" + "\tAst: %.*s @ " + "%.*s(%td:%td)\n", + LIT(ast_strings[expr->kind]), + LIT(token_pos.file), token_pos.line, token_pos.column); + + + return {}; +} + +void lb_init_module(lbModule *m, Checker *c) { + m->info = &c->info; + + m->ctx = LLVMGetGlobalContext(); + m->mod = LLVMModuleCreateWithNameInContext("odin_module", m->ctx); + m->debug_builder = LLVMCreateDIBuilder(m->mod); + + gb_mutex_init(&m->mutex); + gbAllocator a = heap_allocator(); + map_init(&m->types, a); + map_init(&m->values, a); + map_init(&m->members, a); + map_init(&m->procedure_values, a); + map_init(&m->procedures, a); + map_init(&m->const_strings, a); + map_init(&m->anonymous_proc_lits, a); + array_init(&m->procedures_to_generate, a); + array_init(&m->foreign_library_paths, a); + + map_init(&m->debug_values, a); + +} + + +bool lb_init_generator(lbGenerator *gen, Checker *c) { + if (global_error_collector.count != 0) { + return false; + } + + isize tc = c->parser->total_token_count; + if (tc < 2) { + return false; + } + + + String init_fullpath = c->parser->init_fullpath; + + if (build_context.out_filepath.len == 0) { + gen->output_name = remove_directory_from_path(init_fullpath); + gen->output_name = remove_extension_from_path(gen->output_name); + gen->output_base = gen->output_name; + } else { + gen->output_name = build_context.out_filepath; + isize pos = string_extension_position(gen->output_name); + if (pos < 0) { + gen->output_base = gen->output_name; + } else { + gen->output_base = substring(gen->output_name, 0, pos); + } + } + gbAllocator ha = heap_allocator(); + array_init(&gen->output_object_paths, ha); + + gen->output_base = path_to_full_path(ha, gen->output_base); + + gbString output_file_path = gb_string_make_length(ha, gen->output_base.text, gen->output_base.len); + output_file_path = gb_string_appendc(output_file_path, ".obj"); + defer (gb_string_free(output_file_path)); + + gen->info = &c->info; + + lb_init_module(&gen->module, c); + + + return true; +} + +lbAddr lb_add_global_generated(lbModule *m, Type *type, lbValue value) { + GB_ASSERT(type != nullptr); + type = default_type(type); + + isize max_len = 7+8+1; + u8 *str = cast(u8 *)gb_alloc_array(heap_allocator(), u8, max_len); + isize len = gb_snprintf(cast(char *)str, max_len, "ggv$%x", m->global_generated_index); + m->global_generated_index++; + String name = make_string(str, len-1); + + Scope *scope = nullptr; + Entity *e = alloc_entity_variable(scope, make_token_ident(name), type); + lbValue g = {}; + g.type = alloc_type_pointer(type); + g.value = LLVMAddGlobal(m->mod, lb_type(m, type), cast(char const *)str); + if (value.value != nullptr) { + GB_ASSERT(LLVMIsConstant(value.value)); + LLVMSetInitializer(g.value, value.value); + } else { + LLVMSetInitializer(g.value, LLVMConstNull(lb_type(m, type))); + } + + lb_add_entity(m, e, g); + lb_add_member(m, name, g); + return lb_addr(g); +} + +lbValue lb_find_runtime_value(lbModule *m, String const &name) { + AstPackage *p = m->info->runtime_package; + Entity *e = scope_lookup_current(p->scope, name); + lbValue *found = map_get(&m->values, hash_entity(e)); + GB_ASSERT_MSG(found != nullptr, "Unable to find runtime value '%.*s'", LIT(name)); + lbValue value = *found; + return value; +} + +lbValue lb_get_type_info_ptr(lbModule *m, Type *type) { + i32 index = cast(i32)lb_type_info_index(m->info, type); + GB_ASSERT(index >= 0); + // gb_printf_err("%d %s\n", index, type_to_string(type)); + + LLVMValueRef indices[2] = { + LLVMConstInt(lb_type(m, t_int), 0, false), + LLVMConstInt(lb_type(m, t_int), index, false), + }; + + lbValue res = {}; + res.type = t_type_info_ptr; + res.value = LLVMConstGEP(lb_global_type_info_data.addr.value, indices, cast(unsigned)gb_count_of(indices)); + return res; +} + + +lbValue lb_type_info_member_types_offset(lbProcedure *p, isize count) { + lbValue offset = lb_emit_array_epi(p, lb_global_type_info_member_types.addr, lb_global_type_info_member_types_index); + lb_global_type_info_member_types_index += cast(i32)count; + return offset; +} +lbValue lb_type_info_member_names_offset(lbProcedure *p, isize count) { + lbValue offset = lb_emit_array_epi(p, lb_global_type_info_member_names.addr, lb_global_type_info_member_names_index); + lb_global_type_info_member_names_index += cast(i32)count; + return offset; +} +lbValue lb_type_info_member_offsets_offset(lbProcedure *p, isize count) { + lbValue offset = lb_emit_array_epi(p, lb_global_type_info_member_offsets.addr, lb_global_type_info_member_offsets_index); + lb_global_type_info_member_offsets_index += cast(i32)count; + return offset; +} +lbValue lb_type_info_member_usings_offset(lbProcedure *p, isize count) { + lbValue offset = lb_emit_array_epi(p, lb_global_type_info_member_usings.addr, lb_global_type_info_member_usings_index); + lb_global_type_info_member_usings_index += cast(i32)count; + return offset; +} +lbValue lb_type_info_member_tags_offset(lbProcedure *p, isize count) { + lbValue offset = lb_emit_array_epi(p, lb_global_type_info_member_tags.addr, lb_global_type_info_member_tags_index); + lb_global_type_info_member_tags_index += cast(i32)count; + return offset; +} + + +lbValue lb_generate_array(lbModule *m, Type *elem_type, i64 count, String prefix, i64 id) { + gbAllocator a = heap_allocator(); + Token token = {Token_Ident}; + isize name_len = prefix.len + 1 + 20; + + auto suffix_id = cast(unsigned long long)id; + char *text = gb_alloc_array(a, char, name_len+1); + gb_snprintf(text, name_len, + "%.*s-%llu", LIT(prefix), suffix_id); + text[name_len] = 0; + + String s = make_string_c(text); + + Type *t = alloc_type_array(elem_type, count); + lbValue g = {}; + g.value = LLVMAddGlobal(m->mod, lb_type(m, t), text); + g.type = alloc_type_pointer(t); + LLVMSetInitializer(g.value, LLVMConstNull(lb_type(m, t))); + LLVMSetLinkage(g.value, LLVMInternalLinkage); + map_set(&m->members, hash_string(s), g); + return g; +} + + + +void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info data + lbModule *m = p->module; + LLVMContextRef ctx = m->ctx; + gbAllocator a = heap_allocator(); + CheckerInfo *info = m->info; + + { + // NOTE(bill): Set the type_table slice with the global backing array + lbValue global_type_table = lb_find_runtime_value(m, str_lit("type_table")); + Type *type = base_type(lb_addr_type(lb_global_type_info_data)); + GB_ASSERT(is_type_array(type)); + + LLVMValueRef indices[2] = {llvm_zero32(m), llvm_zero32(m)}; + LLVMValueRef values[2] = { + LLVMConstInBoundsGEP(lb_global_type_info_data.addr.value, indices, gb_count_of(indices)), + LLVMConstInt(lb_type(m, t_int), type->Array.count, true), + }; + LLVMValueRef slice = LLVMConstStructInContext(ctx, values, gb_count_of(values), false); + + LLVMSetInitializer(global_type_table.value, slice); + } + + + // Useful types + Type *t_i64_slice_ptr = alloc_type_pointer(alloc_type_slice(t_i64)); + Type *t_string_slice_ptr = alloc_type_pointer(alloc_type_slice(t_string)); + + i32 type_info_member_types_index = 0; + i32 type_info_member_names_index = 0; + i32 type_info_member_offsets_index = 0; + + for_array(type_info_type_index, info->type_info_types) { + Type *t = info->type_info_types[type_info_type_index]; + t = default_type(t); + if (t == t_invalid) { + continue; + } + + isize entry_index = lb_type_info_index(info, t, false); + if (entry_index <= 0) { + continue; + } + + lbValue tag = {}; + lbValue ti_ptr = lb_emit_array_epi(p, lb_global_type_info_data.addr, cast(i32)entry_index); + lbValue variant_ptr = lb_emit_struct_ep(p, ti_ptr, 3); + + lb_emit_store(p, lb_emit_struct_ep(p, ti_ptr, 0), lb_const_int(m, t_int, type_size_of(t))); + lb_emit_store(p, lb_emit_struct_ep(p, ti_ptr, 1), lb_const_int(m, t_int, type_align_of(t))); + lb_emit_store(p, lb_emit_struct_ep(p, ti_ptr, 2), lb_typeid(m, t)); + + + switch (t->kind) { + case Type_Named: { + tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_named_ptr); + LLVMValueRef vals[2] = { + lb_const_string(p->module, t->Named.type_name->token.string).value, + lb_get_type_info_ptr(m, t->Named.base).value, + }; + + lbValue res = {}; + res.type = type_deref(tag.type); + res.value = LLVMConstNamedStruct(lb_type(m, res.type), vals, gb_count_of(vals)); + lb_emit_store(p, tag, res); + break; + } + + case Type_Basic: + switch (t->Basic.kind) { + case Basic_bool: + case Basic_b8: + case Basic_b16: + case Basic_b32: + case Basic_b64: + tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_boolean_ptr); + break; + + case Basic_i8: + case Basic_u8: + case Basic_i16: + case Basic_u16: + case Basic_i32: + case Basic_u32: + case Basic_i64: + case Basic_u64: + case Basic_i128: + case Basic_u128: + + case Basic_i16le: + case Basic_u16le: + case Basic_i32le: + case Basic_u32le: + case Basic_i64le: + case Basic_u64le: + case Basic_i128le: + case Basic_u128le: + case Basic_i16be: + case Basic_u16be: + case Basic_i32be: + case Basic_u32be: + case Basic_i64be: + case Basic_u64be: + case Basic_i128be: + case Basic_u128be: + + case Basic_int: + case Basic_uint: + case Basic_uintptr: { + tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_integer_ptr); + + lbValue is_signed = lb_const_bool(m, t_bool, (t->Basic.flags & BasicFlag_Unsigned) == 0); + // NOTE(bill): This is matches the runtime layout + u8 endianness_value = 0; + if (t->Basic.flags & BasicFlag_EndianLittle) { + endianness_value = 1; + } else if (t->Basic.flags & BasicFlag_EndianBig) { + endianness_value = 2; + } + lbValue endianness = lb_const_int(m, t_u8, endianness_value); + + LLVMValueRef vals[2] = { + is_signed.value, + endianness.value, + }; + + lbValue res = {}; + res.type = type_deref(tag.type); + res.value = LLVMConstNamedStruct(lb_type(m, res.type), vals, gb_count_of(vals)); + lb_emit_store(p, tag, res); + break; + } + + case Basic_rune: + tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_rune_ptr); + break; + + // case Basic_f16: + case Basic_f32: + case Basic_f64: + tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_float_ptr); + break; + + // case Basic_complex32: + case Basic_complex64: + case Basic_complex128: + tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_complex_ptr); + break; + + case Basic_quaternion128: + case Basic_quaternion256: + tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_quaternion_ptr); + break; + + case Basic_rawptr: + tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_pointer_ptr); + break; + + case Basic_string: + tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_string_ptr); + break; + + case Basic_cstring: + { + tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_string_ptr); + LLVMValueRef vals[1] = { + lb_const_bool(m, t_bool, true).value, + }; + + lbValue res = {}; + res.type = type_deref(tag.type); + res.value = LLVMConstNamedStruct(lb_type(m, res.type), vals, gb_count_of(vals)); + lb_emit_store(p, tag, res); + } + break; + + case Basic_any: + tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_any_ptr); + break; + + case Basic_typeid: + tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_typeid_ptr); + break; + } + break; + + case Type_Pointer: { + tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_pointer_ptr); + lbValue gep = lb_get_type_info_ptr(m, t->Pointer.elem); + + LLVMValueRef vals[1] = { + gep.value, + }; + + lbValue res = {}; + res.type = type_deref(tag.type); + res.value = LLVMConstNamedStruct(lb_type(m, res.type), vals, gb_count_of(vals)); + lb_emit_store(p, tag, res); + break; + } + case Type_Array: { + tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_array_ptr); + i64 ez = type_size_of(t->Array.elem); + + LLVMValueRef vals[3] = { + lb_get_type_info_ptr(m, t->Array.elem).value, + lb_const_int(m, t_int, ez).value, + lb_const_int(m, t_int, t->Array.count).value, + }; + + lbValue res = {}; + res.type = type_deref(tag.type); + res.value = LLVMConstNamedStruct(lb_type(m, res.type), vals, gb_count_of(vals)); + lb_emit_store(p, tag, res); + break; + } + case Type_EnumeratedArray: { + tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_enumerated_array_ptr); + + LLVMValueRef vals[6] = { + lb_get_type_info_ptr(m, t->EnumeratedArray.elem).value, + lb_get_type_info_ptr(m, t->EnumeratedArray.index).value, + lb_const_int(m, t_int, type_size_of(t->EnumeratedArray.elem)).value, + lb_const_int(m, t_int, t->EnumeratedArray.count).value, + + // Unions + LLVMConstNull(lb_type(m, t_type_info_enum_value)), + LLVMConstNull(lb_type(m, t_type_info_enum_value)), + }; + + lbValue res = {}; + res.type = type_deref(tag.type); + res.value = LLVMConstNamedStruct(lb_type(m, res.type), vals, gb_count_of(vals)); + lb_emit_store(p, tag, res); + + // NOTE(bill): Union assignment + lbValue min_value = lb_emit_struct_ep(p, tag, 4); + lbValue max_value = lb_emit_struct_ep(p, tag, 5); + + lbValue min_v = lb_const_value(m, core_type(t->EnumeratedArray.index), t->EnumeratedArray.min_value); + lbValue max_v = lb_const_value(m, core_type(t->EnumeratedArray.index), t->EnumeratedArray.max_value); + + lb_emit_store_union_variant(p, min_value, min_v, min_v.type); + lb_emit_store_union_variant(p, max_value, max_v, max_v.type); + break; + } + case Type_DynamicArray: { + tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_dynamic_array_ptr); + + LLVMValueRef vals[2] = { + lb_get_type_info_ptr(m, t->DynamicArray.elem).value, + lb_const_int(m, t_int, type_size_of(t->DynamicArray.elem)).value, + }; + + lbValue res = {}; + res.type = type_deref(tag.type); + res.value = LLVMConstNamedStruct(lb_type(m, res.type), vals, gb_count_of(vals)); + lb_emit_store(p, tag, res); + break; + } + case Type_Slice: { + tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_slice_ptr); + + LLVMValueRef vals[2] = { + lb_get_type_info_ptr(m, t->Slice.elem).value, + lb_const_int(m, t_int, type_size_of(t->Slice.elem)).value, + }; + + lbValue res = {}; + res.type = type_deref(tag.type); + res.value = LLVMConstNamedStruct(lb_type(m, res.type), vals, gb_count_of(vals)); + lb_emit_store(p, tag, res); + break; + } + case Type_Proc: { + tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_procedure_ptr); + + LLVMValueRef params = LLVMConstNull(lb_type(m, t_type_info_ptr)); + LLVMValueRef results = LLVMConstNull(lb_type(m, t_type_info_ptr)); + if (t->Proc.params != nullptr) { + params = lb_get_type_info_ptr(m, t->Proc.params).value; + } + if (t->Proc.results != nullptr) { + results = lb_get_type_info_ptr(m, t->Proc.results).value; + } + + LLVMValueRef vals[4] = { + params, + results, + lb_const_bool(m, t_bool, t->Proc.variadic).value, + lb_const_int(m, t_u8, t->Proc.calling_convention).value, + }; + + lbValue res = {}; + res.type = type_deref(tag.type); + res.value = LLVMConstNamedStruct(lb_type(m, res.type), vals, gb_count_of(vals)); + lb_emit_store(p, tag, res); + break; + } + case Type_Tuple: { + tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_tuple_ptr); + + + lbValue memory_types = lb_type_info_member_types_offset(p, t->Tuple.variables.count); + lbValue memory_names = lb_type_info_member_names_offset(p, t->Tuple.variables.count); + + + for_array(i, t->Tuple.variables) { + // NOTE(bill): offset is not used for tuples + Entity *f = t->Tuple.variables[i]; + + lbValue index = lb_const_int(m, t_int, i); + lbValue type_info = lb_emit_ptr_offset(p, memory_types, index); + + // TODO(bill): Make this constant if possible, 'lb_const_store' does not work + lb_emit_store(p, type_info, lb_type_info(m, f->type)); + if (f->token.string.len > 0) { + lbValue name = lb_emit_ptr_offset(p, memory_names, index); + lb_emit_store(p, name, lb_const_string(m, f->token.string)); + } + } + + lbValue count = lb_const_int(m, t_int, t->Tuple.variables.count); + + LLVMValueRef types_slice = llvm_const_slice(memory_types, count); + LLVMValueRef names_slice = llvm_const_slice(memory_names, count); + + LLVMValueRef vals[2] = { + types_slice, + names_slice, + }; + + lbValue res = {}; + res.type = type_deref(tag.type); + res.value = LLVMConstNamedStruct(lb_type(m, res.type), vals, gb_count_of(vals)); + lb_emit_store(p, tag, res); + + break; + } + + case Type_Enum: + tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_enum_ptr); + + { + GB_ASSERT(t->Enum.base_type != nullptr); + GB_ASSERT(type_size_of(t_type_info_enum_value) == 16); + + + LLVMValueRef vals[3] = {}; + vals[0] = lb_type_info(m, t->Enum.base_type).value; + if (t->Enum.fields.count > 0) { + auto fields = t->Enum.fields; + lbValue name_array = lb_generate_array(m, t_string, fields.count, + str_lit("$enum_names"), cast(i64)entry_index); + lbValue value_array = lb_generate_array(m, t_type_info_enum_value, fields.count, + str_lit("$enum_values"), cast(i64)entry_index); + + + LLVMValueRef *name_values = gb_alloc_array(heap_allocator(), LLVMValueRef, fields.count); + LLVMValueRef *value_values = gb_alloc_array(heap_allocator(), LLVMValueRef, fields.count); + defer (gb_free(heap_allocator(), name_values)); + defer (gb_free(heap_allocator(), value_values)); + + GB_ASSERT(is_type_integer(t->Enum.base_type)); + + LLVMTypeRef align_type = lb_alignment_prefix_type_hack(m, type_align_of(t)); + LLVMTypeRef array_type = LLVMArrayType(lb_type(m, t_u8), 8); + LLVMTypeRef u64_type = lb_type(m, t_u64); + + for_array(i, fields) { + ExactValue value = fields[i]->Constant.value; + lbValue v = lb_const_value(m, t->Enum.base_type, value); + LLVMValueRef zv = LLVMConstZExt(v.value, u64_type); + lbValue tag = lb_const_union_tag(m, t_type_info_enum_value, v.type); + + LLVMValueRef vals[3] = { + LLVMConstNull(align_type), + zv, + tag.value, + }; + + name_values[i] = lb_const_string(m, fields[i]->token.string).value; + value_values[i] = LLVMConstStruct(vals, gb_count_of(vals), false); + } + + LLVMValueRef name_init = LLVMConstArray(lb_type(m, t_string), name_values, cast(unsigned)fields.count); + LLVMValueRef value_init = LLVMConstArray(lb_type(m, t_type_info_enum_value), value_values, cast(unsigned)fields.count); + LLVMSetInitializer(name_array.value, name_init); + LLVMSetInitializer(value_array.value, value_init); + + lbValue v_count = lb_const_int(m, t_int, fields.count); + + vals[1] = llvm_const_slice(lb_array_elem(p, name_array), v_count); + vals[2] = llvm_const_slice(lb_array_elem(p, value_array), v_count); + } else { + vals[1] = LLVMConstNull(lb_type(m, base_type(t_type_info_enum)->Struct.fields[1]->type)); + vals[2] = LLVMConstNull(lb_type(m, base_type(t_type_info_enum)->Struct.fields[2]->type)); + } + + + lbValue res = {}; + res.type = type_deref(tag.type); + res.value = LLVMConstNamedStruct(lb_type(m, res.type), vals, gb_count_of(vals)); + lb_emit_store(p, tag, res); + } + break; + + case Type_Union: { + tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_union_ptr); + + { + LLVMValueRef vals[6] = {}; + + isize variant_count = gb_max(0, t->Union.variants.count); + lbValue memory_types = lb_type_info_member_types_offset(p, variant_count); + + // NOTE(bill): Zeroth is nil so ignore it + for (isize variant_index = 0; variant_index < variant_count; variant_index++) { + Type *vt = t->Union.variants[variant_index]; + lbValue tip = lb_get_type_info_ptr(m, vt); + + lbValue index = lb_const_int(m, t_int, variant_index); + lbValue type_info = lb_emit_ptr_offset(p, memory_types, index); + lb_emit_store(p, type_info, lb_type_info(m, vt)); + } + + lbValue count = lb_const_int(m, t_int, variant_count); + vals[0] = llvm_const_slice(memory_types, count); + + i64 tag_size = union_tag_size(t); + i64 tag_offset = align_formula(t->Union.variant_block_size, tag_size); + + if (tag_size > 0) { + vals[1] = lb_const_int(m, t_uintptr, tag_offset).value; + vals[2] = lb_type_info(m, union_tag_type(t)).value; + } else { + vals[1] = lb_const_int(m, t_uintptr, 0).value; + vals[2] = LLVMConstNull(lb_type(m, t_type_info_ptr)); + } + + vals[3] = lb_const_bool(m, t_bool, t->Union.custom_align != 0).value; + vals[4] = lb_const_bool(m, t_bool, t->Union.no_nil).value; + vals[5] = lb_const_bool(m, t_bool, t->Union.maybe).value; + + + lbValue res = {}; + res.type = type_deref(tag.type); + res.value = LLVMConstNamedStruct(lb_type(m, res.type), vals, gb_count_of(vals)); + lb_emit_store(p, tag, res); + } + + break; + } + + case Type_Struct: { + tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_struct_ptr); + + LLVMValueRef vals[11] = {}; + + + { + lbValue is_packed = lb_const_bool(m, t_bool, t->Struct.is_packed); + lbValue is_raw_union = lb_const_bool(m, t_bool, t->Struct.is_raw_union); + lbValue is_custom_align = lb_const_bool(m, t_bool, t->Struct.custom_align != 0); + vals[5] = is_packed.value; + vals[6] = is_raw_union.value; + vals[7] = is_custom_align.value; + + if (t->Struct.soa_kind != StructSoa_None) { + lbValue kind = lb_emit_struct_ep(p, tag, 8); + Type *kind_type = type_deref(kind.type); + + lbValue soa_kind = lb_const_value(m, kind_type, exact_value_i64(t->Struct.soa_kind)); + lbValue soa_type = lb_type_info(m, t->Struct.soa_elem); + lbValue soa_len = lb_const_int(m, t_int, t->Struct.soa_count); + + vals[8] = soa_kind.value; + vals[9] = soa_type.value; + vals[10] = soa_len.value; + } + } + + isize count = t->Struct.fields.count; + if (count > 0) { + lbValue memory_types = lb_type_info_member_types_offset (p, count); + lbValue memory_names = lb_type_info_member_names_offset (p, count); + lbValue memory_offsets = lb_type_info_member_offsets_offset(p, count); + lbValue memory_usings = lb_type_info_member_usings_offset (p, count); + lbValue memory_tags = lb_type_info_member_tags_offset (p, count); + + type_set_offsets(t); // NOTE(bill): Just incase the offsets have not been set yet + for (isize source_index = 0; source_index < count; source_index++) { + // TODO(bill): Order fields in source order not layout order + Entity *f = t->Struct.fields[source_index]; + lbValue tip = lb_get_type_info_ptr(m, f->type); + i64 foffset = 0; + if (!t->Struct.is_raw_union) { + foffset = t->Struct.offsets[f->Variable.field_index]; + } + GB_ASSERT(f->kind == Entity_Variable && f->flags & EntityFlag_Field); + + lbValue index = lb_const_int(m, t_int, source_index); + lbValue type_info = lb_emit_ptr_offset(p, memory_types, index); + lbValue offset = lb_emit_ptr_offset(p, memory_offsets, index); + lbValue is_using = lb_emit_ptr_offset(p, memory_usings, index); + + lb_emit_store(p, type_info, lb_type_info(m, f->type)); + if (f->token.string.len > 0) { + lbValue name = lb_emit_ptr_offset(p, memory_names, index); + lb_emit_store(p, name, lb_const_string(m, f->token.string)); + } + lb_emit_store(p, offset, lb_const_int(m, t_uintptr, foffset)); + lb_emit_store(p, is_using, lb_const_bool(m, t_bool, (f->flags&EntityFlag_Using) != 0)); + + if (t->Struct.tags.count > 0) { + String tag_string = t->Struct.tags[source_index]; + if (tag_string.len > 0) { + lbValue tag_ptr = lb_emit_ptr_offset(p, memory_tags, index); + lb_emit_store(p, tag_ptr, lb_const_string(m, tag_string)); + } + } + + } + + lbValue cv = lb_const_int(m, t_int, count); + vals[0] = llvm_const_slice(memory_types, cv); + vals[1] = llvm_const_slice(memory_names, cv); + vals[2] = llvm_const_slice(memory_offsets, cv); + vals[3] = llvm_const_slice(memory_usings, cv); + vals[4] = llvm_const_slice(memory_tags, cv); + } + for (isize i = 0; i < gb_count_of(vals); i++) { + if (vals[i] == nullptr) { + vals[i] = LLVMConstNull(lb_type(m, get_struct_field_type(tag.type, i))); + } + } + + + lbValue res = {}; + res.type = type_deref(tag.type); + res.value = LLVMConstNamedStruct(lb_type(m, res.type), vals, gb_count_of(vals)); + lb_emit_store(p, tag, res); + + break; + } + + case Type_Map: { + tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_map_ptr); + init_map_internal_types(t); + + LLVMValueRef vals[3] = { + lb_get_type_info_ptr(m, t->Map.key).value, + lb_get_type_info_ptr(m, t->Map.value).value, + lb_get_type_info_ptr(m, t->Map.generated_struct_type).value, + }; + + lbValue res = {}; + res.type = type_deref(tag.type); + res.value = LLVMConstNamedStruct(lb_type(m, res.type), vals, gb_count_of(vals)); + lb_emit_store(p, tag, res); + break; + } + + case Type_BitField: { + tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_bit_field_ptr); + // names: []string; + // bits: []u32; + // offsets: []u32; + isize count = t->BitField.fields.count; + if (count > 0) { + auto fields = t->BitField.fields; + lbValue name_array = lb_generate_array(m, t_string, count, str_lit("$bit_field_names"), cast(i64)entry_index); + lbValue bit_array = lb_generate_array(m, t_i32, count, str_lit("$bit_field_bits"), cast(i64)entry_index); + lbValue offset_array = lb_generate_array(m, t_i32, count, str_lit("$bit_field_offsets"), cast(i64)entry_index); + + for (isize i = 0; i < count; i++) { + Entity *f = fields[i]; + GB_ASSERT(f->type != nullptr); + GB_ASSERT(f->type->kind == Type_BitFieldValue); + lbValue name_ep = lb_emit_array_epi(p, name_array, cast(i32)i); + lbValue bit_ep = lb_emit_array_epi(p, bit_array, cast(i32)i); + lbValue offset_ep = lb_emit_array_epi(p, offset_array, cast(i32)i); + + lb_emit_store(p, name_ep, lb_const_string(m, f->token.string)); + lb_emit_store(p, bit_ep, lb_const_int(m, t_i32, f->type->BitFieldValue.bits)); + lb_emit_store(p, offset_ep, lb_const_int(m, t_i32, t->BitField.offsets[i])); + + } + + lbValue v_count = lb_const_int(m, t_int, count); + lbValue name_array_elem = lb_array_elem(p, name_array); + lbValue bit_array_elem = lb_array_elem(p, bit_array); + lbValue offset_array_elem = lb_array_elem(p, offset_array); + + + LLVMValueRef vals[3] = { + llvm_const_slice(name_array_elem, v_count), + llvm_const_slice(bit_array_elem, v_count), + llvm_const_slice(offset_array_elem, v_count), + }; + + lbValue res = {}; + res.type = type_deref(tag.type); + res.value = LLVMConstNamedStruct(lb_type(m, res.type), vals, gb_count_of(vals)); + lb_emit_store(p, tag, res); + } + break; + } + + case Type_BitSet: + { + tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_bit_set_ptr); + + GB_ASSERT(is_type_typed(t->BitSet.elem)); + + + LLVMValueRef vals[4] = { + lb_get_type_info_ptr(m, t->BitSet.elem).value, + LLVMConstNull(lb_type(m, t_type_info_ptr)), + lb_const_int(m, t_i64, t->BitSet.lower).value, + lb_const_int(m, t_i64, t->BitSet.upper).value, + }; + if (t->BitSet.underlying != nullptr) { + vals[1] =lb_get_type_info_ptr(m, t->BitSet.underlying).value; + } + + lbValue res = {}; + res.type = type_deref(tag.type); + res.value = LLVMConstNamedStruct(lb_type(m, res.type), vals, gb_count_of(vals)); + lb_emit_store(p, tag, res); + } + break; + + case Type_Opaque: + { + tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_opaque_ptr); + LLVMValueRef vals[1] = { + lb_get_type_info_ptr(m, t->Opaque.elem).value, + }; + + lbValue res = {}; + res.type = type_deref(tag.type); + res.value = LLVMConstNamedStruct(lb_type(m, res.type), vals, gb_count_of(vals)); + lb_emit_store(p, tag, res); + } + break; + case Type_SimdVector: + { + tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_simd_vector_ptr); + + LLVMValueRef vals[4] = {}; + + if (t->SimdVector.is_x86_mmx) { + vals[3] = lb_const_bool(m, t_bool, true).value; + } else { + vals[0] = lb_get_type_info_ptr(m, t->SimdVector.elem).value; + vals[1] = lb_const_int(m, t_int, type_size_of(t->SimdVector.elem)).value; + vals[2] = lb_const_int(m, t_int, t->SimdVector.count).value; + } + + lbValue res = {}; + res.type = type_deref(tag.type); + res.value = LLVMConstNamedStruct(lb_type(m, res.type), vals, gb_count_of(vals)); + lb_emit_store(p, tag, res); + } + break; + } + + + if (tag.value != nullptr) { + Type *tag_type = type_deref(tag.type); + GB_ASSERT(is_type_named(tag_type)); + // lb_emit_store_union_variant(p, variant_ptr, lb_emit_load(p, tag), tag_type); + lb_emit_store_union_variant_tag(p, variant_ptr, tag_type); + } else { + if (t != t_llvm_bool) { + GB_PANIC("Unhandled Type_Info variant: %s", type_to_string(t)); + } + } + } +} + + +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 Initializtion"); + + lbModule *m = &gen->module; + LLVMModuleRef mod = gen->module.mod; + CheckerInfo *info = gen->info; + + Arena temp_arena = {}; + arena_init(&temp_arena, heap_allocator()); + 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; + + + 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); + + LLVMTargetRef target = {}; + char *llvm_error = nullptr; + LLVMGetTargetFromTriple(target_triple, &target, &llvm_error); + GB_ASSERT(target != nullptr); + + TIME_SECTION("LLVM Create Target Machine"); + + LLVMTargetMachineRef target_machine = LLVMCreateTargetMachine(target, target_triple, "generic", "", LLVMCodeGenLevelNone, LLVMRelocDefault, LLVMCodeModelDefault); + defer (LLVMDisposeTargetMachine(target_machine)); + + LLVMSetModuleDataLayout(mod, LLVMCreateTargetDataLayout(target_machine)); + + { // 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 + ); + } + + TIME_SECTION("LLVM Global Variables"); + + { + { // Add type info data + isize max_type_info_count = info->minimum_dependency_type_info_set.entries.count+1; + // gb_printf_err("max_type_info_count: %td\n", max_type_info_count); + Type *t = alloc_type_array(t_type_info, max_type_info_count); + LLVMValueRef g = LLVMAddGlobal(mod, lb_type(m, t), LB_TYPE_INFO_DATA_NAME); + LLVMSetInitializer(g, LLVMConstNull(lb_type(m, t))); + LLVMSetLinkage(g, LLVMInternalLinkage); + + lbValue value = {}; + value.value = g; + value.type = alloc_type_pointer(t); + lb_global_type_info_data = lb_addr(value); + } + { // Type info member buffer + // NOTE(bill): Removes need for heap allocation by making it global memory + isize count = 0; + + for_array(entry_index, m->info->type_info_types) { + Type *t = m->info->type_info_types[entry_index]; + + isize index = lb_type_info_index(m->info, t, false); + if (index < 0) { + continue; + } + + switch (t->kind) { + case Type_Union: + count += t->Union.variants.count; + break; + case Type_Struct: + count += t->Struct.fields.count; + break; + case Type_Tuple: + count += t->Tuple.variables.count; + break; + } + } + + if (count > 0) { + { + char const *name = LB_TYPE_INFO_TYPES_NAME; + Type *t = alloc_type_array(t_type_info_ptr, count); + LLVMValueRef g = LLVMAddGlobal(mod, lb_type(m, t), name); + LLVMSetInitializer(g, LLVMConstNull(lb_type(m, t))); + LLVMSetLinkage(g, LLVMInternalLinkage); + lb_global_type_info_member_types = lb_addr({g, alloc_type_pointer(t)}); + + } + { + char const *name = LB_TYPE_INFO_NAMES_NAME; + Type *t = alloc_type_array(t_string, count); + LLVMValueRef g = LLVMAddGlobal(mod, lb_type(m, t), name); + LLVMSetInitializer(g, LLVMConstNull(lb_type(m, t))); + LLVMSetLinkage(g, LLVMInternalLinkage); + lb_global_type_info_member_names = lb_addr({g, alloc_type_pointer(t)}); + } + { + char const *name = LB_TYPE_INFO_OFFSETS_NAME; + Type *t = alloc_type_array(t_uintptr, count); + LLVMValueRef g = LLVMAddGlobal(mod, lb_type(m, t), name); + LLVMSetInitializer(g, LLVMConstNull(lb_type(m, t))); + LLVMSetLinkage(g, LLVMInternalLinkage); + lb_global_type_info_member_offsets = lb_addr({g, alloc_type_pointer(t)}); + } + + { + char const *name = LB_TYPE_INFO_USINGS_NAME; + Type *t = alloc_type_array(t_bool, count); + LLVMValueRef g = LLVMAddGlobal(mod, lb_type(m, t), name); + LLVMSetInitializer(g, LLVMConstNull(lb_type(m, t))); + LLVMSetLinkage(g, LLVMInternalLinkage); + lb_global_type_info_member_usings = lb_addr({g, alloc_type_pointer(t)}); + } + + { + char const *name = LB_TYPE_INFO_TAGS_NAME; + Type *t = alloc_type_array(t_string, count); + LLVMValueRef g = LLVMAddGlobal(mod, lb_type(m, t), name); + LLVMSetInitializer(g, LLVMConstNull(lb_type(m, t))); + LLVMSetLinkage(g, LLVMInternalLinkage); + lb_global_type_info_member_tags = lb_addr({g, alloc_type_pointer(t)}); + } + } + } + } + + + isize global_variable_max_count = 0; + Entity *entry_point = info->entry_point; + bool has_dll_main = false; + bool has_win_main = false; + + for_array(i, info->entities) { + Entity *e = info->entities[i]; + String name = e->token.string; + + bool is_global = e->pkg != nullptr; + + if (e->kind == Entity_Variable) { + global_variable_max_count++; + } else if (e->kind == Entity_Procedure && !is_global) { + if ((e->scope->flags&ScopeFlag_Init) && name == "main") { + GB_ASSERT(e == entry_point); + // entry_point = e; + } + if (e->Procedure.is_export || + (e->Procedure.link_name.len > 0) || + ((e->scope->flags&ScopeFlag_File) && e->Procedure.link_name.len > 0)) { + if (!has_dll_main && name == "DllMain") { + has_dll_main = true; + } else if (!has_win_main && name == "WinMain") { + has_win_main = true; + } + } + } + } + + struct GlobalVariable { + lbValue var; + lbValue init; + DeclInfo *decl; + }; + auto global_variables = array_make(heap_allocator(), 0, global_variable_max_count); + + for_array(i, info->variable_init_order) { + DeclInfo *d = info->variable_init_order[i]; + + Entity *e = d->entity; + + if ((e->scope->flags & ScopeFlag_File) == 0) { + continue; + } + + if (!ptr_set_exists(min_dep_set, e)) { + continue; + } + DeclInfo *decl = decl_info_of_entity(e); + if (decl == nullptr) { + continue; + } + GB_ASSERT(e->kind == Entity_Variable); + + bool is_foreign = e->Variable.is_foreign; + bool is_export = e->Variable.is_export; + + String name = lb_get_entity_name(m, e); + + + lbValue g = {}; + g.value = LLVMAddGlobal(m->mod, lb_type(m, e->type), alloc_cstring(heap_allocator(), name)); + g.type = alloc_type_pointer(e->type); + if (e->Variable.thread_local_model != "") { + LLVMSetThreadLocal(g.value, true); + + String m = e->Variable.thread_local_model; + LLVMThreadLocalMode mode = LLVMGeneralDynamicTLSModel; + if (m == "default") { + mode = LLVMGeneralDynamicTLSModel; + } else if (m == "localdynamic") { + mode = LLVMLocalDynamicTLSModel; + } else if (m == "initialexec") { + mode = LLVMInitialExecTLSModel; + } else if (m == "localexec") { + mode = LLVMLocalExecTLSModel; + } else { + GB_PANIC("Unhandled thread local mode %.*s", LIT(m)); + } + LLVMSetThreadLocalMode(g.value, mode); + } + if (is_foreign) { + LLVMSetExternallyInitialized(g.value, true); + } else { + LLVMSetInitializer(g.value, LLVMConstNull(lb_type(m, e->type))); + } + if (is_export) { + LLVMSetLinkage(g.value, LLVMDLLExportLinkage); + } + + GlobalVariable var = {}; + var.var = g; + var.decl = decl; + + if (decl->init_expr != nullptr && !is_type_any(e->type)) { + TypeAndValue tav = type_and_value_of_expr(decl->init_expr); + if (tav.mode != Addressing_Invalid) { + if (tav.value.kind != ExactValue_Invalid) { + ExactValue v = tav.value; + lbValue init = lb_const_value(m, tav.type, v); + LLVMSetInitializer(g.value, init.value); + } + } + } + + array_add(&global_variables, var); + + lb_add_entity(m, e, g); + lb_add_member(m, name, g); + } + + + TIME_SECTION("LLVM Global Procedures and Types"); + for_array(i, info->entities) { + // arena_free_all(&temp_arena); + // gbAllocator a = temp_allocator; + + Entity *e = info->entities[i]; + String name = e->token.string; + DeclInfo *decl = e->decl_info; + Scope * scope = e->scope; + + if ((scope->flags & ScopeFlag_File) == 0) { + continue; + } + + Scope *package_scope = scope->parent; + GB_ASSERT(package_scope->flags & ScopeFlag_Pkg); + + switch (e->kind) { + case Entity_Variable: + // NOTE(bill): Handled above as it requires a specific load order + continue; + case Entity_ProcGroup: + continue; + + case Entity_TypeName: + case Entity_Procedure: + break; + } + + bool polymorphic_struct = false; + if (e->type != nullptr && e->kind == Entity_TypeName) { + Type *bt = base_type(e->type); + if (bt->kind == Type_Struct) { + polymorphic_struct = is_type_polymorphic(bt); + } + } + + if (!polymorphic_struct && !ptr_set_exists(min_dep_set, e)) { + // NOTE(bill): Nothing depends upon it so doesn't need to be built + continue; + } + + + String mangled_name = lb_get_entity_name(m, e); + + switch (e->kind) { + case Entity_TypeName: + lb_type(m, e->type); + break; + case Entity_Procedure: + { + lbProcedure *p = lb_create_procedure(m, e); + array_add(&m->procedures_to_generate, p); + } + break; + } + } + + TIME_SECTION("LLVM Procedure Generation"); + for_array(i, m->procedures_to_generate) { + lbProcedure *p = m->procedures_to_generate[i]; + if (p->is_done) { + continue; + } + if (p->body != nullptr) { // Build Procedure + lb_begin_procedure_body(p); + lb_build_stmt(p, p->body); + lb_end_procedure_body(p); + p->is_done = true; + } + lb_end_procedure(p); + + // Add Flags + if (p->body != nullptr) { + if (p->name == "memcpy" || p->name == "memmove" || + p->name == "runtime.mem_copy" || p->name == "mem_copy_non_overlapping" || + string_starts_with(p->name, str_lit("llvm.memcpy")) || + string_starts_with(p->name, str_lit("llvm.memmove"))) { + p->flags |= lbProcedureFlag_WithoutMemcpyPass; + } + } + + 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); + } + } + + + TIME_SECTION("LLVM Function Pass"); + + LLVMPassRegistryRef pass_registry = LLVMGetGlobalPassRegistry(); + + LLVMPassManagerRef default_function_pass_manager = LLVMCreateFunctionPassManagerForModule(mod); + defer (LLVMDisposePassManager(default_function_pass_manager)); + { + LLVMAddMemCpyOptPass(default_function_pass_manager); + LLVMAddPromoteMemoryToRegisterPass(default_function_pass_manager); + LLVMAddMergedLoadStoreMotionPass(default_function_pass_manager); + LLVMAddAggressiveInstCombinerPass(default_function_pass_manager); + LLVMAddConstantPropagationPass(default_function_pass_manager); + LLVMAddAggressiveDCEPass(default_function_pass_manager); + LLVMAddMergedLoadStoreMotionPass(default_function_pass_manager); + LLVMAddPromoteMemoryToRegisterPass(default_function_pass_manager); + // LLVMAddUnifyFunctionExitNodesPass(default_function_pass_manager); + } + + LLVMPassManagerRef default_function_pass_manager_without_memcpy = LLVMCreateFunctionPassManagerForModule(mod); + defer (LLVMDisposePassManager(default_function_pass_manager_without_memcpy)); + { + LLVMAddPromoteMemoryToRegisterPass(default_function_pass_manager_without_memcpy); + LLVMAddMergedLoadStoreMotionPass(default_function_pass_manager_without_memcpy); + LLVMAddAggressiveInstCombinerPass(default_function_pass_manager_without_memcpy); + LLVMAddConstantPropagationPass(default_function_pass_manager_without_memcpy); + LLVMAddAggressiveDCEPass(default_function_pass_manager_without_memcpy); + LLVMAddMergedLoadStoreMotionPass(default_function_pass_manager_without_memcpy); + LLVMAddPromoteMemoryToRegisterPass(default_function_pass_manager_without_memcpy); + // LLVMAddUnifyFunctionExitNodesPass(default_function_pass_manager_without_memcpy); + } + + for_array(i, m->procedures_to_generate) { + lbProcedure *p = m->procedures_to_generate[i]; + if (p->body != nullptr) { // Build Procedure + if (p->flags & lbProcedureFlag_WithoutMemcpyPass) { + LLVMRunFunctionPassManager(default_function_pass_manager_without_memcpy, p->value); + } else { + LLVMRunFunctionPassManager(default_function_pass_manager, p->value); + } + } + } + + TIME_SECTION("LLVM Runtime Creation"); + + lbProcedure *startup_type_info = nullptr; + lbProcedure *startup_context = nullptr; + lbProcedure *startup_runtime = nullptr; + { // Startup Type Info + Type *params = alloc_type_tuple(); + Type *results = alloc_type_tuple(); + + Type *proc_type = alloc_type_proc(nullptr, nullptr, 0, nullptr, 0, false, ProcCC_CDecl); + + lbProcedure *p = lb_create_dummy_procedure(m, str_lit(LB_STARTUP_TYPE_INFO_PROC_NAME), proc_type); + p->is_startup = true; + startup_type_info = p; + + lb_begin_procedure_body(p); + + lb_setup_type_info_data(p); + + lb_end_procedure_body(p); + + if (LLVMVerifyFunction(p->value, LLVMReturnStatusAction)) { + gb_printf_err("LLVM CODE GEN FAILED FOR PROCEDURE: %s\n", "main"); + LLVMDumpValue(p->value); + gb_printf_err("\n\n\n\n"); + LLVMVerifyFunction(p->value, LLVMAbortProcessAction); + } + + LLVMRunFunctionPassManager(default_function_pass_manager, p->value); + } + { // Startup Context + Type *params = alloc_type_tuple(); + Type *results = alloc_type_tuple(); + + Type *proc_type = alloc_type_proc(nullptr, nullptr, 0, nullptr, 0, false, ProcCC_CDecl); + + lbProcedure *p = lb_create_dummy_procedure(m, str_lit(LB_STARTUP_CONTEXT_PROC_NAME), proc_type); + p->is_startup = true; + startup_context = p; + + lb_begin_procedure_body(p); + + lb_emit_init_context(p, p->module->global_default_context); + + lb_end_procedure_body(p); + + if (LLVMVerifyFunction(p->value, LLVMReturnStatusAction)) { + gb_printf_err("LLVM CODE GEN FAILED FOR PROCEDURE: %s\n", "main"); + LLVMDumpValue(p->value); + gb_printf_err("\n\n\n\n"); + LLVMVerifyFunction(p->value, LLVMAbortProcessAction); + } + + LLVMRunFunctionPassManager(default_function_pass_manager, p->value); + } + { // Startup Runtime + Type *params = alloc_type_tuple(); + Type *results = alloc_type_tuple(); + + Type *proc_type = alloc_type_proc(nullptr, nullptr, 0, nullptr, 0, false, ProcCC_CDecl); + + lbProcedure *p = lb_create_dummy_procedure(m, str_lit(LB_STARTUP_RUNTIME_PROC_NAME), proc_type); + p->is_startup = true; + startup_runtime = p; + + lb_begin_procedure_body(p); + + for_array(i, global_variables) { + auto *var = &global_variables[i]; + if (var->decl->init_expr != nullptr) { + var->init = lb_build_expr(p, var->decl->init_expr); + } + + Entity *e = var->decl->entity; + GB_ASSERT(e->kind == Entity_Variable); + + if (e->Variable.is_foreign) { + Entity *fl = e->Procedure.foreign_library; + lb_add_foreign_library_path(m, fl); + } + + if (e->flags & EntityFlag_Static) { + LLVMSetLinkage(var->var.value, LLVMInternalLinkage); + } + + if (var->init.value != nullptr) { + Type *t = type_deref(var->var.type); + + if (is_type_any(t)) { + // NOTE(bill): Edge case for 'any' type + Type *var_type = default_type(var->init.type); + lbAddr g = lb_add_global_generated(m, var_type, var->init); + lb_addr_store(p, g, var->init); + lbValue gp = lb_addr_get_ptr(p, g); + + lbValue data = lb_emit_struct_ep(p, var->var, 0); + lbValue ti = lb_emit_struct_ep(p, var->var, 1); + lb_emit_store(p, data, lb_emit_conv(p, gp, t_rawptr)); + lb_emit_store(p, ti, lb_type_info(m, var_type)); + } else { + lb_emit_store(p, var->var, lb_emit_conv(p, var->init, t)); + } + } + } + + + lb_end_procedure_body(p); + + if (LLVMVerifyFunction(p->value, LLVMReturnStatusAction)) { + gb_printf_err("LLVM CODE GEN FAILED FOR PROCEDURE: %s\n", "main"); + LLVMDumpValue(p->value); + gb_printf_err("\n\n\n\n"); + LLVMVerifyFunction(p->value, LLVMAbortProcessAction); + } + + LLVMRunFunctionPassManager(default_function_pass_manager, p->value); + + /*{ + LLVMValueRef last_instr = LLVMGetLastInstruction(p->decl_block->block); + for (LLVMValueRef instr = LLVMGetFirstInstruction(p->decl_block->block); + instr != last_instr; + instr = LLVMGetNextInstruction(instr)) { + if (LLVMIsAAllocaInst(instr)) { + LLVMTypeRef type = LLVMGetAllocatedType(instr); + LLVMValueRef sz_val = LLVMSizeOf(type); + GB_ASSERT(LLVMIsConstant(sz_val)); + gb_printf_err(">> 0x%p\n", sz_val); + LLVMTypeRef sz_type = LLVMTypeOf(sz_val); + gb_printf_err(">> %s\n", LLVMPrintTypeToString(sz_type)); + unsigned long long sz = LLVMConstIntGetZExtValue(sz_val); + // long long sz = LLVMConstIntGetSExtValue(sz_val); + gb_printf_err(">> %ll\n", sz); + } + } + }*/ + } + + if (!(build_context.is_dll && !has_dll_main)) { + Type *params = alloc_type_tuple(); + Type *results = alloc_type_tuple(); + + array_init(¶ms->Tuple.variables, heap_allocator(), 2); + params->Tuple.variables[0] = alloc_entity_param(nullptr, make_token_ident("argc"), t_i32, false, true); + params->Tuple.variables[1] = alloc_entity_param(nullptr, make_token_ident("argv"), alloc_type_pointer(t_cstring), false, true); + + array_init(&results->Tuple.variables, heap_allocator(), 1); + results->Tuple.variables[0] = alloc_entity_param(nullptr, make_token_ident("_"), t_i32, false, true); + + Type *proc_type = alloc_type_proc(nullptr, params, 2, results, 1, false, ProcCC_CDecl); + + lbProcedure *p = lb_create_dummy_procedure(m, str_lit("main"), proc_type); + p->is_startup = true; + + lb_begin_procedure_body(p); + + lbValue *found = map_get(&m->values, hash_entity(entry_point)); + GB_ASSERT(found != nullptr); + + LLVMBuildCall2(p->builder, LLVMGetElementType(lb_type(m, startup_type_info->type)), startup_type_info->value, nullptr, 0, ""); + LLVMBuildCall2(p->builder, LLVMGetElementType(lb_type(m, startup_context->type)), startup_context->value, nullptr, 0, ""); + LLVMBuildCall2(p->builder, LLVMGetElementType(lb_type(m, startup_runtime->type)), startup_runtime->value, nullptr, 0, ""); + LLVMBuildCall2(p->builder, LLVMGetElementType(lb_type(m, found->type)), found->value, nullptr, 0, ""); + LLVMBuildRet(p->builder, LLVMConstInt(lb_type(m, t_i32), 0, false)); + + lb_end_procedure_body(p); + + if (LLVMVerifyFunction(p->value, LLVMReturnStatusAction)) { + gb_printf_err("LLVM CODE GEN FAILED FOR PROCEDURE: %s\n", "main"); + LLVMDumpValue(p->value); + gb_printf_err("\n\n\n\n"); + LLVMVerifyFunction(p->value, LLVMAbortProcessAction); + } + + LLVMRunFunctionPassManager(default_function_pass_manager, p->value); + } + + + TIME_SECTION("LLVM Module Pass"); + + LLVMPassManagerRef module_pass_manager = LLVMCreatePassManager(); + defer (LLVMDisposePassManager(module_pass_manager)); + LLVMAddAlwaysInlinerPass(module_pass_manager); + LLVMAddStripDeadPrototypesPass(module_pass_manager); + // LLVMAddConstantMergePass(module_pass_manager); + + LLVMPassManagerBuilderRef pass_manager_builder = LLVMPassManagerBuilderCreate(); + defer (LLVMPassManagerBuilderDispose(pass_manager_builder)); + 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); + + llvm_error = nullptr; + defer (LLVMDisposeMessage(llvm_error)); + + String filepath_ll = concatenate_strings(heap_allocator(), gen->output_base, STR_LIT(".ll")); + defer (gb_free(heap_allocator(), filepath_ll.text)); + + String filepath_obj = concatenate_strings(heap_allocator(), gen->output_base, STR_LIT(".obj")); + + + if (build_context.keep_temp_files) { + TIME_SECTION("LLVM Print Module to File"); + LLVMPrintModuleToFile(mod, cast(char const *)filepath_ll.text, &llvm_error); + // exit(1); + } + LLVMDIBuilderFinalize(m->debug_builder); + LLVMVerifyModule(mod, LLVMAbortProcessAction, &llvm_error); + llvm_error = nullptr; + + TIME_SECTION("LLVM Object Generation"); + + LLVMBool was_an_error = LLVMTargetMachineEmitToFile(target_machine, mod, cast(char *)filepath_obj.text, LLVMObjectFile, &llvm_error); + if (was_an_error) { + gb_printf_err("LLVM Error: %s\n", llvm_error); + gb_exit(1); + return; + } + + array_add(&gen->output_object_paths, filepath_obj); + +#undef TIME_SECTION +} diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp new file mode 100644 index 000000000..02284b064 --- /dev/null +++ b/src/llvm_backend.hpp @@ -0,0 +1,407 @@ +#include "llvm-c/Core.h" +#include "llvm-c/ExecutionEngine.h" +#include "llvm-c/Target.h" +#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; + +struct lbValue { + LLVMValueRef value; + Type *type; +}; + + +enum lbAddrKind { + lbAddr_Default, + lbAddr_Map, + lbAddr_BitField, + lbAddr_Context, + lbAddr_SoaVariable, +}; + +struct lbAddr { + lbAddrKind kind; + lbValue addr; + union { + struct { + lbValue key; + Type *type; + Type *result; + } map; + struct { + i32 value_index; + } bit_field; + struct { + Selection sel; + } ctx; + struct { + lbValue index; + Ast *index_expr; + } soa; + }; +}; + +struct lbModule { + LLVMModuleRef mod; + LLVMContextRef ctx; + + CheckerInfo *info; + + gbMutex mutex; + + Map types; // Key: Type * + + Map values; // Key: Entity * + Map members; // Key: String + Map procedures; // Key: String + Map procedure_values; // Key: LLVMValueRef + + Map const_strings; // Key: String + + Map anonymous_proc_lits; // Key: Ast * + + lbAddr global_default_context; + + u32 global_array_index; + u32 global_generated_index; + u32 nested_type_name_guid; + + Array procedures_to_generate; + Array foreign_library_paths; + + + + LLVMDIBuilderRef debug_builder; + LLVMMetadataRef debug_compile_unit; + Map debug_values; // Key: Pointer +}; + +struct lbGenerator { + lbModule module; + CheckerInfo *info; + + Array output_object_paths; + String output_base; + String output_name; +}; + + +struct lbBlock { + LLVMBasicBlockRef block; + Scope *scope; + isize scope_index; + bool appended; + + Array preds; + Array succs; +}; + +struct lbBranchBlocks { + Ast *label; + lbBlock *break_; + lbBlock *continue_; +}; + + +struct lbContextData { + lbAddr ctx; + isize scope_index; +}; + +enum lbParamPasskind { + lbParamPass_Value, // Pass by value + lbParamPass_Pointer, // Pass as a pointer rather than by value + lbParamPass_Integer, // Pass as an integer of the same size + lbParamPass_ConstRef, // Pass as a pointer but the value is immutable + lbParamPass_BitCast, // Pass by value and bit cast to the correct type + lbParamPass_Tuple, // Pass across multiple parameters (System V AMD64, up to 2) +}; + +enum lbDeferExitKind { + lbDeferExit_Default, + lbDeferExit_Return, + lbDeferExit_Branch, +}; + +enum lbDeferKind { + lbDefer_Node, + lbDefer_Instr, + lbDefer_Proc, +}; + +struct lbDefer { + lbDeferKind kind; + isize scope_index; + isize context_stack_count; + lbBlock * block; + union { + Ast *stmt; + // NOTE(bill): 'instr' will be copied every time to create a new one + lbValue instr; + struct { + lbValue deferred; + Array result_as_args; + } proc; + }; +}; + +struct lbTargetList { + lbTargetList *prev; + bool is_block; + lbBlock * break_; + lbBlock * continue_; + lbBlock * fallthrough_; +}; + + +enum lbProcedureFlag : u32 { + lbProcedureFlag_WithoutMemcpyPass = 1<<0, +}; + +struct lbProcedure { + u32 flags; + + lbProcedure *parent; + Array children; + + Entity * entity; + lbModule * module; + String name; + Type * type; + Ast * type_expr; + Ast * body; + u64 tags; + ProcInlining inlining; + bool is_foreign; + bool is_export; + bool is_entry_point; + bool is_startup; + + + LLVMValueRef value; + LLVMBuilderRef builder; + bool is_done; + + lbAddr return_ptr; + Array params; + Array defer_stmts; + Array blocks; + Array branch_blocks; + Scope * curr_scope; + i32 scope_index; + lbBlock * decl_block; + lbBlock * entry_block; + lbBlock * curr_block; + lbTargetList * target_list; + + Array context_stack; + + lbValue return_ptr_hint_value; + Ast * return_ptr_hint_ast; + bool return_ptr_hint_used; +}; + + + + + +bool lb_init_generator(lbGenerator *gen, Checker *c); +void lb_generate_module(lbGenerator *gen); + +String lb_mangle_name(lbModule *m, Entity *e); +String lb_get_entity_name(lbModule *m, Entity *e, String name = {}); + +LLVMAttributeRef lb_create_enum_attribute(LLVMContextRef ctx, char const *name, u64 value); +void lb_add_proc_attribute_at_index(lbProcedure *p, isize index, char const *name, u64 value); +void lb_add_proc_attribute_at_index(lbProcedure *p, isize index, char const *name); +lbProcedure *lb_create_procedure(lbModule *module, Entity *entity); +void lb_end_procedure(lbProcedure *p); + + +LLVMTypeRef lb_type(lbModule *m, Type *type); + +lbBlock *lb_create_block(lbProcedure *p, char const *name, bool append=false); + +lbValue lb_const_nil(lbModule *m, Type *type); +lbValue lb_const_undef(lbModule *m, Type *type); +lbValue lb_const_value(lbModule *m, Type *type, ExactValue value); +lbValue lb_const_bool(lbModule *m, Type *type, bool value); +lbValue lb_const_int(lbModule *m, Type *type, u64 value); + + +lbAddr lb_addr(lbValue addr); +Type *lb_addr_type(lbAddr const &addr); +LLVMTypeRef lb_addr_lb_type(lbAddr const &addr); +void lb_addr_store(lbProcedure *p, lbAddr const &addr, lbValue value); +lbValue lb_addr_load(lbProcedure *p, lbAddr const &addr); +lbValue lb_emit_load(lbProcedure *p, lbValue v); +void lb_emit_store(lbProcedure *p, lbValue ptr, lbValue value); + + +void lb_build_stmt(lbProcedure *p, Ast *stmt); +lbValue lb_build_expr(lbProcedure *p, Ast *expr); +lbAddr lb_build_addr(lbProcedure *p, Ast *expr); +void lb_build_stmt_list(lbProcedure *p, Array const &stmts); + +lbValue lb_build_gep(lbProcedure *p, lbValue const &value, i32 index) ; + +lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index); +lbValue lb_emit_struct_ev(lbProcedure *p, lbValue s, i32 index); +lbValue lb_emit_array_epi(lbProcedure *p, lbValue value, isize index); +lbValue lb_emit_array_ep(lbProcedure *p, lbValue s, lbValue index); +lbValue lb_emit_deep_field_gep(lbProcedure *p, lbValue e, Selection sel); +lbValue lb_emit_deep_field_ev(lbProcedure *p, lbValue e, Selection sel); + +lbValue lb_emit_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type); +lbValue lb_emit_byte_swap(lbProcedure *p, lbValue value, Type *platform_type); +void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlock *block); +lbValue lb_emit_transmute(lbProcedure *p, lbValue value, Type *t); +lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue right); +lbValue lb_emit_call(lbProcedure *p, lbValue value, Array const &args, ProcInlining inlining = ProcInlining_none, bool use_return_ptr_hint = false); +lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t); +lbValue lb_emit_comp_against_nil(lbProcedure *p, TokenKind op_kind, lbValue x); + +void lb_emit_jump(lbProcedure *p, lbBlock *target_block); +void lb_emit_if(lbProcedure *p, lbValue cond, lbBlock *true_block, lbBlock *false_block); +void lb_start_block(lbProcedure *p, lbBlock *b); + +lbValue lb_build_call_expr(lbProcedure *p, Ast *expr); + + +lbAddr lb_find_or_generate_context_ptr(lbProcedure *p); +void lb_push_context_onto_stack(lbProcedure *p, lbAddr ctx); + + +lbAddr lb_add_global_generated(lbModule *m, Type *type, lbValue value={}); +lbAddr lb_add_local(lbProcedure *p, Type *type, Entity *e=nullptr, bool zero_init=true, i32 param_index=0); + +void lb_add_foreign_library_path(lbModule *m, Entity *e); + +lbValue lb_typeid(lbModule *m, Type *type, Type *typeid_type=t_typeid); + +lbValue lb_address_from_load_or_generate_local(lbProcedure *p, lbValue value); +lbDefer lb_add_defer_node(lbProcedure *p, isize scope_index, Ast *stmt); +lbAddr lb_add_local_generated(lbProcedure *p, Type *type, bool zero_init); + +lbValue lb_emit_runtime_call(lbProcedure *p, char const *c_name, Array const &args); + + +lbValue lb_emit_ptr_offset(lbProcedure *p, lbValue ptr, lbValue index); +lbValue lb_string_elem(lbProcedure *p, lbValue string); +lbValue lb_string_len(lbProcedure *p, lbValue string); +lbValue lb_cstring_len(lbProcedure *p, lbValue value); +lbValue lb_array_elem(lbProcedure *p, lbValue array_ptr); +lbValue lb_slice_elem(lbProcedure *p, lbValue slice); +lbValue lb_slice_len(lbProcedure *p, lbValue slice); +lbValue lb_dynamic_array_elem(lbProcedure *p, lbValue da); +lbValue lb_dynamic_array_len(lbProcedure *p, lbValue da); +lbValue lb_dynamic_array_cap(lbProcedure *p, lbValue da); +lbValue lb_dynamic_array_allocator(lbProcedure *p, lbValue da); +lbValue lb_map_entries(lbProcedure *p, lbValue value); +lbValue lb_map_entries_ptr(lbProcedure *p, lbValue value); +lbValue lb_map_len(lbProcedure *p, lbValue value); +lbValue lb_map_cap(lbProcedure *p, lbValue value); +lbValue lb_soa_struct_len(lbProcedure *p, lbValue value); + +void lb_emit_increment(lbProcedure *p, lbValue addr); + + +lbValue lb_type_info(lbModule *m, Type *type); + +lbValue lb_find_or_add_entity_string(lbModule *m, String const &str); +lbValue lb_generate_anonymous_proc_lit(lbModule *m, String const &prefix_name, Ast *expr, lbProcedure *parent = nullptr); + +bool lb_is_const(lbValue value); +bool lb_is_const_nil(lbValue value); +String lb_get_const_string(lbModule *m, lbValue value); + +lbValue lb_generate_array(lbModule *m, Type *elem_type, i64 count, String prefix, i64 id); +lbValue lb_gen_map_header(lbProcedure *p, lbValue map_val_ptr, Type *map_type); +lbValue lb_gen_map_key(lbProcedure *p, lbValue key, Type *key_type); +void lb_insert_dynamic_map_key_and_value(lbProcedure *p, lbAddr addr, Type *map_type, lbValue map_key, lbValue map_value); + + +void lb_store_type_case_implicit(lbProcedure *p, Ast *clause, lbValue value); +lbAddr lb_store_range_stmt_val(lbProcedure *p, Ast *stmt_val, lbValue value); + + +#define LB_STARTUP_RUNTIME_PROC_NAME "__$startup_runtime" +#define LB_STARTUP_CONTEXT_PROC_NAME "__$startup_context" +#define LB_STARTUP_TYPE_INFO_PROC_NAME "__$startup_type_info" +#define LB_TYPE_INFO_DATA_NAME "__$type_info_data" +#define LB_TYPE_INFO_TYPES_NAME "__$type_info_types_data" +#define LB_TYPE_INFO_NAMES_NAME "__$type_info_names_data" +#define LB_TYPE_INFO_OFFSETS_NAME "__$type_info_offsets_data" +#define LB_TYPE_INFO_USINGS_NAME "__$type_info_usings_data" +#define LB_TYPE_INFO_TAGS_NAME "__$type_info_tags_data" + + + +enum lbCallingConventionKind { + lbCallingConvention_C = 0, + lbCallingConvention_Fast = 8, + lbCallingConvention_Cold = 9, + lbCallingConvention_GHC = 10, + lbCallingConvention_HiPE = 11, + lbCallingConvention_WebKit_JS = 12, + lbCallingConvention_AnyReg = 13, + lbCallingConvention_PreserveMost = 14, + lbCallingConvention_PreserveAll = 15, + lbCallingConvention_Swift = 16, + lbCallingConvention_CXX_FAST_TLS = 17, + lbCallingConvention_FirstTargetCC = 64, + lbCallingConvention_X86_StdCall = 64, + lbCallingConvention_X86_FastCall = 65, + lbCallingConvention_ARM_APCS = 66, + lbCallingConvention_ARM_AAPCS = 67, + lbCallingConvention_ARM_AAPCS_VFP = 68, + lbCallingConvention_MSP430_INTR = 69, + lbCallingConvention_X86_ThisCall = 70, + lbCallingConvention_PTX_Kernel = 71, + lbCallingConvention_PTX_Device = 72, + lbCallingConvention_SPIR_FUNC = 75, + lbCallingConvention_SPIR_KERNEL = 76, + lbCallingConvention_Intel_OCL_BI = 77, + lbCallingConvention_X86_64_SysV = 78, + lbCallingConvention_Win64 = 79, + lbCallingConvention_X86_VectorCall = 80, + lbCallingConvention_HHVM = 81, + lbCallingConvention_HHVM_C = 82, + lbCallingConvention_X86_INTR = 83, + lbCallingConvention_AVR_INTR = 84, + lbCallingConvention_AVR_SIGNAL = 85, + lbCallingConvention_AVR_BUILTIN = 86, + lbCallingConvention_AMDGPU_VS = 87, + lbCallingConvention_AMDGPU_GS = 88, + lbCallingConvention_AMDGPU_PS = 89, + lbCallingConvention_AMDGPU_CS = 90, + lbCallingConvention_AMDGPU_KERNEL = 91, + lbCallingConvention_X86_RegCall = 92, + lbCallingConvention_AMDGPU_HS = 93, + lbCallingConvention_MSP430_BUILTIN = 94, + lbCallingConvention_AMDGPU_LS = 95, + lbCallingConvention_AMDGPU_ES = 96, + lbCallingConvention_AArch64_VectorCall = 97, + lbCallingConvention_MaxID = 1023, +}; + +lbCallingConventionKind const lb_calling_convention_map[ProcCC_MAX] = { + lbCallingConvention_C, // ProcCC_Invalid, + lbCallingConvention_C, // ProcCC_Odin, + lbCallingConvention_C, // ProcCC_Contextless, + lbCallingConvention_C, // ProcCC_CDecl, + lbCallingConvention_X86_StdCall, // ProcCC_StdCall, + lbCallingConvention_X86_FastCall, // ProcCC_FastCall, + + lbCallingConvention_C, // ProcCC_None, +}; diff --git a/src/main.cpp b/src/main.cpp index 077603b30..46364d8d6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -10,6 +10,10 @@ gb_global Timings global_timings = {0}; +#if defined(LLVM_BACKEND_SUPPORT) +#include "llvm-c/Types.h" +#endif + #include "parser.hpp" #include "checker.hpp" @@ -17,11 +21,18 @@ gb_global Timings global_timings = {0}; #include "parser.cpp" #include "docs.cpp" #include "checker.cpp" + + +#if defined(LLVM_BACKEND_SUPPORT) +#include "llvm_backend.cpp" +#endif + #include "ir.cpp" #include "ir_opt.cpp" #include "ir_print.cpp" #include "query_data.cpp" + #if defined(GB_SYSTEM_WINDOWS) // NOTE(IC): In order to find Visual C++ paths without relying on environment variables. #include "microsoft_craziness.h" @@ -121,6 +132,304 @@ i32 system_exec_command_line_app(char const *name, char const *fmt, ...) { + +#if defined(LLVM_BACKEND_SUPPORT) +i32 linker_stage(lbGenerator *gen) { + i32 exit_code = 0; + + Timings *timings = &global_timings; + + String output_base = gen->output_base; + + if (build_context.cross_compiling && selected_target_metrics->metrics == &target_essence_amd64) { +#ifdef GB_SYSTEM_UNIX + system_exec_command_line_app("linker", "x86_64-essence-gcc \"%.*s.o\" -o \"%.*s\" %.*s", + LIT(output_base), LIT(output_base), LIT(build_context.link_flags)); +#else + gb_printf_err("Don't know how to cross compile to selected target.\n"); +#endif + } else { + #if defined(GB_SYSTEM_WINDOWS) + timings_start_section(timings, str_lit("msvc-link")); + + gbString lib_str = gb_string_make(heap_allocator(), ""); + defer (gb_string_free(lib_str)); + char lib_str_buf[1024] = {0}; + + char const *output_ext = "exe"; + gbString link_settings = gb_string_make_reserve(heap_allocator(), 256); + defer (gb_string_free(link_settings)); + + + // NOTE(ic): It would be nice to extend this so that we could specify the Visual Studio version that we want instead of defaulting to the latest. + Find_Result_Utf8 find_result = find_visual_studio_and_windows_sdk_utf8(); + + if (find_result.windows_sdk_version == 0) { + gb_printf_err("Windows SDK not found.\n"); + return 1; + } + + // Add library search paths. + if (find_result.vs_library_path.len > 0) { + GB_ASSERT(find_result.windows_sdk_um_library_path.len > 0); + GB_ASSERT(find_result.windows_sdk_ucrt_library_path.len > 0); + + String path = {}; + auto add_path = [&](String path) { + if (path[path.len-1] == '\\') { + path.len -= 1; + } + link_settings = gb_string_append_fmt(link_settings, " /LIBPATH:\"%.*s\"", LIT(path)); + }; + add_path(find_result.windows_sdk_um_library_path); + add_path(find_result.windows_sdk_ucrt_library_path); + add_path(find_result.vs_library_path); + } + + for_array(i, gen->module.foreign_library_paths) { + String lib = gen->module.foreign_library_paths[i]; + GB_ASSERT(lib.len < gb_count_of(lib_str_buf)-1); + isize len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf), + " \"%.*s\"", LIT(lib)); + lib_str = gb_string_appendc(lib_str, lib_str_buf); + } + + + + if (build_context.is_dll) { + output_ext = "dll"; + link_settings = gb_string_append_fmt(link_settings, "/DLL"); + } else { + link_settings = gb_string_append_fmt(link_settings, "/ENTRY:mainCRTStartup"); + } + + if (build_context.pdb_filepath != "") { + link_settings = gb_string_append_fmt(link_settings, " /PDB:%.*s", LIT(build_context.pdb_filepath)); + } + + if (build_context.no_crt) { + link_settings = gb_string_append_fmt(link_settings, " /nodefaultlib"); + } else { + link_settings = gb_string_append_fmt(link_settings, " /defaultlib:libcmt"); + } + + if (build_context.ODIN_DEBUG) { + link_settings = gb_string_append_fmt(link_settings, " /DEBUG"); + } + + gbString object_files = gb_string_make(heap_allocator(), ""); + defer (gb_string_free(object_files)); + for_array(i, gen->output_object_paths) { + String object_path = gen->output_object_paths[i]; + object_files = gb_string_append_fmt(object_files, "\"%.*s\" ", LIT(object_path)); + } + + char const *subsystem_str = build_context.use_subsystem_windows ? "WINDOWS" : "CONSOLE"; + if (!build_context.use_lld) { // msvc + if (build_context.has_resource) { + exit_code = system_exec_command_line_app("msvc-link", + "\"%.*src.exe\" /nologo /fo \"%.*s.res\" \"%.*s.rc\"", + LIT(find_result.vs_exe_path), + LIT(output_base), + LIT(build_context.resource_filepath) + ); + + if (exit_code != 0) { + return exit_code; + } + + exit_code = system_exec_command_line_app("msvc-link", + "\"%.*slink.exe\" %s \"%.*s.res\" -OUT:\"%.*s.%s\" %s " + "/nologo /incremental:no /opt:ref /subsystem:%s " + " %.*s " + " %s " + "", + LIT(find_result.vs_exe_path), object_files, LIT(output_base), LIT(output_base), output_ext, + link_settings, + subsystem_str, + LIT(build_context.link_flags), + lib_str + ); + } else { + exit_code = system_exec_command_line_app("msvc-link", + "\"%.*slink.exe\" %s -OUT:\"%.*s.%s\" %s " + "/nologo /incremental:no /opt:ref /subsystem:%s " + " %.*s " + " %s " + "", + LIT(find_result.vs_exe_path), object_files, LIT(output_base), output_ext, + link_settings, + subsystem_str, + LIT(build_context.link_flags), + lib_str + ); + } + } else { // lld + exit_code = system_exec_command_line_app("msvc-link", + "\"%.*s\\bin\\lld-link\" %s -OUT:\"%.*s.%s\" %s " + "/nologo /incremental:no /opt:ref /subsystem:%s " + " %.*s " + " %s " + "", + LIT(build_context.ODIN_ROOT), + LIT(output_base), object_files, output_ext, + link_settings, + subsystem_str, + LIT(build_context.link_flags), + lib_str + ); + } + #else + timings_start_section(timings, str_lit("ld-link")); + + // NOTE(vassvik): get cwd, for used for local shared libs linking, since those have to be relative to the exe + char cwd[256]; + getcwd(&cwd[0], 256); + //printf("%s\n", cwd); + + // NOTE(vassvik): needs to add the root to the library search paths, so that the full filenames of the library + // files can be passed with -l: + gbString lib_str = gb_string_make(heap_allocator(), "-L/"); + defer (gb_string_free(lib_str)); + + for_array(i, ir_gen.module.foreign_library_paths) { + String lib = ir_gen.module.foreign_library_paths[i]; + + // NOTE(zangent): Sometimes, you have to use -framework on MacOS. + // This allows you to specify '-f' in a #foreign_system_library, + // without having to implement any new syntax specifically for MacOS. + #if defined(GB_SYSTEM_OSX) + if (string_ends_with(lib, str_lit(".framework"))) { + // framework thingie + String lib_name = lib; + lib_name = remove_extension_from_path(lib_name); + lib_str = gb_string_append_fmt(lib_str, " -framework %.*s ", LIT(lib_name)); + } else if (string_ends_with(lib, str_lit(".a"))) { + // static libs, absolute full path relative to the file in which the lib was imported from + lib_str = gb_string_append_fmt(lib_str, " %.*s ", LIT(lib)); + } else if (string_ends_with(lib, str_lit(".dylib"))) { + // dynamic lib + lib_str = gb_string_append_fmt(lib_str, " %.*s ", LIT(lib)); + } else { + // dynamic or static system lib, just link regularly searching system library paths + lib_str = gb_string_append_fmt(lib_str, " -l%.*s ", LIT(lib)); + } + #else + // NOTE(vassvik): static libraries (.a files) in linux can be linked to directly using the full path, + // since those are statically linked to at link time. shared libraries (.so) has to be + // available at runtime wherever the executable is run, so we make require those to be + // local to the executable (unless the system collection is used, in which case we search + // the system library paths for the library file). + if (string_ends_with(lib, str_lit(".a"))) { + // static libs, absolute full path relative to the file in which the lib was imported from + lib_str = gb_string_append_fmt(lib_str, " -l:\"%.*s\" ", LIT(lib)); + } else if (string_ends_with(lib, str_lit(".so"))) { + // dynamic lib, relative path to executable + // NOTE(vassvik): it is the user's responsibility to make sure the shared library files are visible + // at runtimeto the executable + lib_str = gb_string_append_fmt(lib_str, " -l:\"%s/%.*s\" ", cwd, LIT(lib)); + } else { + // dynamic or static system lib, just link regularly searching system library paths + lib_str = gb_string_append_fmt(lib_str, " -l%.*s ", LIT(lib)); + } + #endif + } + + gbString object_files = gb_string_make(heap_allocator(), ""); + defer (gb_string_free(object_files)); + for_array(i, gen->output_object_paths) { + String object_path = gen->output_object_paths[i]; + object_files = gb_string_append_fmt(object_files, "\"%.*s\" ", LIT(object_path)); + } + + // Unlike the Win32 linker code, the output_ext includes the dot, because + // typically executable files on *NIX systems don't have extensions. + String output_ext = {}; + char const *link_settings = ""; + char const *linker; + if (build_context.is_dll) { + // Shared libraries are .dylib on MacOS and .so on Linux. + #if defined(GB_SYSTEM_OSX) + output_ext = STR_LIT(".dylib"); + link_settings = "-dylib -dynamic"; + #else + output_ext = STR_LIT(".so"); + link_settings = "-shared"; + #endif + } else { + // TODO: Do I need anything here? + link_settings = ""; + } + + if (build_context.out_filepath.len > 0) { + //NOTE(thebirk): We have a custom -out arguments, so we should use the extension from that + isize pos = string_extension_position(build_context.out_filepath); + if (pos > 0) { + output_ext = substring(build_context.out_filepath, pos, build_context.out_filepath.len); + } + } + + #if defined(GB_SYSTEM_OSX) + linker = "ld"; + #else + // TODO(zangent): Figure out how to make ld work on Linux. + // It probably has to do with including the entire CRT, but + // that's quite a complicated issue to solve while remaining distro-agnostic. + // Clang can figure out linker flags for us, and that's good enough _for now_. + linker = "clang -Wno-unused-command-line-argument"; + #endif + + exit_code = system_exec_command_line_app("ld-link", + "%s %s -o \"%.*s%.*s\" %s " + " %s " + " %.*s " + " %s " + #if defined(GB_SYSTEM_OSX) + // This sets a requirement of Mountain Lion and up, but the compiler doesn't work without this limit. + // NOTE: If you change this (although this minimum is as low as you can go with Odin working) + // make sure to also change the 'mtriple' param passed to 'opt' + " -macosx_version_min 10.8.0 " + // This points the linker to where the entry point is + " -e _main " + #endif + , linker, object_files, LIT(output_base), LIT(output_ext), + lib_str, + "-lc -lm", + LIT(build_context.link_flags), + link_settings); + if (exit_code != 0) { + return exit_code; + } + + #if defined(GB_SYSTEM_OSX) + if (build_context.ODIN_DEBUG) { + // NOTE: macOS links DWARF symbols dynamically. Dsymutil will map the stubs in the exe + // to the symbols in the object file + exit_code = system_exec_command_line_app("dsymutil", + "dsymutil %.*s%.*s", LIT(output_base), LIT(output_ext) + ); + + if (exit_code != 0) { + return exit_code; + } + } + #endif + + + if (build_context.show_timings) { + show_timings(&checker, timings); + } + + remove_temp_files(output_base); + + + #endif + } + + return exit_code; +} +#endif + Array setup_args(int argc, char const **argv) { gbAllocator a = heap_allocator(); @@ -234,6 +543,7 @@ enum BuildFlagKind { BuildFlag_NoCRT, BuildFlag_UseLLD, BuildFlag_Vet, + BuildFlag_UseLLVMApi, BuildFlag_IgnoreUnknownAttributes, BuildFlag_Compact, @@ -325,6 +635,7 @@ bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_NoCRT, str_lit("no-crt"), BuildFlagParam_None); add_flag(&build_flags, BuildFlag_UseLLD, str_lit("lld"), BuildFlagParam_None); add_flag(&build_flags, BuildFlag_Vet, str_lit("vet"), BuildFlagParam_None); + add_flag(&build_flags, BuildFlag_UseLLVMApi, str_lit("llvm-api"), BuildFlagParam_None); add_flag(&build_flags, BuildFlag_IgnoreUnknownAttributes, str_lit("ignore-unknown-attributes"), BuildFlagParam_None); add_flag(&build_flags, BuildFlag_Compact, str_lit("compact"), BuildFlagParam_None); @@ -349,6 +660,7 @@ bool parse_build_flags(Array args) { gb_printf_err("Invalid flag: %.*s\n", LIT(flag)); continue; } + String name = substring(flag, 1, flag.len); isize end = 0; for (; end < name.len; end++) { @@ -694,6 +1006,10 @@ bool parse_build_flags(Array args) { build_context.vet = true; break; + case BuildFlag_UseLLVMApi: + build_context.use_llvm_api = true; + break; + case BuildFlag_IgnoreUnknownAttributes: build_context.ignore_unknown_attributes = true; break; @@ -1277,331 +1593,370 @@ int main(int arg_count, char const **arg_ptr) { return 1; } - irGen ir_gen = {0}; - if (!ir_gen_init(&ir_gen, &checker)) { - return 1; - } - // defer (ir_gen_destroy(&ir_gen)); + if (build_context.use_llvm_api) { +#if defined(LLVM_BACKEND_SUPPORT) - - timings_start_section(timings, str_lit("llvm ir gen")); - ir_gen_tree(&ir_gen); - - timings_start_section(timings, str_lit("llvm ir opt tree")); - ir_opt_tree(&ir_gen); - - timings_start_section(timings, str_lit("llvm ir print")); - print_llvm_ir(&ir_gen); - - - String output_name = ir_gen.output_name; - String output_base = ir_gen.output_base; - - build_context.optimization_level = gb_clamp(build_context.optimization_level, 0, 3); - - i32 exit_code = 0; - - timings_start_section(timings, str_lit("llvm-opt")); - exit_code = exec_llvm_opt(output_base); - if (exit_code != 0) { - return exit_code; - } - - timings_start_section(timings, str_lit("llvm-llc")); - exit_code = exec_llvm_llc(output_base); - if (exit_code != 0) { - return exit_code; - } - - if (build_context.cross_compiling && selected_target_metrics->metrics == &target_essence_amd64) { -#ifdef GB_SYSTEM_UNIX - system_exec_command_line_app("linker", "x86_64-essence-gcc \"%.*s.o\" -o \"%.*s\" %.*s", - LIT(output_base), LIT(output_base), LIT(build_context.link_flags)); -#else - gb_printf_err("Don't know how to cross compile to selected target.\n"); -#endif - } else { - #if defined(GB_SYSTEM_WINDOWS) - timings_start_section(timings, str_lit("msvc-link")); - - gbString lib_str = gb_string_make(heap_allocator(), ""); - defer (gb_string_free(lib_str)); - char lib_str_buf[1024] = {0}; - - char const *output_ext = "exe"; - gbString link_settings = gb_string_make_reserve(heap_allocator(), 256); - defer (gb_string_free(link_settings)); - - - // NOTE(ic): It would be nice to extend this so that we could specify the Visual Studio version that we want instead of defaulting to the latest. - Find_Result_Utf8 find_result = find_visual_studio_and_windows_sdk_utf8(); - - if (find_result.windows_sdk_version == 0) { - gb_printf_err("Windows SDK not found.\n"); + timings_start_section(timings, str_lit("LLVM API Code Gen")); + lbGenerator gen = {}; + if (!lb_init_generator(&gen, &checker)) { return 1; } + lb_generate_code(&gen); - // Add library search paths. - if (find_result.vs_library_path.len > 0) { - GB_ASSERT(find_result.windows_sdk_um_library_path.len > 0); - GB_ASSERT(find_result.windows_sdk_ucrt_library_path.len > 0); - - String path = {}; - auto add_path = [&](String path) { - if (path[path.len-1] == '\\') { - path.len -= 1; - } - link_settings = gb_string_append_fmt(link_settings, " /LIBPATH:\"%.*s\"", LIT(path)); - }; - add_path(find_result.windows_sdk_um_library_path); - add_path(find_result.windows_sdk_ucrt_library_path); - add_path(find_result.vs_library_path); - } - - for_array(i, ir_gen.module.foreign_library_paths) { - String lib = ir_gen.module.foreign_library_paths[i]; - GB_ASSERT(lib.len < gb_count_of(lib_str_buf)-1); - isize len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf), - " \"%.*s\"", LIT(lib)); - lib_str = gb_string_appendc(lib_str, lib_str_buf); - } - - - - if (build_context.is_dll) { - output_ext = "dll"; - link_settings = gb_string_append_fmt(link_settings, "/DLL"); - } else { - link_settings = gb_string_append_fmt(link_settings, "/ENTRY:mainCRTStartup"); - } - - if (build_context.pdb_filepath != "") { - link_settings = gb_string_append_fmt(link_settings, " /PDB:%.*s", LIT(build_context.pdb_filepath)); - } - - if (build_context.no_crt) { - link_settings = gb_string_append_fmt(link_settings, " /nodefaultlib"); - } else { - link_settings = gb_string_append_fmt(link_settings, " /defaultlib:libcmt"); - } - - if (ir_gen.module.generate_debug_info) { - link_settings = gb_string_append_fmt(link_settings, " /DEBUG"); - } - - - char const *subsystem_str = build_context.use_subsystem_windows ? "WINDOWS" : "CONSOLE"; - if (!build_context.use_lld) { // msvc - if (build_context.has_resource) { - exit_code = system_exec_command_line_app("msvc-link", - "\"%.*src.exe\" /nologo /fo \"%.*s.res\" \"%.*s.rc\"", - LIT(find_result.vs_exe_path), - LIT(output_base), - LIT(build_context.resource_filepath) - ); - - if (exit_code != 0) { - return exit_code; - } - - exit_code = system_exec_command_line_app("msvc-link", - "\"%.*slink.exe\" \"%.*s.obj\" \"%.*s.res\" -OUT:\"%.*s.%s\" %s " - "/nologo /incremental:no /opt:ref /subsystem:%s " - " %.*s " - " %s " - "", - LIT(find_result.vs_exe_path), LIT(output_base), LIT(output_base), LIT(output_base), output_ext, - link_settings, - subsystem_str, - LIT(build_context.link_flags), - lib_str - ); - } else { - exit_code = system_exec_command_line_app("msvc-link", - "\"%.*slink.exe\" \"%.*s.obj\" -OUT:\"%.*s.%s\" %s " - "/nologo /incremental:no /opt:ref /subsystem:%s " - " %.*s " - " %s " - "", - LIT(find_result.vs_exe_path), LIT(output_base), LIT(output_base), output_ext, - link_settings, - subsystem_str, - LIT(build_context.link_flags), - lib_str - ); - } - } else { // lld - exit_code = system_exec_command_line_app("msvc-link", - "\"%.*s\\bin\\lld-link\" \"%.*s.obj\" -OUT:\"%.*s.%s\" %s " - "/nologo /incremental:no /opt:ref /subsystem:%s " - " %.*s " - " %s " - "", - LIT(build_context.ODIN_ROOT), - LIT(output_base), LIT(output_base), output_ext, - link_settings, - subsystem_str, - LIT(build_context.link_flags), - lib_str - ); - } - - if (exit_code != 0) { - return exit_code; + i32 linker_stage_exit_count = linker_stage(&gen); + if (linker_stage_exit_count != 0) { + return linker_stage_exit_count; } if (build_context.show_timings) { show_timings(&checker, timings); } - remove_temp_files(output_base); + remove_temp_files(gen.output_base); if (run_output) { - return system_exec_command_line_app("odin run", "%.*s.exe %.*s", LIT(output_base), LIT(run_args_string)); - } - #else - timings_start_section(timings, str_lit("ld-link")); - - // NOTE(vassvik): get cwd, for used for local shared libs linking, since those have to be relative to the exe - char cwd[256]; - getcwd(&cwd[0], 256); - //printf("%s\n", cwd); - - // NOTE(vassvik): needs to add the root to the library search paths, so that the full filenames of the library - // files can be passed with -l: - gbString lib_str = gb_string_make(heap_allocator(), "-L/"); - defer (gb_string_free(lib_str)); - - for_array(i, ir_gen.module.foreign_library_paths) { - String lib = ir_gen.module.foreign_library_paths[i]; - - // NOTE(zangent): Sometimes, you have to use -framework on MacOS. - // This allows you to specify '-f' in a #foreign_system_library, - // without having to implement any new syntax specifically for MacOS. - #if defined(GB_SYSTEM_OSX) - if (string_ends_with(lib, str_lit(".framework"))) { - // framework thingie - String lib_name = lib; - lib_name = remove_extension_from_path(lib_name); - lib_str = gb_string_append_fmt(lib_str, " -framework %.*s ", LIT(lib_name)); - } else if (string_ends_with(lib, str_lit(".a"))) { - // static libs, absolute full path relative to the file in which the lib was imported from - lib_str = gb_string_append_fmt(lib_str, " %.*s ", LIT(lib)); - } else if (string_ends_with(lib, str_lit(".dylib"))) { - // dynamic lib - lib_str = gb_string_append_fmt(lib_str, " %.*s ", LIT(lib)); - } else { - // dynamic or static system lib, just link regularly searching system library paths - lib_str = gb_string_append_fmt(lib_str, " -l%.*s ", LIT(lib)); - } - #else - // NOTE(vassvik): static libraries (.a files) in linux can be linked to directly using the full path, - // since those are statically linked to at link time. shared libraries (.so) has to be - // available at runtime wherever the executable is run, so we make require those to be - // local to the executable (unless the system collection is used, in which case we search - // the system library paths for the library file). - if (string_ends_with(lib, str_lit(".a"))) { - // static libs, absolute full path relative to the file in which the lib was imported from - lib_str = gb_string_append_fmt(lib_str, " -l:\"%.*s\" ", LIT(lib)); - } else if (string_ends_with(lib, str_lit(".so"))) { - // dynamic lib, relative path to executable - // NOTE(vassvik): it is the user's responsibility to make sure the shared library files are visible - // at runtimeto the executable - lib_str = gb_string_append_fmt(lib_str, " -l:\"%s/%.*s\" ", cwd, LIT(lib)); - } else { - // dynamic or static system lib, just link regularly searching system library paths - lib_str = gb_string_append_fmt(lib_str, " -l%.*s ", LIT(lib)); - } - #endif - } - - // Unlike the Win32 linker code, the output_ext includes the dot, because - // typically executable files on *NIX systems don't have extensions. - String output_ext = {}; - char const *link_settings = ""; - char const *linker; - if (build_context.is_dll) { - // Shared libraries are .dylib on MacOS and .so on Linux. - #if defined(GB_SYSTEM_OSX) - output_ext = STR_LIT(".dylib"); - link_settings = "-dylib -dynamic"; - #else - output_ext = STR_LIT(".so"); - link_settings = "-shared"; - #endif - } else { - // TODO: Do I need anything here? - link_settings = ""; - } - - if (build_context.out_filepath.len > 0) { - //NOTE(thebirk): We have a custom -out arguments, so we should use the extension from that - isize pos = string_extension_position(build_context.out_filepath); - if (pos > 0) { - output_ext = substring(build_context.out_filepath, pos, build_context.out_filepath.len); - } - } - - #if defined(GB_SYSTEM_OSX) - linker = "ld"; + #if defined(GB_SYSTEM_WINDOWS) + return system_exec_command_line_app("odin run", "%.*s.exe %.*s", LIT(gen.output_base), LIT(run_args_string)); #else - // TODO(zangent): Figure out how to make ld work on Linux. - // It probably has to do with including the entire CRT, but - // that's quite a complicated issue to solve while remaining distro-agnostic. - // Clang can figure out linker flags for us, and that's good enough _for now_. - linker = "clang -Wno-unused-command-line-argument"; - #endif - - exit_code = system_exec_command_line_app("ld-link", - "%s \"%.*s.o\" -o \"%.*s%.*s\" %s " - " %s " - " %.*s " - " %s " - #if defined(GB_SYSTEM_OSX) - // This sets a requirement of Mountain Lion and up, but the compiler doesn't work without this limit. - // NOTE: If you change this (although this minimum is as low as you can go with Odin working) - // make sure to also change the 'mtriple' param passed to 'opt' - " -macosx_version_min 10.8.0 " - // This points the linker to where the entry point is - " -e _main " - #endif - , linker, LIT(output_base), LIT(output_base), LIT(output_ext), - lib_str, - "-lc -lm", - LIT(build_context.link_flags), - link_settings); - if (exit_code != 0) { - return exit_code; - } - - #if defined(GB_SYSTEM_OSX) - if (build_context.ODIN_DEBUG) { - // NOTE: macOS links DWARF symbols dynamically. Dsymutil will map the stubs in the exe - // to the symbols in the object file - exit_code = system_exec_command_line_app("dsymutil", - "dsymutil %.*s%.*s", LIT(output_base), LIT(output_ext) - ); - - if (exit_code != 0) { - return exit_code; - } - } - #endif - - - if (build_context.show_timings) { - show_timings(&checker, timings); - } - - remove_temp_files(output_base); - - if (run_output) { //NOTE(thebirk): This whole thing is a little leaky String complete_path = concatenate_strings(heap_allocator(), output_base, output_ext); complete_path = path_to_full_path(heap_allocator(), complete_path); return system_exec_command_line_app("odin run", "\"%.*s\" %.*s", LIT(complete_path), LIT(run_args_string)); + #endif } + + return 0; +#else + gb_printf_err("LLVM C API backend is not supported on this platform yet\n"); + return 1; +#endif + } else { + irGen ir_gen = {0}; + if (!ir_gen_init(&ir_gen, &checker)) { + return 1; + } + // defer (ir_gen_destroy(&ir_gen)); + + + timings_start_section(timings, str_lit("llvm ir gen")); + ir_gen_tree(&ir_gen); + + timings_start_section(timings, str_lit("llvm ir opt tree")); + ir_opt_tree(&ir_gen); + + timings_start_section(timings, str_lit("llvm ir print")); + print_llvm_ir(&ir_gen); + + + String output_name = ir_gen.output_name; + String output_base = ir_gen.output_base; + + build_context.optimization_level = gb_clamp(build_context.optimization_level, 0, 3); + + i32 exit_code = 0; + + timings_start_section(timings, str_lit("llvm-opt")); + exit_code = exec_llvm_opt(output_base); + if (exit_code != 0) { + return exit_code; + } + + timings_start_section(timings, str_lit("llvm-llc")); + exit_code = exec_llvm_llc(output_base); + if (exit_code != 0) { + return exit_code; + } + + if (build_context.cross_compiling && selected_target_metrics->metrics == &target_essence_amd64) { + #ifdef GB_SYSTEM_UNIX + system_exec_command_line_app("linker", "x86_64-essence-gcc \"%.*s.o\" -o \"%.*s\" %.*s", + LIT(output_base), LIT(output_base), LIT(build_context.link_flags)); + #else + gb_printf_err("Don't know how to cross compile to selected target.\n"); #endif + } else { + #if defined(GB_SYSTEM_WINDOWS) + timings_start_section(timings, str_lit("msvc-link")); + + gbString lib_str = gb_string_make(heap_allocator(), ""); + defer (gb_string_free(lib_str)); + char lib_str_buf[1024] = {0}; + + char const *output_ext = "exe"; + gbString link_settings = gb_string_make_reserve(heap_allocator(), 256); + defer (gb_string_free(link_settings)); + + + // NOTE(ic): It would be nice to extend this so that we could specify the Visual Studio version that we want instead of defaulting to the latest. + Find_Result_Utf8 find_result = find_visual_studio_and_windows_sdk_utf8(); + + if (find_result.windows_sdk_version == 0) { + gb_printf_err("Windows SDK not found.\n"); + return 1; + } + + // Add library search paths. + if (find_result.vs_library_path.len > 0) { + GB_ASSERT(find_result.windows_sdk_um_library_path.len > 0); + GB_ASSERT(find_result.windows_sdk_ucrt_library_path.len > 0); + + String path = {}; + auto add_path = [&](String path) { + if (path[path.len-1] == '\\') { + path.len -= 1; + } + link_settings = gb_string_append_fmt(link_settings, " /LIBPATH:\"%.*s\"", LIT(path)); + }; + add_path(find_result.windows_sdk_um_library_path); + add_path(find_result.windows_sdk_ucrt_library_path); + add_path(find_result.vs_library_path); + } + + for_array(i, ir_gen.module.foreign_library_paths) { + String lib = ir_gen.module.foreign_library_paths[i]; + GB_ASSERT(lib.len < gb_count_of(lib_str_buf)-1); + isize len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf), + " \"%.*s\"", LIT(lib)); + lib_str = gb_string_appendc(lib_str, lib_str_buf); + } + + + + if (build_context.is_dll) { + output_ext = "dll"; + link_settings = gb_string_append_fmt(link_settings, "/DLL"); + } else { + link_settings = gb_string_append_fmt(link_settings, "/ENTRY:mainCRTStartup"); + } + + if (build_context.pdb_filepath != "") { + link_settings = gb_string_append_fmt(link_settings, " /PDB:%.*s", LIT(build_context.pdb_filepath)); + } + + if (build_context.no_crt) { + link_settings = gb_string_append_fmt(link_settings, " /nodefaultlib"); + } else { + link_settings = gb_string_append_fmt(link_settings, " /defaultlib:libcmt"); + } + + if (ir_gen.module.generate_debug_info) { + link_settings = gb_string_append_fmt(link_settings, " /DEBUG"); + } + + + char const *subsystem_str = build_context.use_subsystem_windows ? "WINDOWS" : "CONSOLE"; + if (!build_context.use_lld) { // msvc + if (build_context.has_resource) { + exit_code = system_exec_command_line_app("msvc-link", + "\"%.*src.exe\" /nologo /fo \"%.*s.res\" \"%.*s.rc\"", + LIT(find_result.vs_exe_path), + LIT(output_base), + LIT(build_context.resource_filepath) + ); + + if (exit_code != 0) { + return exit_code; + } + + exit_code = system_exec_command_line_app("msvc-link", + "\"%.*slink.exe\" \"%.*s.obj\" \"%.*s.res\" -OUT:\"%.*s.%s\" %s " + "/nologo /incremental:no /opt:ref /subsystem:%s " + " %.*s " + " %s " + "", + LIT(find_result.vs_exe_path), LIT(output_base), LIT(output_base), LIT(output_base), output_ext, + link_settings, + subsystem_str, + LIT(build_context.link_flags), + lib_str + ); + } else { + exit_code = system_exec_command_line_app("msvc-link", + "\"%.*slink.exe\" \"%.*s.obj\" -OUT:\"%.*s.%s\" %s " + "/nologo /incremental:no /opt:ref /subsystem:%s " + " %.*s " + " %s " + "", + LIT(find_result.vs_exe_path), LIT(output_base), LIT(output_base), output_ext, + link_settings, + subsystem_str, + LIT(build_context.link_flags), + lib_str + ); + } + } else { // lld + exit_code = system_exec_command_line_app("msvc-link", + "\"%.*s\\bin\\lld-link\" \"%.*s.obj\" -OUT:\"%.*s.%s\" %s " + "/nologo /incremental:no /opt:ref /subsystem:%s " + " %.*s " + " %s " + "", + LIT(build_context.ODIN_ROOT), + LIT(output_base), LIT(output_base), output_ext, + link_settings, + subsystem_str, + LIT(build_context.link_flags), + lib_str + ); + } + + if (exit_code != 0) { + return exit_code; + } + + if (build_context.show_timings) { + show_timings(&checker, timings); + } + + remove_temp_files(output_base); + + if (run_output) { + return system_exec_command_line_app("odin run", "%.*s.exe %.*s", LIT(output_base), LIT(run_args_string)); + } + #else + timings_start_section(timings, str_lit("ld-link")); + + // NOTE(vassvik): get cwd, for used for local shared libs linking, since those have to be relative to the exe + char cwd[256]; + getcwd(&cwd[0], 256); + //printf("%s\n", cwd); + + // NOTE(vassvik): needs to add the root to the library search paths, so that the full filenames of the library + // files can be passed with -l: + gbString lib_str = gb_string_make(heap_allocator(), "-L/"); + defer (gb_string_free(lib_str)); + + for_array(i, ir_gen.module.foreign_library_paths) { + String lib = ir_gen.module.foreign_library_paths[i]; + + // NOTE(zangent): Sometimes, you have to use -framework on MacOS. + // This allows you to specify '-f' in a #foreign_system_library, + // without having to implement any new syntax specifically for MacOS. + #if defined(GB_SYSTEM_OSX) + if (string_ends_with(lib, str_lit(".framework"))) { + // framework thingie + String lib_name = lib; + lib_name = remove_extension_from_path(lib_name); + lib_str = gb_string_append_fmt(lib_str, " -framework %.*s ", LIT(lib_name)); + } else if (string_ends_with(lib, str_lit(".a"))) { + // static libs, absolute full path relative to the file in which the lib was imported from + lib_str = gb_string_append_fmt(lib_str, " %.*s ", LIT(lib)); + } else if (string_ends_with(lib, str_lit(".dylib"))) { + // dynamic lib + lib_str = gb_string_append_fmt(lib_str, " %.*s ", LIT(lib)); + } else { + // dynamic or static system lib, just link regularly searching system library paths + lib_str = gb_string_append_fmt(lib_str, " -l%.*s ", LIT(lib)); + } + #else + // NOTE(vassvik): static libraries (.a files) in linux can be linked to directly using the full path, + // since those are statically linked to at link time. shared libraries (.so) has to be + // available at runtime wherever the executable is run, so we make require those to be + // local to the executable (unless the system collection is used, in which case we search + // the system library paths for the library file). + if (string_ends_with(lib, str_lit(".a"))) { + // static libs, absolute full path relative to the file in which the lib was imported from + lib_str = gb_string_append_fmt(lib_str, " -l:\"%.*s\" ", LIT(lib)); + } else if (string_ends_with(lib, str_lit(".so"))) { + // dynamic lib, relative path to executable + // NOTE(vassvik): it is the user's responsibility to make sure the shared library files are visible + // at runtimeto the executable + lib_str = gb_string_append_fmt(lib_str, " -l:\"%s/%.*s\" ", cwd, LIT(lib)); + } else { + // dynamic or static system lib, just link regularly searching system library paths + lib_str = gb_string_append_fmt(lib_str, " -l%.*s ", LIT(lib)); + } + #endif + } + + // Unlike the Win32 linker code, the output_ext includes the dot, because + // typically executable files on *NIX systems don't have extensions. + String output_ext = {}; + char const *link_settings = ""; + char const *linker; + if (build_context.is_dll) { + // Shared libraries are .dylib on MacOS and .so on Linux. + #if defined(GB_SYSTEM_OSX) + output_ext = STR_LIT(".dylib"); + link_settings = "-dylib -dynamic"; + #else + output_ext = STR_LIT(".so"); + link_settings = "-shared"; + #endif + } else { + // TODO: Do I need anything here? + link_settings = ""; + } + + if (build_context.out_filepath.len > 0) { + //NOTE(thebirk): We have a custom -out arguments, so we should use the extension from that + isize pos = string_extension_position(build_context.out_filepath); + if (pos > 0) { + output_ext = substring(build_context.out_filepath, pos, build_context.out_filepath.len); + } + } + + #if defined(GB_SYSTEM_OSX) + linker = "ld"; + #else + // TODO(zangent): Figure out how to make ld work on Linux. + // It probably has to do with including the entire CRT, but + // that's quite a complicated issue to solve while remaining distro-agnostic. + // Clang can figure out linker flags for us, and that's good enough _for now_. + linker = "clang -Wno-unused-command-line-argument"; + #endif + + exit_code = system_exec_command_line_app("ld-link", + "%s \"%.*s.o\" -o \"%.*s%.*s\" %s " + " %s " + " %.*s " + " %s " + #if defined(GB_SYSTEM_OSX) + // This sets a requirement of Mountain Lion and up, but the compiler doesn't work without this limit. + // NOTE: If you change this (although this minimum is as low as you can go with Odin working) + // make sure to also change the 'mtriple' param passed to 'opt' + " -macosx_version_min 10.8.0 " + // This points the linker to where the entry point is + " -e _main " + #endif + , linker, LIT(output_base), LIT(output_base), LIT(output_ext), + lib_str, + "-lc -lm", + LIT(build_context.link_flags), + link_settings); + if (exit_code != 0) { + return exit_code; + } + + #if defined(GB_SYSTEM_OSX) + if (build_context.ODIN_DEBUG) { + // NOTE: macOS links DWARF symbols dynamically. Dsymutil will map the stubs in the exe + // to the symbols in the object file + exit_code = system_exec_command_line_app("dsymutil", + "dsymutil %.*s%.*s", LIT(output_base), LIT(output_ext) + ); + + if (exit_code != 0) { + return exit_code; + } + } + #endif + + + if (build_context.show_timings) { + show_timings(&checker, timings); + } + + remove_temp_files(output_base); + + if (run_output) { + //NOTE(thebirk): This whole thing is a little leaky + String complete_path = concatenate_strings(heap_allocator(), output_base, output_ext); + complete_path = path_to_full_path(heap_allocator(), complete_path); + return system_exec_command_line_app("odin run", "\"%.*s\" %.*s", LIT(complete_path), LIT(run_args_string)); + } + #endif + } } return 0; diff --git a/src/map.cpp b/src/map.cpp index aa4152696..03ac924fe 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -55,12 +55,14 @@ gb_inline HashKey hash_string(String s) { gb_inline HashKey hash_pointer(void *ptr) { HashKey h = {HashKey_Ptr}; h.key = cast(u64)cast(uintptr)ptr; + // h.key = gb_fnv64a(&ptr, gb_size_of(void *)); h.ptr = ptr; return h; } gb_inline HashKey hash_ptr_and_id(void *ptr, u64 id) { HashKey h = {HashKey_PtrAndId}; h.key = cast(u64)cast(uintptr)ptr; + // h.key = gb_fnv64a(&ptr, gb_size_of(void *)); h.ptr_and_id.ptr = ptr; h.ptr_and_id.id = id; return h; diff --git a/src/parser.hpp b/src/parser.hpp index 3de848ca6..129f1d41b 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; }; @@ -174,12 +176,10 @@ enum ProcCallingConvention { ProcCC_StdCall, ProcCC_FastCall, - // TODO(bill): Add extra calling conventions - // ProcCC_VectorCall, - // ProcCC_ClrCall, - ProcCC_None, + ProcCC_MAX, + ProcCC_ForeignBlockDefault = -1, }; @@ -251,6 +251,7 @@ enum StmtAllowFlag { ProcInlining inlining; \ Token where_token; \ Array where_clauses; \ + DeclInfo *decl; \ }) \ AST_KIND(CompoundLit, "compound literal", struct { \ Ast *type; \ diff --git a/src/string.cpp b/src/string.cpp index 9551821aa..724733ce7 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -101,6 +101,14 @@ char *alloc_cstring(gbAllocator a, String s) { return c_str; } +char *cstring_duplicate(gbAllocator a, char const *s) { + isize len = gb_strlen(s); + char *c_str = gb_alloc_array(a, char, len+1); + gb_memmove(c_str, s, len); + c_str[len] = '\0'; + return c_str; +} + gb_inline bool str_eq_ignore_case(String const &a, String const &b) { diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 19cb9b9aa..5ac590b22 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -179,6 +179,10 @@ Token make_token_ident(String s) { Token t = {Token_Ident, s}; return t; } +Token make_token_ident(char const *s) { + Token t = {Token_Ident, make_string_c(s)}; + return t; +} struct ErrorCollector { @@ -904,7 +908,7 @@ Token tokenizer_get_token(Tokenizer *t) { } if (token.kind == Token_Ident && token.string == "notin") { - token.kind = Token_not_in; + token.kind = Token_not_in; } }