mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Compilation is now done with each module compiled together.
This commit is contained in:
committed by
Christoffer Lerno
parent
15a65d0c97
commit
9b86b00834
@@ -54,10 +54,13 @@ void decl_set_external_name(Decl *decl)
|
||||
decl->external_name = decl->name;
|
||||
return;
|
||||
}
|
||||
char buffer[1024];
|
||||
uint32_t len = sprintf(buffer, "%s.%s", decl->module->name->module, decl->name ? decl->name : "anon");
|
||||
assert(len);
|
||||
scratch_buffer_clear();
|
||||
scratch_buffer_append(decl->module->name->module);
|
||||
scratch_buffer_append("::");
|
||||
scratch_buffer_append(decl->name ?: "anon");
|
||||
TokenType type = TOKEN_INVALID_TOKEN;
|
||||
const char *buffer = scratch_buffer_to_string();
|
||||
size_t len = global_context.scratch_buffer_len;
|
||||
decl->external_name = symtab_add(buffer, len, fnv1a(buffer, len), &type);
|
||||
}
|
||||
|
||||
|
||||
@@ -198,17 +198,16 @@ void compiler_compile(void)
|
||||
|
||||
llvm_codegen_setup();
|
||||
|
||||
void **gen_contexts = malloc(source_count * sizeof(void *));
|
||||
void **gen_contexts = malloc(module_count * sizeof(void *));
|
||||
|
||||
for (unsigned i = 0; i < source_count; i++)
|
||||
for (unsigned i = 0; i < module_count; i++)
|
||||
{
|
||||
Context *context = contexts[i];
|
||||
if (context->module->parameters)
|
||||
if (!modules[i]->contexts)
|
||||
{
|
||||
gen_contexts[i] = NULL;
|
||||
continue;
|
||||
}
|
||||
gen_contexts[i] = llvm_gen(context);
|
||||
gen_contexts[i] = llvm_gen(modules[i]);
|
||||
}
|
||||
|
||||
|
||||
@@ -236,8 +235,8 @@ 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++)
|
||||
pthread_t *threads = malloc(module_count * sizeof(threads));
|
||||
for (unsigned i = 0; i < module_count; i++)
|
||||
{
|
||||
if (!gen_contexts[i]) continue;
|
||||
pthread_create(&threads[i], NULL, &compile_on_pthread, gen_contexts[i]);
|
||||
@@ -247,11 +246,10 @@ void compiler_compile(void)
|
||||
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++)
|
||||
for (unsigned i = 0; i < module_count; i++)
|
||||
{
|
||||
if (!gen_contexts[i]) continue;
|
||||
const char *file_name = llvm_codegen(gen_contexts[i]);
|
||||
@@ -432,3 +430,37 @@ void compiler_register_public_symbol(Decl *decl)
|
||||
prev = stable_get(sub_module_space, decl->name);
|
||||
stable_set(sub_module_space, decl->name, prev ? poisoned_decl : decl);
|
||||
}
|
||||
|
||||
void scratch_buffer_clear(void)
|
||||
{
|
||||
global_context.scratch_buffer_len = 0;
|
||||
}
|
||||
|
||||
void scratch_buffer_append_len(const char *string, size_t len)
|
||||
{
|
||||
if (len + global_context.scratch_buffer_len > MAX_STRING_BUFFER - 1)
|
||||
{
|
||||
error_exit("Scratch buffer size (%d chars) exceeded", MAX_STRING_BUFFER - 1);
|
||||
}
|
||||
memcpy(global_context.scratch_buffer + global_context.scratch_buffer_len, string, len);
|
||||
global_context.scratch_buffer_len += len;
|
||||
}
|
||||
|
||||
void scratch_buffer_append(const char *string)
|
||||
{
|
||||
scratch_buffer_append_len(string, strlen(string));
|
||||
}
|
||||
|
||||
void scratch_buffer_append_char(char c)
|
||||
{
|
||||
if (global_context.scratch_buffer_len + 1 > MAX_STRING_BUFFER - 1)
|
||||
{
|
||||
error_exit("Scratch buffer size (%d chars) exceeded", MAX_STRING_BUFFER - 1);
|
||||
}
|
||||
global_context.scratch_buffer[global_context.scratch_buffer_len++] = c;
|
||||
}
|
||||
char *scratch_buffer_to_string(void)
|
||||
{
|
||||
global_context.scratch_buffer[global_context.scratch_buffer_len] = '\0';
|
||||
return global_context.scratch_buffer;
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ typedef struct
|
||||
#define INVALID_RANGE ((SourceSpan){ INVALID_TOKEN_ID, INVALID_TOKEN_ID })
|
||||
#define MAX_LOCALS 0xFFFF
|
||||
#define MAX_SCOPE_DEPTH 0x1000
|
||||
#define MAX_PATH 0x10000
|
||||
#define MAX_STRING_BUFFER 0x10000
|
||||
#define MAX_MACRO_NESTING 1024
|
||||
#define MAX_FUNCTION_SIGNATURE_SIZE 2048
|
||||
#define MAX_PARAMS 512
|
||||
@@ -1264,6 +1264,8 @@ typedef struct _Context
|
||||
Token next_tok;
|
||||
TokenId docs_start;
|
||||
TokenId docs_end;
|
||||
void *llvm_debug_file;
|
||||
void *llvm_debug_compile_unit;
|
||||
} Context;
|
||||
|
||||
typedef struct
|
||||
@@ -1280,7 +1282,8 @@ typedef struct
|
||||
bool in_test_mode : 1;
|
||||
unsigned errors_found;
|
||||
unsigned warnings_found;
|
||||
char path_scratch[MAX_PATH];
|
||||
char scratch_buffer[MAX_STRING_BUFFER];
|
||||
size_t scratch_buffer_len;
|
||||
Decl* locals[MAX_LOCALS];
|
||||
DynamicScope scopes[MAX_SCOPE_DEPTH];
|
||||
STable scratch_table;
|
||||
@@ -1474,7 +1477,7 @@ CastKind cast_to_bool_kind(Type *type);
|
||||
bool cast_implicitly_to_runtime(Expr *expr);
|
||||
|
||||
const char *llvm_codegen(void *context);
|
||||
void *llvm_gen(Context *context);
|
||||
void *llvm_gen(Module *module);
|
||||
void llvm_codegen_setup();
|
||||
|
||||
void header_gen(Context *context);
|
||||
@@ -1581,7 +1584,7 @@ static inline TokenType token_type(Token token) { return toktypeptr(token.id.ind
|
||||
Decl *module_find_symbol(Module *module, const char *symbol);
|
||||
|
||||
bool parse_file(Context *context);
|
||||
Path *path_create_from_string(Context *context, const char *string, size_t len, SourceSpan span);
|
||||
Path *path_create_from_string(const char *string, size_t len, SourceSpan span);
|
||||
Path *path_find_parent_path(Context *context, Path *path);
|
||||
|
||||
const char *resolve_status_to_string(ResolveStatus status);
|
||||
@@ -1645,6 +1648,12 @@ void *stable_get(STable *table, const char *key);
|
||||
void *stable_delete(STable *table, const char *key);
|
||||
void stable_clear(STable *table);
|
||||
|
||||
void scratch_buffer_clear(void);
|
||||
void scratch_buffer_append(const char *string);
|
||||
void scratch_buffer_append_len(const char *string, size_t len);
|
||||
void scratch_buffer_append_char(char c);
|
||||
char *scratch_buffer_to_string(void);
|
||||
|
||||
const char *symtab_add(const char *symbol, uint32_t len, uint32_t fnv1hash, TokenType *type);
|
||||
|
||||
void *llvm_target_machine_create(void);
|
||||
|
||||
@@ -14,7 +14,7 @@ static void diagnostics_handler(LLVMDiagnosticInfoRef ref, void *context)
|
||||
switch (severity)
|
||||
{
|
||||
case LLVMDSError:
|
||||
error_exit("LLVM error generating code for %s: %s", ((GenContext *)context)->ast_context->module->name, message);
|
||||
error_exit("LLVM error generating code for %s: %s", ((GenContext *)context)->code_module->name, message);
|
||||
case LLVMDSWarning:
|
||||
severity_name = "warning";
|
||||
break;
|
||||
@@ -36,14 +36,14 @@ static void diagnostics_handler(LLVMDiagnosticInfoRef ref, void *context)
|
||||
LLVMDisposeMessage(message);
|
||||
}
|
||||
|
||||
static void gencontext_init(GenContext *context, Context *ast_context)
|
||||
static void gencontext_init(GenContext *context, Module *module)
|
||||
{
|
||||
memset(context, 0, sizeof(GenContext));
|
||||
context->context = LLVMContextCreate();
|
||||
context->bool_type = LLVMInt1TypeInContext(context->context);
|
||||
context->byte_type = LLVMInt8TypeInContext(context->context);
|
||||
LLVMContextSetDiagnosticHandler(context->context, &diagnostics_handler, context);
|
||||
context->ast_context = ast_context;
|
||||
context->code_module = module;
|
||||
}
|
||||
|
||||
static void gencontext_destroy(GenContext *context)
|
||||
@@ -941,47 +941,69 @@ const char *llvm_codegen(void *context)
|
||||
return object_name;
|
||||
}
|
||||
|
||||
void *llvm_gen(Context *context)
|
||||
void *llvm_gen(Module *module)
|
||||
{
|
||||
assert(intrinsics_setup);
|
||||
GenContext *gen_context = calloc(sizeof(GenContext), 1);
|
||||
gencontext_init(gen_context, context);
|
||||
gencontext_init(gen_context, module);
|
||||
gencontext_begin_module(gen_context);
|
||||
|
||||
VECEACH(module->contexts, j)
|
||||
{
|
||||
Context *context = module->contexts[j];
|
||||
gencontext_init_file_emit(gen_context, context);
|
||||
gen_context->debug.compile_unit = context->llvm_debug_compile_unit;
|
||||
gen_context->debug.file = context->llvm_debug_file;
|
||||
|
||||
VECEACH(context->external_symbol_list, i)
|
||||
{
|
||||
Decl *d = context->external_symbol_list[i];
|
||||
// Avoid duplicating symbol
|
||||
if (d->module == context->module) continue;
|
||||
llvm_emit_extern_decl(gen_context, context->external_symbol_list[i]);
|
||||
}
|
||||
VECEACH(context->methods, i)
|
||||
{
|
||||
llvm_emit_function_decl(gen_context, context->methods[i]);
|
||||
}
|
||||
VECEACH(context->types, i)
|
||||
{
|
||||
gencontext_emit_type_decls(gen_context, context->types[i]);
|
||||
}
|
||||
VECEACH(context->functions, i)
|
||||
{
|
||||
llvm_emit_function_decl(gen_context, context->functions[i]);
|
||||
}
|
||||
}
|
||||
|
||||
VECEACH(module->contexts, j)
|
||||
{
|
||||
Context *context = module->contexts[j];
|
||||
gen_context->debug.compile_unit = context->llvm_debug_compile_unit;
|
||||
gen_context->debug.file = context->llvm_debug_file;
|
||||
|
||||
VECEACH(context->vars, i)
|
||||
{
|
||||
gencontext_emit_global_variable_definition(gen_context, context->vars[i]);
|
||||
}
|
||||
VECEACH(context->vars, i)
|
||||
{
|
||||
gencontext_emit_global_variable_init(gen_context, context->vars[i]);
|
||||
}
|
||||
VECEACH(context->functions, i)
|
||||
{
|
||||
Decl *decl = context->functions[i];
|
||||
if (decl->func.body) llvm_emit_function_body(gen_context, decl);
|
||||
}
|
||||
VECEACH(context->methods, i)
|
||||
{
|
||||
Decl *decl = context->methods[i];
|
||||
if (decl->func.body) llvm_emit_function_body(gen_context, decl);
|
||||
}
|
||||
|
||||
gencontext_end_file_emit(gen_context, context);
|
||||
}
|
||||
// EmitDeferred()
|
||||
VECEACH(context->external_symbol_list, i)
|
||||
{
|
||||
llvm_emit_extern_decl(gen_context, context->external_symbol_list[i]);
|
||||
}
|
||||
VECEACH(context->methods, i)
|
||||
{
|
||||
llvm_emit_function_decl(gen_context, context->methods[i]);
|
||||
}
|
||||
VECEACH(context->functions, i)
|
||||
{
|
||||
llvm_emit_function_decl(gen_context, context->functions[i]);
|
||||
}
|
||||
VECEACH(context->types, i)
|
||||
{
|
||||
gencontext_emit_type_decls(gen_context, context->types[i]);
|
||||
}
|
||||
VECEACH(context->vars, i)
|
||||
{
|
||||
gencontext_emit_global_variable_definition(gen_context, context->vars[i]);
|
||||
}
|
||||
VECEACH(context->vars, i)
|
||||
{
|
||||
gencontext_emit_global_variable_init(gen_context, context->vars[i]);
|
||||
}
|
||||
VECEACH(context->functions, i)
|
||||
{
|
||||
Decl *decl = context->functions[i];
|
||||
if (decl->func.body) llvm_emit_function_body(gen_context, decl);
|
||||
}
|
||||
VECEACH(context->methods, i)
|
||||
{
|
||||
Decl *decl = context->methods[i];
|
||||
if (decl->func.body) llvm_emit_function_body(gen_context, decl);
|
||||
}
|
||||
|
||||
if (llvm_use_debug(gen_context)) LLVMDIBuilderFinalize(gen_context->debug.builder);
|
||||
|
||||
|
||||
@@ -88,7 +88,7 @@ typedef struct
|
||||
int return_expressions;
|
||||
Ast **defer_stack;
|
||||
DebugContext debug;
|
||||
Context *ast_context;
|
||||
Module *code_module;
|
||||
LLVMValueRef return_out;
|
||||
LLVMValueRef failable_out;
|
||||
LLVMBasicBlockRef error_exit_block;
|
||||
@@ -176,6 +176,8 @@ extern unsigned attribute_byval; // ByVal (param)
|
||||
extern unsigned attribute_inreg; // inreg (param)
|
||||
|
||||
void gencontext_begin_module(GenContext *c);
|
||||
void gencontext_init_file_emit(GenContext *c, Context *ast);
|
||||
void gencontext_end_file_emit(GenContext *c, Context *ast);
|
||||
void gencontext_end_module(GenContext *context);
|
||||
|
||||
// BE value
|
||||
|
||||
@@ -9,16 +9,27 @@ void gencontext_begin_module(GenContext *c)
|
||||
{
|
||||
assert(!c->module && "Expected no module");
|
||||
|
||||
c->ir_filename = strformat("%.*s.ll", (int)strlen(c->ast_context->file->name) - 3, c->ast_context->file->name);
|
||||
c->object_filename = strformat("%.*s.o", (int)strlen(c->ast_context->file->name) - 3, c->ast_context->file->name);
|
||||
scratch_buffer_clear();
|
||||
StringSlice slice = strtoslice(c->code_module->name->module);
|
||||
while (true)
|
||||
{
|
||||
StringSlice part = strnexttok(&slice, ':');
|
||||
scratch_buffer_append_len(part.ptr, part.len);
|
||||
if (!slice.len) break;
|
||||
slice.ptr++;
|
||||
slice.len--;
|
||||
scratch_buffer_append_char('.');
|
||||
}
|
||||
const char *result = scratch_buffer_to_string();
|
||||
c->ir_filename = strformat("%s.ll", result);
|
||||
// TODO filename should depend on platform.
|
||||
c->object_filename = strformat("%s.o", result);
|
||||
|
||||
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);
|
||||
c->module = LLVMModuleCreateWithNameInContext(c->code_module->name->module, c->context);
|
||||
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));
|
||||
LLVMSetSourceFileName(c->module, c->code_module->name->module, strlen(c->code_module->name->module));
|
||||
LLVMTypeRef options_type = LLVMInt8TypeInContext(c->context);
|
||||
|
||||
if (active_target.pic == PIC_BIG || active_target.pic == PIC_SMALL)
|
||||
@@ -35,31 +46,7 @@ void gencontext_begin_module(GenContext *c)
|
||||
}
|
||||
|
||||
LLVMSetTarget(c->module, platform_target.target_triple);
|
||||
if (active_target.debug_info != DEBUG_INFO_NONE)
|
||||
{
|
||||
const char *filename = c->ast_context->file->name;
|
||||
const char *dir_path = c->ast_context->file->dir_path;
|
||||
// Set runtime version here.
|
||||
c->debug.runtime_version = 1;
|
||||
c->debug.builder = LLVMCreateDIBuilder(c->module);
|
||||
c->debug.file = LLVMDIBuilderCreateFile(c->debug.builder, filename, strlen(filename), dir_path, strlen(dir_path));
|
||||
|
||||
bool is_optimized = active_target.optimization_level != OPTIMIZATION_NONE;
|
||||
const char *dwarf_flags = "";
|
||||
unsigned runtime_version = 1;
|
||||
LLVMDWARFEmissionKind emission_kind = active_target.debug_info == DEBUG_INFO_FULL ? LLVMDWARFEmissionFull : LLVMDWARFEmissionLineTablesOnly;
|
||||
c->debug.compile_unit = LLVMDIBuilderCreateCompileUnit(c->debug.builder, LLVMDWARFSourceLanguageC,
|
||||
c->debug.file, DWARF_PRODUCER_NAME,
|
||||
strlen(DWARF_PRODUCER_NAME), is_optimized,
|
||||
dwarf_flags, strlen(dwarf_flags),
|
||||
runtime_version, "" /* split name */, 0 /* len */,
|
||||
emission_kind, /* dwo */0, /* inlining */0,
|
||||
/* debug for profiling */0
|
||||
#if LLVM_VERSION_MAJOR > 10
|
||||
, "", 0, "", 0
|
||||
#endif
|
||||
);
|
||||
}
|
||||
// Setup all types. Not thread-safe, but at this point in time we can assume a single context.
|
||||
// We need to remove the context from the cache after this.
|
||||
// This would seem to indicate that we should change Type / actual type.
|
||||
@@ -72,8 +59,64 @@ void gencontext_begin_module(GenContext *c)
|
||||
global_context.type[i]->backend_type = NULL;
|
||||
global_context.type[i]->backend_debug_type = NULL;
|
||||
}
|
||||
if (active_target.debug_info != DEBUG_INFO_NONE)
|
||||
{
|
||||
c->debug.runtime_version = 1;
|
||||
c->debug.builder = LLVMCreateDIBuilder(c->module);
|
||||
}
|
||||
}
|
||||
|
||||
void gencontext_init_file_emit(GenContext *c, Context *ast)
|
||||
{
|
||||
if (active_target.debug_info != DEBUG_INFO_NONE)
|
||||
{
|
||||
const char *filename = ast->file->name;
|
||||
const char *dir_path = ast->file->dir_path;
|
||||
// Set runtime version here.
|
||||
ast->llvm_debug_file = LLVMDIBuilderCreateFile(c->debug.builder,
|
||||
filename,
|
||||
strlen(filename),
|
||||
dir_path,
|
||||
strlen(dir_path));
|
||||
|
||||
bool is_optimized = active_target.optimization_level != OPTIMIZATION_NONE;
|
||||
const char *dwarf_flags = "";
|
||||
unsigned runtime_version = 1;
|
||||
LLVMDWARFEmissionKind emission_kind =
|
||||
active_target.debug_info == DEBUG_INFO_FULL ? LLVMDWARFEmissionFull : LLVMDWARFEmissionLineTablesOnly;
|
||||
const char *debug_output_file = "";
|
||||
bool emit_debug_info_for_profiling = false;
|
||||
bool split_debug_inlining = false;
|
||||
const char *sysroot = "";
|
||||
const char *sdk = "";
|
||||
unsigned dwo_id = 0;
|
||||
ast->llvm_debug_compile_unit = LLVMDIBuilderCreateCompileUnit(c->debug.builder,
|
||||
LLVMDWARFSourceLanguageC,
|
||||
ast->llvm_debug_file,
|
||||
DWARF_PRODUCER_NAME,
|
||||
strlen(DWARF_PRODUCER_NAME),
|
||||
is_optimized,
|
||||
dwarf_flags,
|
||||
strlen(dwarf_flags),
|
||||
runtime_version,
|
||||
debug_output_file,
|
||||
strlen(debug_output_file),
|
||||
emission_kind,
|
||||
dwo_id,
|
||||
split_debug_inlining,
|
||||
emit_debug_info_for_profiling,
|
||||
sysroot,
|
||||
strlen(sysroot),
|
||||
sdk,
|
||||
strlen(sdk)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void gencontext_end_file_emit(GenContext *c, Context *ast)
|
||||
{
|
||||
}
|
||||
|
||||
void gencontext_end_module(GenContext *context)
|
||||
{
|
||||
|
||||
@@ -9,7 +9,7 @@ Decl *module_find_symbol(Module *module, const char *symbol)
|
||||
return stable_get(&module->symbols, symbol);
|
||||
}
|
||||
|
||||
Path *path_create_from_string(Context *context, const char *string, size_t len, SourceSpan span)
|
||||
Path *path_create_from_string(const char *string, size_t len, SourceSpan span)
|
||||
{
|
||||
Path *path = CALLOCS(Path);
|
||||
path->span = span;
|
||||
@@ -30,7 +30,7 @@ Path *path_find_parent_path(Context *context, Path *path)
|
||||
// No parent
|
||||
if (!last_scope_chars) return NULL;
|
||||
|
||||
Path *parent_path = path_create_from_string(context, path->module, last_scope_chars - path->module - 1, INVALID_RANGE);
|
||||
Path *parent_path = path_create_from_string(path->module, last_scope_chars - path->module - 1, INVALID_RANGE);
|
||||
|
||||
assert(parent_path && "Didn't we pass in a TOKEN_IDENT? That's the only reason this could fail.");
|
||||
|
||||
|
||||
@@ -257,12 +257,11 @@ 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 = global_context.path_scratch;
|
||||
scratch_buffer_clear();
|
||||
char *scratch_ptr = global_context.scratch_buffer;
|
||||
size_t offset = 0;
|
||||
SourceSpan span = source_span_from_token_id(context->tok.id);
|
||||
unsigned len = TOKLEN(context->tok);
|
||||
memcpy(scratch_ptr, TOKSTR(context->tok), len);
|
||||
offset += len;
|
||||
scratch_buffer_append_len(TOKSTR(context->tok), TOKLEN(context->tok));
|
||||
TokenId last_token;
|
||||
while (1)
|
||||
{
|
||||
@@ -277,14 +276,10 @@ static inline Path *parse_module_path(Context *context)
|
||||
span.end_loc = last_token;
|
||||
break;
|
||||
}
|
||||
scratch_ptr[offset++] = ':';
|
||||
scratch_ptr[offset++] = ':';
|
||||
len = TOKLEN(context->tok);
|
||||
memcpy(scratch_ptr + offset, TOKSTR(context->tok), len);
|
||||
offset += len;
|
||||
scratch_buffer_append("::");
|
||||
scratch_buffer_append_len(TOKSTR(context->tok), TOKLEN(context->tok));
|
||||
}
|
||||
scratch_ptr[offset] = '\0';
|
||||
return path_create_from_string(context, scratch_ptr, offset, span);
|
||||
return path_create_from_string(scratch_buffer_to_string(), global_context.scratch_buffer_len, span);
|
||||
}
|
||||
|
||||
|
||||
@@ -469,7 +464,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 = global_context.path_scratch;
|
||||
char *scratch_ptr = global_context.scratch_buffer;
|
||||
size_t offset = 0;
|
||||
|
||||
Path *path = CALLOCS(Path);
|
||||
|
||||
@@ -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 = global_context.path_scratch;
|
||||
char *param_path = global_context.scratch_buffer;
|
||||
memcpy(param_path, module->name->module, module->name->len);
|
||||
unsigned offset = module->name->len;
|
||||
param_path[offset++] = '(';
|
||||
|
||||
@@ -94,6 +94,7 @@ static Decl *sema_resolve_path_symbol(Context *context, const char *symbol, Path
|
||||
// 16. Otherwise return null.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// 17. Store that this external symbol is used and return.
|
||||
context_register_external_symbol(context, decl);
|
||||
return decl;
|
||||
|
||||
@@ -5,14 +5,14 @@
|
||||
#include "compiler_internal.h"
|
||||
|
||||
static unsigned arch_pointer_bit_width(OsType os, ArchType arch);
|
||||
static ArchType arch_from_llvm_string(const char *string);
|
||||
static EnvironmentType environment_type_from_llvm_string(const char *string);
|
||||
static ArchType arch_from_llvm_string(StringSlice string);
|
||||
static EnvironmentType environment_type_from_llvm_string(StringSlice string);
|
||||
static bool arch_is_supported(ArchType arch);
|
||||
static unsigned os_target_c_type_bits(OsType os, ArchType arch, CType type);
|
||||
static unsigned os_target_alignment_of_int(OsType os, ArchType arch, int bits);
|
||||
static unsigned os_target_alignment_of_float(OsType os, ArchType arch, int bits);
|
||||
static OsType os_from_llvm_string(const char *string);
|
||||
static VendorType vendor_from_llvm_string(const char *string);
|
||||
static OsType os_from_llvm_string(StringSlice string);
|
||||
static VendorType vendor_from_llvm_string(StringSlice string);
|
||||
static ObjectFormatType object_format_from_os(OsType os);
|
||||
static unsigned os_target_supports_int128(OsType os, ArchType arch);
|
||||
static unsigned os_target_supports_float16(OsType os, ArchType arch);
|
||||
@@ -387,9 +387,9 @@ static bool arch_is_supported(ArchType arch)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
static ArchType arch_from_llvm_string(const char *string)
|
||||
static ArchType arch_from_llvm_string(StringSlice slice)
|
||||
{
|
||||
#define STRCASE(_str, _arch) if (strcmp(string, _str) == 0) return _arch;
|
||||
#define STRCASE(_str, _arch) if (slicestrcmp(slice, _str)) return _arch;
|
||||
STRCASE("i386", ARCH_TYPE_X86)
|
||||
STRCASE("i486", ARCH_TYPE_X86)
|
||||
STRCASE("i586", ARCH_TYPE_X86)
|
||||
@@ -480,9 +480,19 @@ static ArchType arch_from_llvm_string(const char *string)
|
||||
// TODO parse arm & bpf names
|
||||
}
|
||||
|
||||
static EnvironmentType environment_type_from_llvm_string(const char *string)
|
||||
static EnvironmentType environment_type_from_llvm_string(StringSlice env)
|
||||
{
|
||||
#define STRCASE(_str, _arch) if (strcmp(string, _str) == 0) return _arch;
|
||||
// Remove trailing parts.
|
||||
for (size_t i = 0; i < env.len; i++)
|
||||
{
|
||||
if (env.ptr[i] < 'A')
|
||||
{
|
||||
env.len = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#define STRCASE(_str, _arch) if (slicestrcmp(env, _str) == 0) return _arch;
|
||||
STRCASE("gnu", ENV_TYPE_GNU)
|
||||
STRCASE("gnuabin32", ENV_TYPE_GNUABIN32)
|
||||
STRCASE("gnuabi64", ENV_TYPE_GNUABI64)
|
||||
@@ -508,13 +518,18 @@ static EnvironmentType environment_type_from_llvm_string(const char *string)
|
||||
#undef STRCASE
|
||||
}
|
||||
|
||||
static OsType os_from_llvm_string(const char *os_string)
|
||||
static OsType os_from_llvm_string(StringSlice os_string)
|
||||
{
|
||||
char *string = strdup(os_string);
|
||||
int len = 0;
|
||||
while (string[len] >= 'A') len++;
|
||||
string[len] = '\0';
|
||||
#define STRCASE(_str, _os) if (strncmp(string, _str, sizeof(_str)) == 0) { free(string); return _os; }
|
||||
// Remove trailing parts.
|
||||
for (size_t i = 0; i < os_string.len; i++)
|
||||
{
|
||||
if (os_string.ptr[i] < 'A')
|
||||
{
|
||||
os_string.len = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#define STRCASE(_str, _os) if (slicestrcmp(os_string, _str)) return _os;
|
||||
STRCASE("ananas", OS_TYPE_ANANAS)
|
||||
STRCASE("cloudabi", OS_TYPE_CLOUD_ABI)
|
||||
STRCASE("darwin", OS_TYPE_MACOSX)
|
||||
@@ -550,14 +565,13 @@ static OsType os_from_llvm_string(const char *os_string)
|
||||
STRCASE("hurd", OS_TYPE_HURD)
|
||||
STRCASE("wasi", OS_TYPE_WASI)
|
||||
STRCASE("emscripten", OS_TYPE_EMSCRIPTEN)
|
||||
free(string);
|
||||
return OS_TYPE_UNKNOWN;
|
||||
#undef STRCASE
|
||||
}
|
||||
|
||||
static VendorType vendor_from_llvm_string(const char *string)
|
||||
static VendorType vendor_from_llvm_string(StringSlice slice)
|
||||
{
|
||||
#define STRCASE(_str, _vendor) if (strcmp(string, _str) == 0) return _vendor;
|
||||
#define STRCASE(_str, _vendor) if (slicestrcmp(slice, _str) == 0) return _vendor;
|
||||
STRCASE("apple", VENDOR_APPLE)
|
||||
STRCASE("pc", VENDOR_PC)
|
||||
STRCASE("scei", VENDOR_SCEI)
|
||||
@@ -1131,20 +1145,19 @@ void target_setup(BuildTarget *target)
|
||||
|
||||
LLVMTargetMachineRef machine = llvm_target_machine_create();
|
||||
char *target_triple = LLVMGetTargetMachineTriple(machine);
|
||||
platform_target.target_triple = strdup(target_triple);
|
||||
LLVMDisposeMessage(target_triple);
|
||||
LLVMDisposeTargetMachine(machine);
|
||||
|
||||
platform_target.target_triple = strdup(target_triple);
|
||||
platform_target.arch = arch_from_llvm_string(strtok(target_triple, "-"));
|
||||
StringSlice target_triple_string = strtoslice(platform_target.target_triple);
|
||||
platform_target.arch = arch_from_llvm_string(strnexttok(&target_triple_string, '-'));
|
||||
if (!arch_is_supported(platform_target.arch))
|
||||
{
|
||||
printf("WARNING! This architecture is not supported.\n");
|
||||
}
|
||||
platform_target.vendor = vendor_from_llvm_string(strtok(NULL, "-"));
|
||||
platform_target.os = os_from_llvm_string(strtok(NULL, "-"));
|
||||
char *env = strtok(NULL, "0123456789");
|
||||
platform_target.environment_type = env ? environment_type_from_llvm_string(env) : ENV_TYPE_UNKNOWN;
|
||||
|
||||
LLVMDisposeMessage(target_triple);
|
||||
platform_target.vendor = vendor_from_llvm_string(strnexttok(&target_triple_string, '-'));
|
||||
platform_target.os = os_from_llvm_string(strnexttok(&target_triple_string, '-'));
|
||||
platform_target.environment_type = environment_type_from_llvm_string(target_triple_string);
|
||||
|
||||
platform_target.float_abi = false;
|
||||
platform_target.little_endian = arch_little_endian(platform_target.arch);
|
||||
|
||||
@@ -368,9 +368,26 @@ static inline bool is_all_lower(const char* string)
|
||||
#define __printflike(x, y)
|
||||
#endif
|
||||
|
||||
typedef struct StringSlice_
|
||||
{
|
||||
const char *ptr;
|
||||
size_t len;
|
||||
} StringSlice;
|
||||
|
||||
char *strcat_arena(const char *a, const char *b);
|
||||
char *strformat(const char *var, ...) __printflike(1, 2);
|
||||
char *strcopy(const char *start, size_t len);
|
||||
StringSlice strnexttok(StringSlice *slice, char separator);
|
||||
static inline bool slicestrcmp(StringSlice slice, const char *other)
|
||||
{
|
||||
if (strlen(other) != slice.len) return false;
|
||||
return strncmp(slice.ptr, other, slice.len) == 0;
|
||||
}
|
||||
|
||||
static inline StringSlice strtoslice(const char *data)
|
||||
{
|
||||
return (StringSlice) { data, strlen(data) };
|
||||
}
|
||||
|
||||
#define MAX(_a, _b) ({ \
|
||||
typeof(_a) __a__ = (_a); \
|
||||
|
||||
@@ -23,6 +23,24 @@ char *strformat(const char *var, ...)
|
||||
return buffer;
|
||||
}
|
||||
|
||||
StringSlice strnexttok(StringSlice *slice, char separator)
|
||||
{
|
||||
for (size_t i = 0; i < slice->len; i++)
|
||||
{
|
||||
if (slice->ptr[i] == separator)
|
||||
{
|
||||
StringSlice result = { slice->ptr, i };
|
||||
slice->ptr = slice->ptr + i + 1;
|
||||
slice->len = slice->len - i - 1;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
StringSlice result = *slice;
|
||||
slice->ptr = slice->ptr + slice->len;
|
||||
slice->len = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
char *strcopy(const char *start, size_t len)
|
||||
{
|
||||
char *buffer = malloc_arena(len + 1);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
module test;
|
||||
module array_casts;
|
||||
|
||||
|
||||
func void test()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// #target: x64_darwin
|
||||
module testing;
|
||||
module array_literal;
|
||||
|
||||
func double test(uint x)
|
||||
{
|
||||
|
||||
@@ -8,6 +8,6 @@ struct Foo
|
||||
|
||||
Foo[10] array;
|
||||
|
||||
// #expect: array_struct.ll
|
||||
// #expect: test.ll
|
||||
|
||||
@array = protected global [10 x %test.Foo] zeroinitializer, align 16
|
||||
@@ -13,7 +13,7 @@ Connection[3] link
|
||||
{2, "link2", 20},
|
||||
{3, "link3", 30} };
|
||||
|
||||
// #expect: complex_array_const.ll
|
||||
// #expect: test.ll
|
||||
|
||||
@.str = private constant [6 x i8] c"link1\00"
|
||||
@.str.1 = private constant [6 x i8] c"link2\00"
|
||||
|
||||
@@ -18,7 +18,7 @@ func int foo()
|
||||
}
|
||||
|
||||
|
||||
// #expect: int_assign.ll
|
||||
// #expect: test.ll
|
||||
|
||||
%x = alloca i32, align 4
|
||||
%y = alloca i32, align 4
|
||||
|
||||
@@ -11,7 +11,7 @@ public char g = '"';
|
||||
public char h = '\\';
|
||||
public char i = '\e';
|
||||
|
||||
// #expect: file1.ll
|
||||
// #expect: test.ll
|
||||
|
||||
@a = global i8 32
|
||||
@b = global i8 13
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
module test;
|
||||
module cast_expr;
|
||||
|
||||
public func int main(int argc, char** argv)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
module test;
|
||||
module simple_float_sub_neg;
|
||||
|
||||
func double test(double a, double b, double c, double d)
|
||||
{
|
||||
|
||||
@@ -5,6 +5,6 @@ func char* foo()
|
||||
return "*** Word \"%s\" on line %d is not";
|
||||
}
|
||||
|
||||
// #expect: strings.ll
|
||||
// #expect: test.ll
|
||||
|
||||
@.str = private constant [32 x i8] c"*** Word \22%s\22 on line %d is not\00"
|
||||
@@ -48,7 +48,7 @@ func void denormalize(InternalFPF* ptr)
|
||||
}
|
||||
|
||||
|
||||
// #expect: assorted_tests.ll
|
||||
// #expect: test.ll
|
||||
|
||||
%pp = alloca i8*, align 8
|
||||
%w_cnt = alloca i32, align 4
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
module test;
|
||||
module double_return;
|
||||
|
||||
func int test(bool pos, bool color)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
module test;
|
||||
module varargs;
|
||||
|
||||
extern func void printf(char* c, ...);
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ func int extract_or_test_files()
|
||||
return 0;
|
||||
}
|
||||
|
||||
// #expect: external_global.ll
|
||||
// #expect: test.ll
|
||||
|
||||
%test.UzGlobs = type { i8, [1 x %test.MinInfo], %test.MinInfo* }
|
||||
%test.MinInfo = type { i64, i32 }
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// #target: x64_darwin
|
||||
|
||||
module test;
|
||||
module const_pointer;
|
||||
|
||||
double foo = 17;
|
||||
double bar = 12.0;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
module foo;
|
||||
module pointer_index;
|
||||
|
||||
public func void test1(int* x)
|
||||
{
|
||||
|
||||
@@ -46,7 +46,7 @@ public func int main(int argc)
|
||||
return 0;
|
||||
}
|
||||
|
||||
// #expect: defer_break.ll
|
||||
// #expect: foo.ll
|
||||
call void @foo.defer2()
|
||||
%1 = load i32, i32* %a
|
||||
%eq = icmp eq i32 %1, 1
|
||||
|
||||
@@ -22,7 +22,7 @@ public func int main(int argc)
|
||||
return 0;
|
||||
}
|
||||
|
||||
// #expect: defer_break_simple.ll
|
||||
// #expect: test.ll
|
||||
|
||||
store i32 0, i32* %a
|
||||
br label %while.begin
|
||||
|
||||
@@ -33,7 +33,7 @@ public func int main(int argc)
|
||||
return 0 + argc;
|
||||
}
|
||||
|
||||
// #expect: defer_return.ll
|
||||
// #expect: test.ll
|
||||
|
||||
while.begin:
|
||||
%1 = load i32, i32* %a
|
||||
|
||||
@@ -12,7 +12,7 @@ func void test()
|
||||
}
|
||||
}
|
||||
|
||||
// #expect: foreach_break.ll
|
||||
// #expect: test.ll
|
||||
|
||||
store i32 0, i32* %g, align 4
|
||||
store i64 0, i64* %idx, align 8
|
||||
|
||||
@@ -32,7 +32,7 @@ func void main()
|
||||
}
|
||||
}
|
||||
|
||||
// #expect: foreach_common.ll
|
||||
// #expect: test.ll
|
||||
|
||||
entry:
|
||||
%foo = alloca [3 x float], align 4
|
||||
|
||||
@@ -11,7 +11,7 @@ func void test()
|
||||
}
|
||||
}
|
||||
|
||||
// #expect: foreach_with_error.ll
|
||||
// #expect: test.ll
|
||||
|
||||
entry:
|
||||
%x = alloca [3 x i32], align 4
|
||||
|
||||
@@ -26,7 +26,7 @@ func void test3(int x)
|
||||
else { x += 1; }
|
||||
}
|
||||
|
||||
// #expect: if_tests.ll
|
||||
// #expect: iftest.ll
|
||||
|
||||
%x = alloca i32, align 4
|
||||
store i32 %0, i32* %x, align 4
|
||||
|
||||
@@ -28,7 +28,7 @@ func int main()
|
||||
return 0;
|
||||
}
|
||||
|
||||
// #expect: while_switch.ll
|
||||
// #expect: test.ll
|
||||
|
||||
|
||||
@.str = private constant [2 x i8] c"3\00"
|
||||
|
||||
@@ -8,7 +8,7 @@ struct Foo
|
||||
double a;
|
||||
}
|
||||
|
||||
// #expect: simple_struct.ll
|
||||
// #expect: test.ll
|
||||
|
||||
%test.Foo = type { i32, double }
|
||||
@a = protected global %test.Foo zeroinitializer, align 8
|
||||
@@ -12,7 +12,7 @@ func void test1()
|
||||
Point p = { 5, 6 };
|
||||
}
|
||||
|
||||
// #expect: struct_codegen.ll
|
||||
// #expect: test.ll
|
||||
|
||||
%test.Point = type { i32, i32 }
|
||||
@Point = linkonce_odr constant i8 1
|
||||
|
||||
@@ -17,7 +17,7 @@ Foo foo6;
|
||||
const Foo FOO7 = { 1, 2 };
|
||||
Foo foo8 = FOO7;
|
||||
|
||||
// #expect: struct_const_construct_simple.ll
|
||||
// #expect: structo.ll
|
||||
|
||||
%structo.Foo = type { i32, i64 }
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ struct Foo6 @packed
|
||||
$assert(Foo6.sizeof == 8);
|
||||
public Foo6 foo6 = { 1, 2, 3 };
|
||||
|
||||
// #expect: struct_pack_and_align.ll
|
||||
// #expect: struct2.ll
|
||||
|
||||
%struct2.Foo1 = type <{ i64, i8, [3 x i8] }>
|
||||
%struct2.Foo2 = type <{ i8, i64, [3 x i8] }>
|
||||
|
||||
@@ -11,7 +11,7 @@ Foo g = { .b = 2.3 };
|
||||
Foo h = { .a = 23, .b = 2.3 };
|
||||
Foo i = { .b = 2.3, .a = 23 };
|
||||
|
||||
// #expect: union_codegen_const.ll
|
||||
// #expect: test.ll
|
||||
|
||||
@f = protected global { i32, [4 x i8] } { i32 23, [4 x i8] undef }, align 8
|
||||
@g = protected global %test.Foo { double 2.300000e+00 }, align 8
|
||||
|
||||
@@ -17,7 +17,7 @@ func void test()
|
||||
UnionB b = { .c = bar(), .b = {} };
|
||||
}
|
||||
|
||||
// #expect: union_codegen_overwrite_call.ll
|
||||
// #expect: test.ll
|
||||
|
||||
entry:
|
||||
%b = alloca %test.UnionB, align 8
|
||||
|
||||
@@ -17,7 +17,7 @@ func void test(Blend_Map_Entry* foo)
|
||||
{
|
||||
}
|
||||
|
||||
// #expect: union_in_struct.ll
|
||||
// #expect: test.ll
|
||||
|
||||
|
||||
%test.Blend_Map_Entry = type { %test.vals }
|
||||
|
||||
Reference in New Issue
Block a user