aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorgingerBill <gingerBill@users.noreply.github.com>2020-03-26 17:41:38 +0000
committerGitHub <noreply@github.com>2020-03-26 17:41:38 +0000
commit6bbecbe895a7b413dee61da772586be4e3138174 (patch)
treea86e716cb2a519a7bff7a320821fbde7abd8673e /src
parent7909872877fd5c82c29df711f160838a7a4e59e1 (diff)
parentb21993a1c470a533a83e5b01274d3b026fb34f9b (diff)
Merge pull request #595 from odin-lang/llvm-integration
LLVM C API Integration
Diffstat (limited to 'src')
-rw-r--r--src/build_settings.cpp2
-rw-r--r--src/check_decl.cpp1
-rw-r--r--src/check_expr.cpp13
-rw-r--r--src/checker.cpp8
-rw-r--r--src/checker.hpp3
-rw-r--r--src/ir_print.cpp3
-rw-r--r--src/llvm-c/Analysis.h65
-rw-r--r--src/llvm-c/BitReader.h85
-rw-r--r--src/llvm-c/BitWriter.h59
-rw-r--r--src/llvm-c/Comdat.h75
-rw-r--r--src/llvm-c/Config/AsmParsers.def44
-rw-r--r--src/llvm-c/Config/AsmPrinters.def46
-rw-r--r--src/llvm-c/Config/Disassemblers.def45
-rw-r--r--src/llvm-c/Config/Targets.def45
-rw-r--r--src/llvm-c/Config/abi-breaking.h62
-rw-r--r--src/llvm-c/Config/llvm-config.h85
-rw-r--r--src/llvm-c/Core.h4079
-rw-r--r--src/llvm-c/DataTypes.h90
-rw-r--r--src/llvm-c/DebugInfo.h1315
-rw-r--r--src/llvm-c/Disassembler.h113
-rw-r--r--src/llvm-c/DisassemblerTypes.h160
-rw-r--r--src/llvm-c/Error.h69
-rw-r--r--src/llvm-c/ErrorHandling.h49
-rw-r--r--src/llvm-c/ExecutionEngine.h200
-rw-r--r--src/llvm-c/IRReader.h40
-rw-r--r--src/llvm-c/Initialization.h56
-rw-r--r--src/llvm-c/LinkTimeOptimizer.h68
-rw-r--r--src/llvm-c/Linker.h41
-rw-r--r--src/llvm-c/Object.h233
-rw-r--r--src/llvm-c/OrcBindings.h172
-rw-r--r--src/llvm-c/Remarks.h329
-rw-r--r--src/llvm-c/Support.h65
-rw-r--r--src/llvm-c/Target.h295
-rw-r--r--src/llvm-c/TargetMachine.h163
-rw-r--r--src/llvm-c/Transforms/AggressiveInstCombine.h43
-rw-r--r--src/llvm-c/Transforms/Coroutines.h55
-rw-r--r--src/llvm-c/Transforms/IPO.h84
-rw-r--r--src/llvm-c/Transforms/InstCombine.h43
-rw-r--r--src/llvm-c/Transforms/PassManagerBuilder.h90
-rw-r--r--src/llvm-c/Transforms/Scalar.h167
-rw-r--r--src/llvm-c/Transforms/Utils.h53
-rw-r--r--src/llvm-c/Transforms/Vectorize.h50
-rw-r--r--src/llvm-c/Types.h179
-rw-r--r--src/llvm-c/lto.h899
-rw-r--r--src/llvm_backend.cpp11024
-rw-r--r--src/llvm_backend.hpp407
-rw-r--r--src/main.cpp877
-rw-r--r--src/map.cpp2
-rw-r--r--src/parser.hpp11
-rw-r--r--src/string.cpp8
-rw-r--r--src/tokenizer.cpp6
51 files changed, 21904 insertions, 272 deletions
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 <cmath>
+#else
+#include <math.h>
+#endif
+
+#include <inttypes.h>
+#include <stdint.h>
+
+#ifndef _MSC_VER
+
+#if !defined(UINT32_MAX)
+# error "The standard header <cstdint> 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 <cstdint> is not C++11 compliant. Must #define "\
+ "__STDC_CONSTANT_MACROS before #including llvm-c/DataTypes.h"
+#endif
+
+/* Note that <inttypes.h> includes <stdint.h>, if this is a C99 system. */
+#include <sys/types.h>
+
+#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 <cstddef>
+#include <cstdlib>
+#else
+#include <stddef.h>
+#include <stdlib.h>
+#endif
+#include <sys/types.h>
+
+#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 <cstddef>
+#else
+#include <stddef.h>
+#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 <cstddef>
+extern "C" {
+#else
+#include <stddef.h>
+#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<RequiredType>(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<unsigned, MDNode *>
+ */
+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 <cstddef>
+#else
+#include <stddef.h>
+#endif
+#include <sys/types.h>
+
+#ifndef __cplusplus
+#if !defined(_MSC_VER)
+#include <stdbool.h>
+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<lbValue>(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<lbValue>(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<Ast *> 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<lbValue>(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<Ast *> 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<LLVMValueRef> incoming_values = {};
+ Array<LLVMBasicBlockRef> 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<lbAddr>(heap_allocator(), 0, vd->names.count);
+ auto inits = array_make<lbValue>(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<lbAddr>(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<lbValue>(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<lbValue>(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<lbValue>(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<u32>(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<lbValue>(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<lbValue>(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<<cast(u64)(v-lower);
+ }
+ if (is_type_different_to_arch_endianness(type)) {
+ i64 size = type_size_of(type);
+ switch (size) {
+ case 2: bits = cast(u64)gb_endian_swap16(cast(u16)bits); break;
+ case 4: bits = cast(u64)gb_endian_swap32(cast(u32)bits); break;
+ case 8: bits = cast(u64)gb_endian_swap64(cast(u64)bits); break;
+ }
+ }
+
+ res.value = LLVMConstInt(lb_type(m, original_type), bits, false);
+ return res;
+ } else {
+ return lb_const_nil(m, original_type);
+ }
+ break;
+ case ExactValue_Procedure:
+ {
+ Ast *expr = value.value_procedure;
+ GB_ASSERT(expr != nullptr);
+ if (expr->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<lbValue>(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<lbValue>(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<lbValue>(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<lbValue>(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<lbValue>(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<lbValue>(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<lbValue> 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<lbValue> lb_value_to_array(lbProcedure *p, lbValue value) {
+ Array<lbValue> 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<lbValue>(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<lbValue>(heap_allocator(), 1);
+ array[0] = value;
+ }
+ return array;
+}
+
+
+
+lbValue lb_emit_call_internal(lbProcedure *p, lbValue value, lbValue return_ptr, Array<lbValue> 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<lbValue> 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<lbValue> 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<lbValue>(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<lbValue> 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<lbValue>(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<lbValue>(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<lbValue>(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<lbValue>(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<lbValue>(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<lbValue>(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<lbValue>(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<lbValue>(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<lbValue>(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<lbValue>(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<lbValue>(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<lbValue>(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<lbValue>(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<lbValue>(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<lbValue>(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<lbValue>(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<lbValue>(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<lbValue>(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<lbValue>(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<lbValue>(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<lbCompoundLitElemTempData>(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<lbCompoundLitElemTempData>(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<lbCompoundLitElemTempData>(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<lbValue>(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<lbValue>(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<GlobalVariable>(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(&params->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<LLVMTypeRef> types; // Key: Type *
+
+ Map<lbValue> values; // Key: Entity *
+ Map<lbValue> members; // Key: String
+ Map<lbProcedure *> procedures; // Key: String
+ Map<Entity *> procedure_values; // Key: LLVMValueRef
+
+ Map<LLVMValueRef> const_strings; // Key: String
+
+ Map<lbProcedure *> anonymous_proc_lits; // Key: Ast *
+
+ lbAddr global_default_context;
+
+ u32 global_array_index;
+ u32 global_generated_index;
+ u32 nested_type_name_guid;
+
+ Array<lbProcedure *> procedures_to_generate;
+ Array<String> foreign_library_paths;
+
+
+
+ LLVMDIBuilderRef debug_builder;
+ LLVMMetadataRef debug_compile_unit;
+ Map<LLVMMetadataRef> debug_values; // Key: Pointer
+};
+
+struct lbGenerator {
+ lbModule module;
+ CheckerInfo *info;
+
+ Array<String> output_object_paths;
+ String output_base;
+ String output_name;
+};
+
+
+struct lbBlock {
+ LLVMBasicBlockRef block;
+ Scope *scope;
+ isize scope_index;
+ bool appended;
+
+ Array<lbBlock *> preds;
+ Array<lbBlock *> 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<lbValue> 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<lbProcedure *> 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<lbValue> params;
+ Array<lbDefer> defer_stmts;
+ Array<lbBlock *> blocks;
+ Array<lbBranchBlocks> branch_blocks;
+ Scope * curr_scope;
+ i32 scope_index;
+ lbBlock * decl_block;
+ lbBlock * entry_block;
+ lbBlock * curr_block;
+ lbTargetList * target_list;
+
+ Array<lbContextData> 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<Ast *> 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<lbValue> 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<lbValue> 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<String> 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<String> 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<String> 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<String> 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 API Code Gen"));
+ lbGenerator gen = {};
+ if (!lb_init_generator(&gen, &checker)) {
+ return 1;
+ }
+ lb_generate_code(&gen);
- timings_start_section(timings, str_lit("llvm ir gen"));
- ir_gen_tree(&ir_gen);
+ i32 linker_stage_exit_count = linker_stage(&gen);
+ if (linker_stage_exit_count != 0) {
+ return linker_stage_exit_count;
+ }
- timings_start_section(timings, str_lit("llvm ir opt tree"));
- ir_opt_tree(&ir_gen);
+ if (build_context.show_timings) {
+ show_timings(&checker, timings);
+ }
- timings_start_section(timings, str_lit("llvm ir print"));
- print_llvm_ir(&ir_gen);
+ remove_temp_files(gen.output_base);
+ if (run_output) {
+ #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
+ //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
+ }
- String output_name = ir_gen.output_name;
- String output_base = ir_gen.output_base;
+ 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));
- build_context.optimization_level = gb_clamp(build_context.optimization_level, 0, 3);
- i32 exit_code = 0;
+ timings_start_section(timings, str_lit("llvm ir gen"));
+ ir_gen_tree(&ir_gen);
- 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 ir opt tree"));
+ ir_opt_tree(&ir_gen);
- timings_start_section(timings, str_lit("llvm-llc"));
- exit_code = exec_llvm_llc(output_base);
- if (exit_code != 0) {
- return exit_code;
- }
+ timings_start_section(timings, str_lit("llvm ir print"));
+ print_llvm_ir(&ir_gen);
- 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};
+ String output_name = ir_gen.output_name;
+ String output_base = ir_gen.output_base;
- char const *output_ext = "exe";
- gbString link_settings = gb_string_make_reserve(heap_allocator(), 256);
- defer (gb_string_free(link_settings));
+ build_context.optimization_level = gb_clamp(build_context.optimization_level, 0, 3);
+ i32 exit_code = 0;
- // 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();
+ timings_start_section(timings, str_lit("llvm-opt"));
+ exit_code = exec_llvm_opt(output_base);
+ if (exit_code != 0) {
+ return exit_code;
+ }
- if (find_result.windows_sdk_version == 0) {
- gb_printf_err("Windows SDK not found.\n");
- return 1;
+ timings_start_section(timings, str_lit("llvm-llc"));
+ exit_code = exec_llvm_llc(output_base);
+ if (exit_code != 0) {
+ return exit_code;
}
- // 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);
+ 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"));
- 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);
- }
+ gbString lib_str = gb_string_make(heap_allocator(), "");
+ defer (gb_string_free(lib_str));
+ char lib_str_buf[1024] = {0};
- 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);
- }
+ 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 (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 (find_result.windows_sdk_version == 0) {
+ gb_printf_err("Windows SDK not found.\n");
+ return 1;
+ }
- if (build_context.pdb_filepath != "") {
- link_settings = gb_string_append_fmt(link_settings, " /PDB:%.*s", LIT(build_context.pdb_filepath));
- }
+ // 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);
- 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");
- }
+ 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);
+ }
- if (ir_gen.module.generate_debug_info) {
- link_settings = gb_string_append_fmt(link_settings, " /DEBUG");
- }
+ 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);
+ }
- 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;
- }
+ 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");
+ }
- 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
- );
+ 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",
- "\"%.*slink.exe\" \"%.*s.obj\" -OUT:\"%.*s.%s\" %s "
+ "\"%.*s\\bin\\lld-link\" \"%.*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,
+ LIT(build_context.ODIN_ROOT),
+ 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 (exit_code != 0) {
+ return exit_code;
+ }
- 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"));
+ if (build_context.show_timings) {
+ show_timings(&checker, timings);
+ }
- // 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);
+ remove_temp_files(output_base);
- // 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));
+ 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
+ }
- for_array(i, ir_gen.module.foreign_library_paths) {
- String lib = ir_gen.module.foreign_library_paths[i];
+ // 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 = "";
+ }
- // 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));
+ 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);
}
- #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";
+ linker = "ld";
#else
- output_ext = STR_LIT(".so");
- link_settings = "-shared";
+ // 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
- } 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);
+ 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)
- 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 (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;
+ if (exit_code != 0) {
+ return exit_code;
+ }
}
- }
- #endif
+ #endif
- if (build_context.show_timings) {
- show_timings(&checker, timings);
- }
+ if (build_context.show_timings) {
+ show_timings(&checker, timings);
+ }
- remove_temp_files(output_base);
+ 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));
+ 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
}
- #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<Ast *> 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<Ast *> 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;
}
}