mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Allow use of pthreads to parallelize codegen.
This commit is contained in:
committed by
Christoffer Lerno
parent
f7919edb35
commit
15a65d0c97
@@ -3,9 +3,15 @@
|
||||
// a copy of which can be found in the LICENSE file.
|
||||
|
||||
#include "compiler_internal.h"
|
||||
#include "../build/build_options.h"
|
||||
#include <unistd.h>
|
||||
|
||||
#if PLATFORM_POSIX
|
||||
#include <pthread.h>
|
||||
#define USE_PTHREAD 1
|
||||
#else
|
||||
#define USE_PTHREAD 0
|
||||
#endif
|
||||
|
||||
GlobalContext global_context;
|
||||
BuildTarget active_target;
|
||||
|
||||
@@ -30,6 +36,7 @@ void compiler_init(const char *std_lib_dir)
|
||||
//compiler.lib_dir = find_lib_dir();
|
||||
//DEBUG_LOG("Found std library: %s", compiler.lib_dir);
|
||||
stable_init(&global_context.modules, 64);
|
||||
stable_init(&global_context.scratch_table, 32);
|
||||
global_context.module_list = NULL;
|
||||
global_context.generic_module_list = NULL;
|
||||
stable_init(&global_context.global_symbols, 0x1000);
|
||||
@@ -96,6 +103,12 @@ static inline void halt_on_error(void)
|
||||
if (global_context.errors_found > 0) exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
#if USE_PTHREAD
|
||||
void* compile_on_pthread(void *gencontext)
|
||||
{
|
||||
return (void *)llvm_codegen(gencontext);
|
||||
}
|
||||
#endif
|
||||
void compiler_compile(void)
|
||||
{
|
||||
Context **contexts = NULL;
|
||||
@@ -186,6 +199,7 @@ void compiler_compile(void)
|
||||
llvm_codegen_setup();
|
||||
|
||||
void **gen_contexts = malloc(source_count * sizeof(void *));
|
||||
|
||||
for (unsigned i = 0; i < source_count; i++)
|
||||
{
|
||||
Context *context = contexts[i];
|
||||
@@ -197,6 +211,7 @@ void compiler_compile(void)
|
||||
gen_contexts[i] = llvm_gen(context);
|
||||
}
|
||||
|
||||
|
||||
printf("-- AST/EXPR INFO -- \n");
|
||||
printf(" * Ast memory use: %llukb\n", (unsigned long long)ast_arena.allocated / 1024);
|
||||
printf(" * Decl memory use: %llukb\n", (unsigned long long)decl_arena.allocated / 1024);
|
||||
@@ -220,6 +235,22 @@ void compiler_compile(void)
|
||||
|
||||
const char **obj_files = NULL;
|
||||
|
||||
#if USE_PTHREAD
|
||||
pthread_t *threads = malloc(source_count * sizeof(threads));
|
||||
for (unsigned i = 0; i < source_count; i++)
|
||||
{
|
||||
if (!gen_contexts[i]) continue;
|
||||
pthread_create(&threads[i], NULL, &compile_on_pthread, gen_contexts[i]);
|
||||
}
|
||||
for (unsigned i = 0; i < source_count; i++)
|
||||
{
|
||||
void *file_name;
|
||||
pthread_join(threads[i], &file_name);
|
||||
assert(file_name || !create_exe);
|
||||
printf("Received result: %s\n", (char*)file_name);
|
||||
vec_add(obj_files, file_name);
|
||||
}
|
||||
#else
|
||||
for (unsigned i = 0; i < source_count; i++)
|
||||
{
|
||||
if (!gen_contexts[i]) continue;
|
||||
@@ -227,6 +258,7 @@ void compiler_compile(void)
|
||||
assert(file_name || !create_exe);
|
||||
vec_add(obj_files, file_name);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (create_exe)
|
||||
{
|
||||
|
||||
@@ -41,8 +41,8 @@ typedef struct
|
||||
#define INVALID_TOKEN_ID ((TokenId) { UINT32_MAX })
|
||||
#define INVALID_RANGE ((SourceSpan){ INVALID_TOKEN_ID, INVALID_TOKEN_ID })
|
||||
#define MAX_LOCALS 0xFFFF
|
||||
#define MAX_SCOPE_DEPTH 0xFF
|
||||
#define MAX_PATH 1024
|
||||
#define MAX_SCOPE_DEPTH 0x1000
|
||||
#define MAX_PATH 0x10000
|
||||
#define MAX_MACRO_NESTING 1024
|
||||
#define MAX_FUNCTION_SIGNATURE_SIZE 2048
|
||||
#define MAX_PARAMS 512
|
||||
@@ -1254,20 +1254,16 @@ typedef struct _Context
|
||||
int macro_nesting;
|
||||
};
|
||||
Decl **last_local;
|
||||
char path_scratch[MAX_PATH];
|
||||
struct {
|
||||
STable external_symbols;
|
||||
Decl **external_symbol_list;
|
||||
};
|
||||
STable scratch_table;
|
||||
Lexer lexer;
|
||||
Token tok;
|
||||
TokenId prev_tok;
|
||||
Token next_tok;
|
||||
TokenId docs_start;
|
||||
TokenId docs_end;
|
||||
Decl* locals[MAX_LOCALS];
|
||||
DynamicScope scopes[MAX_SCOPE_DEPTH];
|
||||
} Context;
|
||||
|
||||
typedef struct
|
||||
@@ -1284,13 +1280,12 @@ typedef struct
|
||||
bool in_test_mode : 1;
|
||||
unsigned errors_found;
|
||||
unsigned warnings_found;
|
||||
char path_scratch[MAX_PATH];
|
||||
Decl* locals[MAX_LOCALS];
|
||||
DynamicScope scopes[MAX_SCOPE_DEPTH];
|
||||
STable scratch_table;
|
||||
} GlobalContext;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
MODULE_SYMBOL_SEARCH_EXTERNAL,
|
||||
MODULE_SYMBOL_SEARCH_MODULE
|
||||
} ModuleSymbolSearch;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
@@ -1652,11 +1647,9 @@ void stable_clear(STable *table);
|
||||
|
||||
const char *symtab_add(const char *symbol, uint32_t len, uint32_t fnv1hash, TokenType *type);
|
||||
|
||||
void *llvm_target_machine_create(void);
|
||||
void target_setup(BuildTarget *build_target);
|
||||
int target_alloca_addr_space();
|
||||
void *target_data_layout();
|
||||
void *target_machine();
|
||||
void *target_target();
|
||||
|
||||
#define TOK2VARSTR(_token) _token.span.length, _token.start
|
||||
bool token_is_type(TokenType type);
|
||||
|
||||
@@ -11,7 +11,6 @@ Context *context_create(File *file)
|
||||
context->file = file;
|
||||
stable_init(&context->local_symbols, 256);
|
||||
stable_init(&context->external_symbols, 256);
|
||||
stable_init(&context->scratch_table, 32);
|
||||
return context;
|
||||
}
|
||||
|
||||
|
||||
@@ -49,6 +49,8 @@ static void gencontext_init(GenContext *context, Context *ast_context)
|
||||
static void gencontext_destroy(GenContext *context)
|
||||
{
|
||||
LLVMContextDispose(context->context);
|
||||
LLVMDisposeTargetData(context->target_data);
|
||||
LLVMDisposeTargetMachine(context->machine);
|
||||
free(context);
|
||||
}
|
||||
|
||||
@@ -426,12 +428,12 @@ void gencontext_emit_object_file(GenContext *context)
|
||||
{
|
||||
char *err = "";
|
||||
LLVMSetTarget(context->module, platform_target.target_triple);
|
||||
char *layout = LLVMCopyStringRepOfTargetData(target_data_layout());
|
||||
char *layout = LLVMCopyStringRepOfTargetData(context->target_data);
|
||||
LLVMSetDataLayout(context->module, layout);
|
||||
LLVMDisposeMessage(layout);
|
||||
|
||||
// Generate .o or .obj file
|
||||
if (LLVMTargetMachineEmitToFile(target_machine(), context->module, context->object_filename, LLVMObjectFile, &err))
|
||||
if (LLVMTargetMachineEmitToFile(context->machine, context->module, context->object_filename, LLVMObjectFile, &err))
|
||||
{
|
||||
error_exit("Could not emit object file: %s", err);
|
||||
}
|
||||
@@ -893,8 +895,8 @@ const char *llvm_codegen(void *context)
|
||||
LLVMPassManagerBuilderUseInlinerWithThreshold(pass_manager_builder, get_inlining_threshold());
|
||||
LLVMPassManagerRef pass_manager = LLVMCreatePassManager();
|
||||
LLVMPassManagerRef function_pass_manager = LLVMCreateFunctionPassManagerForModule(module);
|
||||
LLVMAddAnalysisPasses(target_machine(), function_pass_manager);
|
||||
LLVMAddAnalysisPasses(target_machine(), pass_manager);
|
||||
LLVMAddAnalysisPasses(c->machine, function_pass_manager);
|
||||
LLVMAddAnalysisPasses(c->machine, pass_manager);
|
||||
LLVMPassManagerBuilderPopulateModulePassManager(pass_manager_builder, pass_manager);
|
||||
LLVMPassManagerBuilderPopulateFunctionPassManager(pass_manager_builder, function_pass_manager);
|
||||
|
||||
@@ -1017,14 +1019,14 @@ void llvm_attribute_add_string(GenContext *context, LLVMValueRef value_to_add_at
|
||||
LLVMAddAttributeAtIndex(value_to_add_attribute_to, index, llvm_attr);
|
||||
}
|
||||
|
||||
unsigned llvm_abi_size(LLVMTypeRef type)
|
||||
unsigned llvm_abi_size(GenContext *c, LLVMTypeRef type)
|
||||
{
|
||||
return LLVMABISizeOfType(target_data_layout(), type);
|
||||
return LLVMABISizeOfType(c->target_data, type);
|
||||
}
|
||||
|
||||
AlignSize llvm_abi_alignment(LLVMTypeRef type)
|
||||
AlignSize llvm_abi_alignment(GenContext *c, LLVMTypeRef type)
|
||||
{
|
||||
return (AlignSize)LLVMABIAlignmentOfType(target_data_layout(), type);
|
||||
return (AlignSize)LLVMABIAlignmentOfType(c->target_data, type);
|
||||
}
|
||||
|
||||
void llvm_store_bevalue_aligned(GenContext *c, LLVMValueRef destination, BEValue *value, AlignSize alignment)
|
||||
@@ -1111,16 +1113,16 @@ void llvm_emit_memcpy_to_decl(GenContext *c, Decl *decl, LLVMValueRef source, un
|
||||
llvm_emit_memcpy(c, decl->backend_ref, decl->alignment, source, source_alignment, type_size(decl->type));
|
||||
}
|
||||
|
||||
LLVMValueRef llvm_emit_load_aligned(GenContext *context, LLVMTypeRef type, LLVMValueRef pointer, AlignSize alignment, const char *name)
|
||||
LLVMValueRef llvm_emit_load_aligned(GenContext *c, LLVMTypeRef type, LLVMValueRef pointer, AlignSize alignment, const char *name)
|
||||
{
|
||||
LLVMValueRef value = LLVMBuildLoad2(context->builder, type, pointer, name);
|
||||
llvm_set_alignment(value, alignment ?: llvm_abi_alignment(type));
|
||||
LLVMValueRef value = LLVMBuildLoad2(c->builder, type, pointer, name);
|
||||
llvm_set_alignment(value, alignment ?: llvm_abi_alignment(c, type));
|
||||
return value;
|
||||
}
|
||||
|
||||
unsigned llvm_store_size(LLVMTypeRef type)
|
||||
unsigned llvm_store_size(GenContext *c, LLVMTypeRef type)
|
||||
{
|
||||
return LLVMStoreSizeOfType(target_data_layout(), type);
|
||||
return LLVMStoreSizeOfType(c->target_data, type);
|
||||
}
|
||||
|
||||
void llvm_set_error_exit(GenContext *c, LLVMBasicBlockRef block)
|
||||
|
||||
@@ -59,39 +59,39 @@ static inline LLVMValueRef llvm_emit_add_int(GenContext *c, Type *type, LLVMValu
|
||||
return LLVMBuildAdd(c->builder, left, right, "add");
|
||||
}
|
||||
|
||||
LLVMValueRef llvm_emit_coerce(GenContext *context, LLVMTypeRef coerced, BEValue *value, Type *original_type)
|
||||
LLVMValueRef llvm_emit_coerce(GenContext *c, LLVMTypeRef coerced, BEValue *value, Type *original_type)
|
||||
{
|
||||
LLVMValueRef cast;
|
||||
AlignSize target_alignment = llvm_abi_alignment(coerced);
|
||||
AlignSize max_align = MAX(value->alignment, llvm_abi_alignment(coerced));
|
||||
AlignSize target_alignment = llvm_abi_alignment(c, coerced);
|
||||
AlignSize max_align = MAX(value->alignment, llvm_abi_alignment(c, coerced));
|
||||
|
||||
// If we are loading something with greater alignment than what we have, we cannot directly memcpy.
|
||||
if (llvm_value_is_addr(value) && value->alignment < target_alignment)
|
||||
{
|
||||
// So load it instead.
|
||||
llvm_value_rvalue(context, value);
|
||||
llvm_value_rvalue(c, value);
|
||||
}
|
||||
|
||||
// In this case we have something nicely aligned, so we just do a cast.
|
||||
if (llvm_value_is_addr(value))
|
||||
{
|
||||
cast = LLVMBuildBitCast(context->builder, value->value, LLVMPointerType(coerced, 0), "");
|
||||
cast = LLVMBuildBitCast(c->builder, value->value, LLVMPointerType(coerced, 0), "");
|
||||
}
|
||||
else
|
||||
{
|
||||
cast = llvm_emit_alloca(context, coerced, max_align, "coerce");
|
||||
LLVMValueRef target = LLVMBuildBitCast(context->builder, cast, llvm_get_ptr_type(context, value->type), "");
|
||||
llvm_store_bevalue_aligned(context, target, value, max_align);
|
||||
cast = llvm_emit_alloca(c, coerced, max_align, "coerce");
|
||||
LLVMValueRef target = LLVMBuildBitCast(c->builder, cast, llvm_get_ptr_type(c, value->type), "");
|
||||
llvm_store_bevalue_aligned(c, target, value, max_align);
|
||||
}
|
||||
return llvm_emit_load_aligned(context, coerced, cast, max_align, "coerced");
|
||||
return llvm_emit_load_aligned(c, coerced, cast, max_align, "coerced");
|
||||
}
|
||||
|
||||
void llvm_emit_convert_value_from_coerced(GenContext *context, BEValue *result, LLVMTypeRef coerced, LLVMValueRef value, Type *original_type)
|
||||
void llvm_emit_convert_value_from_coerced(GenContext *c, BEValue *result, LLVMTypeRef coerced, LLVMValueRef value, Type *original_type)
|
||||
{
|
||||
unsigned max_align = MAX(llvm_abi_alignment(coerced), type_abi_alignment(original_type));
|
||||
LLVMValueRef temp = llvm_emit_alloca(context, coerced, max_align, "coerce_temp");
|
||||
llvm_store_aligned(context, temp, value, max_align);
|
||||
temp = LLVMBuildBitCast(context->builder, temp, llvm_get_type(context, type_get_ptr(original_type)), "");
|
||||
unsigned max_align = MAX(llvm_abi_alignment(c, coerced), type_abi_alignment(original_type));
|
||||
LLVMValueRef temp = llvm_emit_alloca(c, coerced, max_align, "coerce_temp");
|
||||
llvm_store_aligned(c, temp, value, max_align);
|
||||
temp = LLVMBuildBitCast(c->builder, temp, llvm_get_type(c, type_get_ptr(original_type)), "");
|
||||
llvm_value_set_address_align(result, temp, original_type, max_align);
|
||||
}
|
||||
|
||||
@@ -1686,7 +1686,7 @@ static inline LLVMValueRef llvm_fixup_shift_rhs(GenContext *c, LLVMValueRef left
|
||||
LLVMTypeRef left_type = LLVMTypeOf(left);
|
||||
LLVMTypeRef right_type = LLVMTypeOf(right);
|
||||
if (left_type == right_type) return right;
|
||||
if (LLVMStoreSizeOfType(platform_target.target, left_type) < LLVMStoreSizeOfType(platform_target.target, right_type))
|
||||
if (LLVMStoreSizeOfType(c->target_data, left_type) < LLVMStoreSizeOfType(c->target_data, right_type))
|
||||
{
|
||||
return LLVMBuildTrunc(c->builder, right, left_type, "");
|
||||
}
|
||||
@@ -2447,7 +2447,7 @@ void gencontext_emit_call_intrinsic_expr(GenContext *c, BEValue *be_value, Expr
|
||||
UNREACHABLE
|
||||
}
|
||||
|
||||
void llvm_emit_parameter(GenContext *context, LLVMValueRef **args, ABIArgInfo *info, BEValue *be_value, Type *type)
|
||||
void llvm_emit_parameter(GenContext *c, LLVMValueRef **args, ABIArgInfo *info, BEValue *be_value, Type *type)
|
||||
{
|
||||
switch (info->kind)
|
||||
{
|
||||
@@ -2458,100 +2458,100 @@ void llvm_emit_parameter(GenContext *context, LLVMValueRef **args, ABIArgInfo *i
|
||||
{
|
||||
// If we want we could optimize for structs by doing it by reference here.
|
||||
unsigned alignment = info->indirect.realignment ?: type_abi_alignment(type);
|
||||
LLVMValueRef indirect = llvm_emit_alloca(context,
|
||||
llvm_get_type(context, type),
|
||||
LLVMValueRef indirect = llvm_emit_alloca(c,
|
||||
llvm_get_type(c, type),
|
||||
alignment,
|
||||
"indirectarg");
|
||||
llvm_store_bevalue_aligned(context, indirect, be_value, alignment);
|
||||
llvm_store_bevalue_aligned(c, indirect, be_value, alignment);
|
||||
vec_add(*args, indirect);
|
||||
return;
|
||||
}
|
||||
case ABI_ARG_DIRECT_COERCE:
|
||||
{
|
||||
LLVMTypeRef coerce_type = llvm_get_coerce_type(context, info);
|
||||
if (!coerce_type || coerce_type == llvm_get_type(context, type))
|
||||
LLVMTypeRef coerce_type = llvm_get_coerce_type(c, info);
|
||||
if (!coerce_type || coerce_type == llvm_get_type(c, type))
|
||||
{
|
||||
vec_add(*args, llvm_value_rvalue_store(context, be_value));
|
||||
vec_add(*args, llvm_value_rvalue_store(c, be_value));
|
||||
return;
|
||||
}
|
||||
if (!abi_info_should_flatten(info))
|
||||
{
|
||||
vec_add(*args, llvm_emit_coerce(context, coerce_type, be_value, type));
|
||||
vec_add(*args, llvm_emit_coerce(c, coerce_type, be_value, type));
|
||||
return;
|
||||
}
|
||||
LLVMValueRef cast;
|
||||
AlignSize target_alignment = llvm_abi_alignment(coerce_type);
|
||||
AlignSize max_align = MAX((be_value->alignment), llvm_abi_alignment(coerce_type));
|
||||
AlignSize target_alignment = llvm_abi_alignment(c, coerce_type);
|
||||
AlignSize max_align = MAX((be_value->alignment), llvm_abi_alignment(c, coerce_type));
|
||||
|
||||
// If we are loading something with greater alignment than what we have, we cannot directly memcpy.
|
||||
if (llvm_value_is_addr(be_value) && be_value->alignment < target_alignment)
|
||||
{
|
||||
// So load it instead.
|
||||
llvm_value_rvalue(context, be_value);
|
||||
llvm_value_rvalue(c, be_value);
|
||||
}
|
||||
|
||||
// In this case we have something nicely aligned, so we just do a cast.
|
||||
if (llvm_value_is_addr(be_value))
|
||||
{
|
||||
cast = LLVMBuildBitCast(context->builder, be_value->value, LLVMPointerType(coerce_type, 0), "");
|
||||
cast = LLVMBuildBitCast(c->builder, be_value->value, LLVMPointerType(coerce_type, 0), "");
|
||||
}
|
||||
else
|
||||
{
|
||||
cast = llvm_emit_alloca(context, coerce_type, max_align, "coerce");
|
||||
LLVMValueRef target = LLVMBuildBitCast(context->builder, cast, llvm_get_ptr_type(context, type), "");
|
||||
llvm_store_bevalue_aligned(context, target, be_value, max_align);
|
||||
cast = llvm_emit_alloca(c, coerce_type, max_align, "coerce");
|
||||
LLVMValueRef target = LLVMBuildBitCast(c->builder, cast, llvm_get_ptr_type(c, type), "");
|
||||
llvm_store_bevalue_aligned(c, target, be_value, max_align);
|
||||
}
|
||||
LLVMTypeRef element = llvm_abi_type(context, info->direct_coerce.type);
|
||||
LLVMTypeRef element = llvm_abi_type(c, info->direct_coerce.type);
|
||||
for (unsigned idx = 0; idx < info->direct_coerce.elements; idx++)
|
||||
{
|
||||
LLVMValueRef element_ptr = LLVMBuildStructGEP2(context->builder, coerce_type, cast, idx, "");
|
||||
LLVMValueRef element_ptr = LLVMBuildStructGEP2(c->builder, coerce_type, cast, idx, "");
|
||||
vec_add(*args,
|
||||
llvm_emit_load_aligned(context, element, element_ptr, llvm_abi_alignment(element), ""));
|
||||
llvm_emit_load_aligned(c, element, element_ptr, llvm_abi_alignment(c, element), ""));
|
||||
}
|
||||
return;
|
||||
}
|
||||
case ABI_ARG_DIRECT_PAIR:
|
||||
{
|
||||
llvm_value_addr(context, be_value);
|
||||
llvm_value_addr(c, be_value);
|
||||
printf("Handle invalid alignment");
|
||||
// Here we do the following transform:
|
||||
// struct -> { lo, hi } -> lo, hi
|
||||
LLVMTypeRef lo = llvm_abi_type(context, info->direct_pair.lo);
|
||||
LLVMTypeRef hi = llvm_abi_type(context, info->direct_pair.hi);
|
||||
LLVMTypeRef struct_type = llvm_get_coerce_type(context, info);
|
||||
LLVMValueRef cast = LLVMBuildBitCast(context->builder, be_value->value, llvm_get_ptr_type(context, type), "casttemp");
|
||||
LLVMTypeRef lo = llvm_abi_type(c, info->direct_pair.lo);
|
||||
LLVMTypeRef hi = llvm_abi_type(c, info->direct_pair.hi);
|
||||
LLVMTypeRef struct_type = llvm_get_coerce_type(c, info);
|
||||
LLVMValueRef cast = LLVMBuildBitCast(c->builder, be_value->value, llvm_get_ptr_type(c, type), "casttemp");
|
||||
// Get the lo value.
|
||||
LLVMValueRef lo_ptr = LLVMBuildStructGEP2(context->builder, struct_type, cast, 0, "lo");
|
||||
vec_add(*args, llvm_emit_load_aligned(context, lo, lo_ptr, llvm_abi_alignment(lo), "lo"));
|
||||
LLVMValueRef lo_ptr = LLVMBuildStructGEP2(c->builder, struct_type, cast, 0, "lo");
|
||||
vec_add(*args, llvm_emit_load_aligned(c, lo, lo_ptr, llvm_abi_alignment(c, lo), "lo"));
|
||||
// Get the hi value.
|
||||
LLVMValueRef hi_ptr = LLVMBuildStructGEP2(context->builder, struct_type, cast, 1, "hi");
|
||||
vec_add(*args, llvm_emit_load_aligned(context, hi, hi_ptr, llvm_abi_alignment(hi), "hi"));
|
||||
LLVMValueRef hi_ptr = LLVMBuildStructGEP2(c->builder, struct_type, cast, 1, "hi");
|
||||
vec_add(*args, llvm_emit_load_aligned(c, hi, hi_ptr, llvm_abi_alignment(c, hi), "hi"));
|
||||
return;
|
||||
}
|
||||
case ABI_ARG_EXPAND_COERCE:
|
||||
{
|
||||
// Move this to an address (if needed)
|
||||
llvm_value_addr(context, be_value);
|
||||
LLVMTypeRef coerce_type = llvm_get_coerce_type(context, info);
|
||||
LLVMValueRef temp = LLVMBuildBitCast(context->builder, be_value->value, LLVMPointerType(coerce_type, 0), "coerce");
|
||||
LLVMValueRef gep_first = LLVMBuildStructGEP2(context->builder, coerce_type, temp, info->coerce_expand.lo_index, "first");
|
||||
vec_add(*args, LLVMBuildLoad2(context->builder, llvm_abi_type(context, info->coerce_expand.lo), gep_first, ""));
|
||||
llvm_value_addr(c, be_value);
|
||||
LLVMTypeRef coerce_type = llvm_get_coerce_type(c, info);
|
||||
LLVMValueRef temp = LLVMBuildBitCast(c->builder, be_value->value, LLVMPointerType(coerce_type, 0), "coerce");
|
||||
LLVMValueRef gep_first = LLVMBuildStructGEP2(c->builder, coerce_type, temp, info->coerce_expand.lo_index, "first");
|
||||
vec_add(*args, LLVMBuildLoad2(c->builder, llvm_abi_type(c, info->coerce_expand.lo), gep_first, ""));
|
||||
if (info->coerce_expand.hi)
|
||||
{
|
||||
LLVMValueRef gep_second = LLVMBuildStructGEP2(context->builder, coerce_type, temp, info->coerce_expand.hi_index, "second");
|
||||
vec_add(*args, LLVMBuildLoad2(context->builder, llvm_abi_type(context, info->coerce_expand.hi), gep_second, ""));
|
||||
LLVMValueRef gep_second = LLVMBuildStructGEP2(c->builder, coerce_type, temp, info->coerce_expand.hi_index, "second");
|
||||
vec_add(*args, LLVMBuildLoad2(c->builder, llvm_abi_type(c, info->coerce_expand.hi), gep_second, ""));
|
||||
}
|
||||
return;
|
||||
}
|
||||
case ABI_ARG_EXPAND:
|
||||
{
|
||||
// Move this to an address (if needed)
|
||||
llvm_value_addr(context, be_value);
|
||||
llvm_expand_type_to_args(context, type, be_value->value, args);
|
||||
llvm_value_addr(c, be_value);
|
||||
llvm_expand_type_to_args(c, type, be_value->value, args);
|
||||
// Expand the padding here.
|
||||
if (info->expand.padding_type)
|
||||
{
|
||||
vec_add(*args, LLVMGetUndef(llvm_get_type(context, info->expand.padding_type)));
|
||||
vec_add(*args, LLVMGetUndef(llvm_get_type(c, info->expand.padding_type)));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -162,12 +162,12 @@ static inline void llvm_process_parameter_value(GenContext *c, Decl *decl, unsig
|
||||
// Point to the lo value.
|
||||
LLVMValueRef lo_ptr = LLVMBuildStructGEP2(c->builder, struct_type, cast, 0, "lo");
|
||||
// Store it in the struct.
|
||||
AlignSize lo_alignment = MIN(llvm_abi_alignment(lo), decl_alignment);
|
||||
AlignSize lo_alignment = MIN(llvm_abi_alignment(c, lo), decl_alignment);
|
||||
llvm_store_aligned(c, lo_ptr, llvm_get_next_param(c, index), lo_alignment);
|
||||
// Point to the hi value.
|
||||
LLVMValueRef hi_ptr = LLVMBuildStructGEP2(c->builder, struct_type, cast, 1, "hi");
|
||||
// Store it in the struct.
|
||||
AlignSize hi_alignment = MIN(llvm_abi_alignment(hi), decl_alignment);
|
||||
AlignSize hi_alignment = MIN(llvm_abi_alignment(c, hi), decl_alignment);
|
||||
llvm_store_aligned(c, hi_ptr, llvm_get_next_param(c, index), decl_alignment);
|
||||
return;
|
||||
}
|
||||
@@ -199,7 +199,7 @@ static inline void llvm_process_parameter_value(GenContext *c, Decl *decl, unsig
|
||||
LLVMValueRef element_ptr = LLVMBuildStructGEP2(c->builder, coerce_type, cast, idx, "");
|
||||
LLVMValueRef value = llvm_get_next_param(c, index);
|
||||
|
||||
llvm_store_aligned(c, element_ptr, value, MIN(llvm_abi_alignment(element_type), decl->alignment));
|
||||
llvm_store_aligned(c, element_ptr, value, MIN(llvm_abi_alignment(c, element_type), decl->alignment));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -63,6 +63,8 @@ typedef struct
|
||||
typedef struct
|
||||
{
|
||||
LLVMModuleRef module;
|
||||
LLVMTargetMachineRef machine;
|
||||
LLVMTargetDataRef target_data;
|
||||
LLVMContextRef context;
|
||||
LLVMValueRef function;
|
||||
LLVMValueRef alloca_point;
|
||||
@@ -193,8 +195,8 @@ void llvm_value_struct_gep(GenContext *c, BEValue *element, BEValue *struct_poin
|
||||
LLVMValueRef llvm_value_rvalue_store(GenContext *c, BEValue *value);
|
||||
|
||||
LLVMTypeRef llvm_abi_type(GenContext *c, AbiType *type);
|
||||
unsigned llvm_abi_size(LLVMTypeRef type);
|
||||
AlignSize llvm_abi_alignment(LLVMTypeRef type);
|
||||
unsigned llvm_abi_size(GenContext *c, LLVMTypeRef type);
|
||||
AlignSize llvm_abi_alignment(GenContext *c, LLVMTypeRef type);
|
||||
void llvm_attribute_add_range(GenContext *c, LLVMValueRef value_to_add_attribute_to, unsigned attribute_id, int index_start, int index_end);
|
||||
void llvm_attribute_add(GenContext *c, LLVMValueRef value_to_add_attribute_to, unsigned attribute_id, int index);
|
||||
void llvm_attribute_add_string(GenContext *c, LLVMValueRef value_to_add_attribute_to, const char *attribute, const char *value, int index);
|
||||
@@ -211,7 +213,7 @@ void llvm_emit_block(GenContext *c, LLVMBasicBlockRef next_block);
|
||||
void llvm_emit_br(GenContext *c, LLVMBasicBlockRef next_block);
|
||||
void llvm_emit_compound_stmt(GenContext *context, Ast *ast);
|
||||
void llvm_emit_and_set_decl_alloca(GenContext *c, Decl *decl);
|
||||
void llvm_emit_convert_value_from_coerced(GenContext *context, BEValue *result, LLVMTypeRef coerced, LLVMValueRef value, Type *original_type);
|
||||
void llvm_emit_convert_value_from_coerced(GenContext *c, BEValue *result, LLVMTypeRef coerced, LLVMValueRef value, Type *original_type);
|
||||
void llvm_emit_function_body(GenContext *context, Decl *decl);
|
||||
void llvm_emit_function_decl(GenContext *c, Decl *decl);
|
||||
LLVMValueRef llvm_emit_call_intrinsic(GenContext *c, unsigned intrinsic_id, LLVMTypeRef *types, unsigned type_count, LLVMValueRef *values, unsigned arg_count);
|
||||
@@ -230,7 +232,7 @@ LLVMValueRef llvm_emit_int_comparison(GenContext *c, Type *lhs_type, Type *rhs_t
|
||||
|
||||
LLVMValueRef llvm_emit_is_no_error_value(GenContext *c, BEValue *value);
|
||||
void llvm_emit_len_for_expr(GenContext *c, BEValue *be_value, BEValue *expr_to_len);
|
||||
LLVMValueRef llvm_emit_load_aligned(GenContext *context, LLVMTypeRef type, LLVMValueRef pointer, AlignSize alignment, const char *name);
|
||||
LLVMValueRef llvm_emit_load_aligned(GenContext *c, LLVMTypeRef type, LLVMValueRef pointer, AlignSize alignment, const char *name);
|
||||
void llvm_emit_local_var_alloca(GenContext *c, Decl *decl);
|
||||
void llvm_emit_expr(GenContext *c, BEValue *value, Expr *expr);
|
||||
LLVMValueRef llvm_emit_memclear_size_align(GenContext *c, LLVMValueRef ref, uint64_t size, unsigned align, bool bitcast);
|
||||
@@ -264,7 +266,7 @@ LLVMMetadataRef llvm_debug_current_scope(GenContext *context);
|
||||
bool llvm_emit_check_block_branch(GenContext *context);
|
||||
|
||||
|
||||
unsigned llvm_store_size(LLVMTypeRef type);
|
||||
unsigned llvm_store_size(GenContext *c, LLVMTypeRef type);
|
||||
void llvm_store_bevalue(GenContext *c, BEValue *destination, BEValue *value);
|
||||
void llvm_store_bevalue_raw(GenContext *c, BEValue *destination, LLVMValueRef raw_value);
|
||||
void llvm_store_bevalue_dest_aligned(GenContext *c, LLVMValueRef destination, BEValue *value);
|
||||
@@ -274,7 +276,7 @@ void llvm_store_aligned(GenContext *context, LLVMValueRef pointer, LLVMValueRef
|
||||
void llvm_store_aligned_decl(GenContext *context, Decl *decl, LLVMValueRef value);
|
||||
|
||||
LLVMTypeRef llvm_get_twostruct(GenContext *context, LLVMTypeRef lo, LLVMTypeRef hi);
|
||||
LLVMValueRef llvm_emit_coerce(GenContext *context, LLVMTypeRef coerced, BEValue *value, Type *original_type);
|
||||
LLVMValueRef llvm_emit_coerce(GenContext *c, LLVMTypeRef coerced, BEValue *value, Type *original_type);
|
||||
|
||||
static inline LLVMValueRef gencontext_emit_load(GenContext *c, Type *type, LLVMValueRef value)
|
||||
{
|
||||
|
||||
@@ -15,7 +15,9 @@ void gencontext_begin_module(GenContext *c)
|
||||
const char *full_path = c->ast_context->file->full_path;
|
||||
char *mangled_module_name = strformat("%s-%s", c->ast_context->module->name->module, c->ast_context->file->name);
|
||||
c->module = LLVMModuleCreateWithNameInContext(mangled_module_name, c->context);
|
||||
LLVMSetModuleDataLayout(c->module, target_data_layout());
|
||||
c->machine = llvm_target_machine_create();
|
||||
c->target_data = LLVMCreateTargetDataLayout(c->machine);
|
||||
LLVMSetModuleDataLayout(c->module, c->target_data);
|
||||
LLVMSetSourceFileName(c->module, full_path, strlen(c->ast_context->file->full_path));
|
||||
LLVMTypeRef options_type = LLVMInt8TypeInContext(c->context);
|
||||
|
||||
|
||||
@@ -257,7 +257,7 @@ static inline Decl *parse_ct_switch_top_level(Context *context)
|
||||
static inline Path *parse_module_path(Context *context)
|
||||
{
|
||||
assert(TOKEN_IS(TOKEN_IDENT));
|
||||
char *scratch_ptr = context->path_scratch;
|
||||
char *scratch_ptr = global_context.path_scratch;
|
||||
size_t offset = 0;
|
||||
SourceSpan span = source_span_from_token_id(context->tok.id);
|
||||
unsigned len = TOKLEN(context->tok);
|
||||
@@ -469,7 +469,7 @@ Path *parse_path_prefix(Context *context, bool *had_error)
|
||||
*had_error = false;
|
||||
if (!TOKEN_IS(TOKEN_IDENT) || context->next_tok.type != TOKEN_SCOPE) return NULL;
|
||||
|
||||
char *scratch_ptr = context->path_scratch;
|
||||
char *scratch_ptr = global_context.path_scratch;
|
||||
size_t offset = 0;
|
||||
|
||||
Path *path = CALLOCS(Path);
|
||||
|
||||
@@ -373,7 +373,7 @@ static inline Type *sema_analyse_function_signature(Context *context, FunctionSi
|
||||
SEMA_ERROR(signature->params[MAX_PARAMS], "Number of params exceeds %d which is unsupported.", MAX_PARAMS);
|
||||
return false;
|
||||
}
|
||||
STable *names = &context->scratch_table;
|
||||
STable *names = &global_context.scratch_table;
|
||||
stable_clear(names);
|
||||
|
||||
VECEACH(signature->params, i)
|
||||
@@ -1048,7 +1048,7 @@ static bool sema_analyse_parameterized_define(Context *c, Decl *decl, Module *mo
|
||||
parameter_count, vec_size(decl->define_decl.params));
|
||||
return false;
|
||||
}
|
||||
char *param_path = c->path_scratch;
|
||||
char *param_path = global_context.path_scratch;
|
||||
memcpy(param_path, module->name->module, module->name->len);
|
||||
unsigned offset = module->name->len;
|
||||
param_path[offset++] = '(';
|
||||
|
||||
@@ -126,7 +126,7 @@ Decl *sema_resolve_symbol(Context *context, const char *symbol, Path *path, Decl
|
||||
|
||||
if (context->current_scope)
|
||||
{
|
||||
Decl **first = &context->locals[0];
|
||||
Decl **first = &global_context.locals[0];
|
||||
if (context->macro_nesting) first = context->macro_locals_start;
|
||||
Decl **current = context->last_local - 1;
|
||||
while (current >= first)
|
||||
@@ -179,7 +179,7 @@ Decl *sema_resolve_symbol(Context *context, const char *symbol, Path *path, Decl
|
||||
|
||||
static inline bool sema_append_local(Context *context, Decl *decl)
|
||||
{
|
||||
if (context->last_local == &context->locals[MAX_LOCALS - 1])
|
||||
if (context->last_local == &global_context.locals[MAX_LOCALS - 1])
|
||||
{
|
||||
SEMA_ERROR(decl, "Reached the maximum number of locals.");
|
||||
return false;
|
||||
|
||||
@@ -182,9 +182,9 @@ void sema_analysis_pass_decls(Context *context)
|
||||
if (context->module->parameters) return;
|
||||
|
||||
DEBUG_LOG("Pass: Decl analysis %s", context->file->name);
|
||||
context->current_scope = &context->scopes[0];
|
||||
context->current_scope = &global_context.scopes[0];
|
||||
context->current_scope->scope_id = 0;
|
||||
context->last_local = &context->locals[0];
|
||||
context->last_local = &global_context.locals[0];
|
||||
VECEACH(context->enums, i)
|
||||
{
|
||||
sema_analyse_decl(context, context->enums[i]);
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
void context_push_scope_with_flags(Context *context, ScopeFlags flags)
|
||||
{
|
||||
if (context->current_scope == &context->scopes[MAX_SCOPE_DEPTH - 1])
|
||||
if (context->current_scope == &global_context.scopes[MAX_SCOPE_DEPTH - 1])
|
||||
{
|
||||
FATAL_ERROR("Too deeply nested scopes.");
|
||||
}
|
||||
@@ -67,7 +67,7 @@ static inline void context_pop_defers_to(Context *context, DeferList *list)
|
||||
|
||||
void context_pop_scope(Context *context)
|
||||
{
|
||||
assert(context->current_scope != &context->scopes[0]);
|
||||
assert(context->current_scope != &global_context.scopes[0]);
|
||||
context->last_local = context->current_scope->local_decl_start;
|
||||
|
||||
assert(context_start_defer(context) == context->current_scope->defer_last);
|
||||
@@ -114,7 +114,7 @@ static void context_pop_defers_and_replace_ast(Context *context, Ast *ast)
|
||||
|
||||
AstId context_start_defer(Context *context)
|
||||
{
|
||||
if (context->current_scope == context->scopes) return 0;
|
||||
if (context->current_scope == global_context.scopes) return 0;
|
||||
if (context->current_scope->in_defer != context->current_scope[-1].in_defer) return 0;
|
||||
return context->current_scope[-1].defer_last;
|
||||
}
|
||||
@@ -933,7 +933,7 @@ static DynamicScope *context_find_scope_by_id(Context *context, ScopeId scope_id
|
||||
while (1)
|
||||
{
|
||||
if (scope->scope_id == scope_id) return scope;
|
||||
assert(scope != &context->scopes[0]);
|
||||
assert(scope != &global_context.scopes[0]);
|
||||
scope--;
|
||||
}
|
||||
UNREACHABLE
|
||||
@@ -968,7 +968,7 @@ static inline Decl *sema_analyse_label(Context *context, Ast *stmt)
|
||||
|
||||
static bool context_labels_exist_in_scope(Context *context)
|
||||
{
|
||||
for (Decl **from = &context->locals[0]; from < context->last_local; from++)
|
||||
for (Decl **from = &global_context.locals[0]; from < context->last_local; from++)
|
||||
{
|
||||
if ((*from)->decl_kind == DECL_LABEL) return true;
|
||||
}
|
||||
@@ -1919,7 +1919,7 @@ bool sema_analyse_function_body(Context *context, Decl *func)
|
||||
FunctionSignature *signature = &func->func.function_signature;
|
||||
context->active_function_for_analysis = func;
|
||||
context->rtype = signature->rtype->type;
|
||||
context->current_scope = &context->scopes[0];
|
||||
context->current_scope = &global_context.scopes[0];
|
||||
context->current_scope->scope_id = 0;
|
||||
context->failable_return = signature->failable;
|
||||
|
||||
@@ -1929,9 +1929,8 @@ bool sema_analyse_function_body(Context *context, Decl *func)
|
||||
// Clear returns
|
||||
vec_resize(context->returns, 0);
|
||||
context->scope_id = 0;
|
||||
context->returns = NULL;
|
||||
context->expected_block_type = NULL;
|
||||
context->last_local = &context->locals[0];
|
||||
context->last_local = &global_context.locals[0];
|
||||
context->in_volatile_section = 0;
|
||||
context->macro_counter = 0;
|
||||
context->macro_nesting = 0;
|
||||
@@ -1942,13 +1941,13 @@ bool sema_analyse_function_body(Context *context, Decl *func)
|
||||
func->func.annotations = CALLOCS(FuncAnnotations);
|
||||
context_push_scope(context);
|
||||
Decl **params = signature->params;
|
||||
assert(context->current_scope == &context->scopes[1]);
|
||||
assert(context->current_scope == &global_context.scopes[1]);
|
||||
VECEACH(params, i)
|
||||
{
|
||||
if (!sema_add_local(context, params[i])) return false;
|
||||
}
|
||||
if (!sema_analyse_compound_statement_no_scope(context, func->func.body)) return false;
|
||||
assert(context->current_scope == &context->scopes[1]);
|
||||
assert(context->current_scope == &global_context.scopes[1]);
|
||||
if (!context->current_scope->jump_end)
|
||||
{
|
||||
Type *canonical_rtype = signature->rtype->type->canonical;
|
||||
|
||||
@@ -375,22 +375,6 @@ static char *arch_to_target_triple[ARCH_OS_TARGET_LAST + 1] = {
|
||||
|
||||
void target_destroy()
|
||||
{
|
||||
assert(platform_target.machine);
|
||||
LLVMDisposeTargetMachine(platform_target.machine);
|
||||
}
|
||||
|
||||
void *target_target()
|
||||
{
|
||||
return platform_target.target;
|
||||
}
|
||||
|
||||
void *target_machine()
|
||||
{
|
||||
return platform_target.machine;
|
||||
}
|
||||
void *target_data_layout()
|
||||
{
|
||||
return platform_target.llvm_data_layout;
|
||||
}
|
||||
|
||||
static bool arch_is_supported(ArchType arch)
|
||||
@@ -1046,38 +1030,54 @@ static unsigned os_target_pref_alignment_of_float(OsType os, ArchType arch, int
|
||||
UNREACHABLE
|
||||
}
|
||||
|
||||
void *llvm_target_machine_create(void)
|
||||
{
|
||||
char *err = NULL;
|
||||
LLVMTargetRef target = NULL;
|
||||
if (LLVMGetTargetFromTriple(platform_target.target_triple, &target, &err) != 0)
|
||||
{
|
||||
error_exit("Could not create target: %s for triple '%s'", err, platform_target.target_triple);
|
||||
// Usually we would dispose of err, but no need to do it due to exit.
|
||||
}
|
||||
void *result = LLVMCreateTargetMachine(target, platform_target.target_triple,
|
||||
platform_target.cpu ?: "", platform_target.features ?: "",
|
||||
(LLVMCodeGenOptLevel)platform_target.llvm_opt_level,
|
||||
(LLVMRelocMode)platform_target.llvm_reloc_mode, LLVMCodeModelDefault);
|
||||
if (!result) error_exit("Failed to create target machine.");
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
#define INITIALIZE_TARGET(X) do { \
|
||||
DEBUG_LOG("Initialize target: %s.", #X); \
|
||||
LLVMInitialize ## X ## AsmParser(); \
|
||||
LLVMInitialize ## X ## AsmPrinter(); \
|
||||
LLVMInitialize ## X ## TargetInfo(); \
|
||||
LLVMInitialize ## X ## Target(); \
|
||||
LLVMInitialize ## X ## Disassembler(); \
|
||||
LLVMInitialize ## X ## TargetMC(); \
|
||||
} while(0)
|
||||
|
||||
void target_setup(BuildTarget *target)
|
||||
{
|
||||
assert(!platform_target.target);
|
||||
INITIALIZE_TARGET(ARM);
|
||||
INITIALIZE_TARGET(AArch64);
|
||||
INITIALIZE_TARGET(RISCV);
|
||||
INITIALIZE_TARGET(WebAssembly);
|
||||
INITIALIZE_TARGET(X86);
|
||||
// To support more targets, add them above.
|
||||
|
||||
LLVMInitializeAllTargetInfos();
|
||||
LLVMInitializeAllTargetMCs();
|
||||
LLVMInitializeAllTargets();
|
||||
LLVMInitializeAllAsmPrinters();
|
||||
LLVMInitializeAllAsmParsers();
|
||||
|
||||
platform_target.target = NULL;
|
||||
|
||||
const char *triple;
|
||||
if (target->arch_os_target == ARCH_OS_TARGET_DEFAULT)
|
||||
{
|
||||
triple = LLVMGetDefaultTargetTriple();
|
||||
platform_target.target_triple = LLVMGetDefaultTargetTriple();
|
||||
}
|
||||
else
|
||||
{
|
||||
triple = arch_to_target_triple[target->arch_os_target];
|
||||
}
|
||||
|
||||
char *err = NULL;
|
||||
if (LLVMGetTargetFromTriple(triple, ((LLVMTargetRef *)&platform_target.target), &err) != 0)
|
||||
{
|
||||
error_exit("Could not create target: %s", err);
|
||||
// Usually we would dispose of err, but no need to do it due to exit.
|
||||
platform_target.target_triple = arch_to_target_triple[target->arch_os_target];
|
||||
}
|
||||
|
||||
platform_target.alloca_address_space = 0;
|
||||
|
||||
DEBUG_LOG("Target set to %s.", triple);
|
||||
// Create a specific target machine
|
||||
LLVMCodeGenOptLevel level;
|
||||
LLVMRelocMode reloc_mode = LLVMRelocDefault;
|
||||
@@ -1123,19 +1123,15 @@ void target_setup(BuildTarget *target)
|
||||
reloc_mode = LLVMRelocStatic;
|
||||
}
|
||||
|
||||
/*
|
||||
if (!opt->features)
|
||||
{
|
||||
opt->features = "";
|
||||
}*/
|
||||
if (!(platform_target.machine = LLVMCreateTargetMachine(platform_target.target, triple, "", "", level, reloc_mode,
|
||||
LLVMCodeModelDefault))) {
|
||||
error_exit("Failed to create target machine.");
|
||||
}
|
||||
DEBUG_LOG("Feature and CPU not checked.");
|
||||
|
||||
platform_target.llvm_data_layout = LLVMCreateTargetDataLayout(platform_target.machine);
|
||||
platform_target.llvm_opt_level = (int)level;
|
||||
platform_target.llvm_reloc_mode = (int)reloc_mode;
|
||||
DEBUG_LOG("Triple picked was %s.", platform_target.target_triple);
|
||||
|
||||
char *target_triple = LLVMGetTargetMachineTriple(platform_target.machine);
|
||||
LLVMTargetMachineRef machine = llvm_target_machine_create();
|
||||
char *target_triple = LLVMGetTargetMachineTriple(machine);
|
||||
LLVMDisposeTargetMachine(machine);
|
||||
|
||||
platform_target.target_triple = strdup(target_triple);
|
||||
platform_target.arch = arch_from_llvm_string(strtok(target_triple, "-"));
|
||||
@@ -1153,7 +1149,6 @@ void target_setup(BuildTarget *target)
|
||||
platform_target.float_abi = false;
|
||||
platform_target.little_endian = arch_little_endian(platform_target.arch);
|
||||
platform_target.width_pointer = arch_pointer_bit_width(platform_target.os, platform_target.arch);
|
||||
assert(platform_target.width_pointer == LLVMPointerSize(platform_target.llvm_data_layout) * 8);
|
||||
platform_target.alloca_address_space = 0;
|
||||
|
||||
// Todo PIC or no PIC depending on architecture.
|
||||
|
||||
@@ -235,10 +235,11 @@ typedef enum
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void *target;
|
||||
void *machine;
|
||||
void *llvm_data_layout;
|
||||
const char *target_triple;
|
||||
int llvm_opt_level;
|
||||
int llvm_reloc_mode;
|
||||
const char *features;
|
||||
const char *cpu;
|
||||
ArchType arch;
|
||||
OsType os;
|
||||
VendorType vendor;
|
||||
|
||||
Reference in New Issue
Block a user