diff --git a/src/compiler/ast.c b/src/compiler/ast.c index 3ce3aa1ac..5a4250ea0 100644 --- a/src/compiler/ast.c +++ b/src/compiler/ast.c @@ -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); } diff --git a/src/compiler/compiler.c b/src/compiler/compiler.c index 23c34da16..8e0c8084c 100644 --- a/src/compiler/compiler.c +++ b/src/compiler/compiler.c @@ -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; +} diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 214e2a1bb..e91210fca 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -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); diff --git a/src/compiler/llvm_codegen.c b/src/compiler/llvm_codegen.c index 1f3993a84..26ec0686d 100644 --- a/src/compiler/llvm_codegen.c +++ b/src/compiler/llvm_codegen.c @@ -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); diff --git a/src/compiler/llvm_codegen_internal.h b/src/compiler/llvm_codegen_internal.h index 8ba05f23f..4f4a0e0dc 100644 --- a/src/compiler/llvm_codegen_internal.h +++ b/src/compiler/llvm_codegen_internal.h @@ -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 diff --git a/src/compiler/llvm_codegen_module.c b/src/compiler/llvm_codegen_module.c index af4850017..43f506c5f 100644 --- a/src/compiler/llvm_codegen_module.c +++ b/src/compiler/llvm_codegen_module.c @@ -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) { diff --git a/src/compiler/module.c b/src/compiler/module.c index 03d2aadee..4433c4e86 100644 --- a/src/compiler/module.c +++ b/src/compiler/module.c @@ -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."); diff --git a/src/compiler/parse_global.c b/src/compiler/parse_global.c index 8d315d219..d01254dac 100644 --- a/src/compiler/parse_global.c +++ b/src/compiler/parse_global.c @@ -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); diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index 38ceb14cb..c68f05917 100644 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -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++] = '('; diff --git a/src/compiler/sema_name_resolution.c b/src/compiler/sema_name_resolution.c index 5abf9ea3f..fcceac3a1 100644 --- a/src/compiler/sema_name_resolution.c +++ b/src/compiler/sema_name_resolution.c @@ -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; diff --git a/src/compiler/target.c b/src/compiler/target.c index ff15065b0..25bf319d1 100644 --- a/src/compiler/target.c +++ b/src/compiler/target.c @@ -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); diff --git a/src/utils/lib.h b/src/utils/lib.h index 815628ac8..447fbc205 100644 --- a/src/utils/lib.h +++ b/src/utils/lib.h @@ -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); \ diff --git a/src/utils/stringutils.c b/src/utils/stringutils.c index 7599477d6..353724783 100644 --- a/src/utils/stringutils.c +++ b/src/utils/stringutils.c @@ -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); diff --git a/test/test_suite/arrays/array_casts.c3t b/test/test_suite/arrays/array_casts.c3t index 7974d4c80..db777181b 100644 --- a/test/test_suite/arrays/array_casts.c3t +++ b/test/test_suite/arrays/array_casts.c3t @@ -1,4 +1,4 @@ -module test; +module array_casts; func void test() diff --git a/test/test_suite/arrays/array_literal.c3t b/test/test_suite/arrays/array_literal.c3t index 42e904f99..27348361e 100644 --- a/test/test_suite/arrays/array_literal.c3t +++ b/test/test_suite/arrays/array_literal.c3t @@ -1,5 +1,5 @@ // #target: x64_darwin -module testing; +module array_literal; func double test(uint x) { diff --git a/test/test_suite/arrays/array_struct.c3t b/test/test_suite/arrays/array_struct.c3t index 159ca97ca..d765fac87 100644 --- a/test/test_suite/arrays/array_struct.c3t +++ b/test/test_suite/arrays/array_struct.c3t @@ -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 \ No newline at end of file diff --git a/test/test_suite/arrays/complex_array_const.c3t b/test/test_suite/arrays/complex_array_const.c3t index cde380aa5..381e6ff0c 100644 --- a/test/test_suite/arrays/complex_array_const.c3t +++ b/test/test_suite/arrays/complex_array_const.c3t @@ -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" diff --git a/test/test_suite/assignment/int_assign.c3t b/test/test_suite/assignment/int_assign.c3t index 19b698977..d32e2680c 100644 --- a/test/test_suite/assignment/int_assign.c3t +++ b/test/test_suite/assignment/int_assign.c3t @@ -18,7 +18,7 @@ func int foo() } -// #expect: int_assign.ll +// #expect: test.ll %x = alloca i32, align 4 %y = alloca i32, align 4 diff --git a/test/test_suite/constants/char_literals.c3t b/test/test_suite/constants/char_literals.c3t index 8aa4b0900..d843c7b5a 100644 --- a/test/test_suite/constants/char_literals.c3t +++ b/test/test_suite/constants/char_literals.c3t @@ -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 diff --git a/test/test_suite/expressions/casts/cast_expr.c3t b/test/test_suite/expressions/casts/cast_expr.c3t index 14b06f77d..a33cc9887 100644 --- a/test/test_suite/expressions/casts/cast_expr.c3t +++ b/test/test_suite/expressions/casts/cast_expr.c3t @@ -1,4 +1,4 @@ -module test; +module cast_expr; public func int main(int argc, char** argv) { diff --git a/test/test_suite/expressions/simple_float_sub_neg.c3t b/test/test_suite/expressions/simple_float_sub_neg.c3t index aa2f4808c..c30e80e4b 100644 --- a/test/test_suite/expressions/simple_float_sub_neg.c3t +++ b/test/test_suite/expressions/simple_float_sub_neg.c3t @@ -1,4 +1,4 @@ -module test; +module simple_float_sub_neg; func double test(double a, double b, double c, double d) { diff --git a/test/test_suite/expressions/strings.c3t b/test/test_suite/expressions/strings.c3t index 02b477a19..0d2e3984b 100644 --- a/test/test_suite/expressions/strings.c3t +++ b/test/test_suite/expressions/strings.c3t @@ -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" \ No newline at end of file diff --git a/test/test_suite/functions/assorted_tests.c3t b/test/test_suite/functions/assorted_tests.c3t index 479823689..ecf1b4f37 100644 --- a/test/test_suite/functions/assorted_tests.c3t +++ b/test/test_suite/functions/assorted_tests.c3t @@ -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 diff --git a/test/test_suite/functions/double_return.c3t b/test/test_suite/functions/double_return.c3t index 9ebc8c9a7..6d158e208 100644 --- a/test/test_suite/functions/double_return.c3t +++ b/test/test_suite/functions/double_return.c3t @@ -1,4 +1,4 @@ -module test; +module double_return; func int test(bool pos, bool color) { diff --git a/test/test_suite/functions/varargs.c3t b/test/test_suite/functions/varargs.c3t index dd976fbe6..0121ba2f9 100644 --- a/test/test_suite/functions/varargs.c3t +++ b/test/test_suite/functions/varargs.c3t @@ -1,4 +1,4 @@ -module test; +module varargs; extern func void printf(char* c, ...); diff --git a/test/test_suite/globals/external_global.c3t b/test/test_suite/globals/external_global.c3t index 145ab009c..5f24ea566 100644 --- a/test/test_suite/globals/external_global.c3t +++ b/test/test_suite/globals/external_global.c3t @@ -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 } diff --git a/test/test_suite/pointers/const_pointer.c3t b/test/test_suite/pointers/const_pointer.c3t index e4b2239bd..a1f02cd56 100644 --- a/test/test_suite/pointers/const_pointer.c3t +++ b/test/test_suite/pointers/const_pointer.c3t @@ -1,6 +1,6 @@ // #target: x64_darwin -module test; +module const_pointer; double foo = 17; double bar = 12.0; diff --git a/test/test_suite/pointers/pointer_index.c3t b/test/test_suite/pointers/pointer_index.c3t index 65d7c815d..67dccb65d 100644 --- a/test/test_suite/pointers/pointer_index.c3t +++ b/test/test_suite/pointers/pointer_index.c3t @@ -1,4 +1,4 @@ -module foo; +module pointer_index; public func void test1(int* x) { diff --git a/test/test_suite/statements/defer_break.c3t b/test/test_suite/statements/defer_break.c3t index 32fd3a4d2..5eef58756 100644 --- a/test/test_suite/statements/defer_break.c3t +++ b/test/test_suite/statements/defer_break.c3t @@ -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 diff --git a/test/test_suite/statements/defer_break_simple.c3t b/test/test_suite/statements/defer_break_simple.c3t index 96b9178d8..fee09974b 100644 --- a/test/test_suite/statements/defer_break_simple.c3t +++ b/test/test_suite/statements/defer_break_simple.c3t @@ -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 diff --git a/test/test_suite/statements/defer_return.c3t b/test/test_suite/statements/defer_return.c3t index 77f76ea45..995510b83 100644 --- a/test/test_suite/statements/defer_return.c3t +++ b/test/test_suite/statements/defer_return.c3t @@ -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 diff --git a/test/test_suite/statements/foreach_break.c3t b/test/test_suite/statements/foreach_break.c3t index 9bc658f26..e15810df3 100644 --- a/test/test_suite/statements/foreach_break.c3t +++ b/test/test_suite/statements/foreach_break.c3t @@ -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 diff --git a/test/test_suite/statements/foreach_common.c3t b/test/test_suite/statements/foreach_common.c3t index 8be37b7f3..9cebccda6 100644 --- a/test/test_suite/statements/foreach_common.c3t +++ b/test/test_suite/statements/foreach_common.c3t @@ -32,7 +32,7 @@ func void main() } } -// #expect: foreach_common.ll +// #expect: test.ll entry: %foo = alloca [3 x float], align 4 diff --git a/test/test_suite/statements/foreach_with_error.c3t b/test/test_suite/statements/foreach_with_error.c3t index bdbb80936..066c8d77c 100644 --- a/test/test_suite/statements/foreach_with_error.c3t +++ b/test/test_suite/statements/foreach_with_error.c3t @@ -11,7 +11,7 @@ func void test() } } -// #expect: foreach_with_error.ll +// #expect: test.ll entry: %x = alloca [3 x i32], align 4 diff --git a/test/test_suite/statements/if_tests.c3t b/test/test_suite/statements/if_tests.c3t index c5dc5a0f4..f0a0eb957 100644 --- a/test/test_suite/statements/if_tests.c3t +++ b/test/test_suite/statements/if_tests.c3t @@ -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 diff --git a/test/test_suite/statements/while_switch.c3t b/test/test_suite/statements/while_switch.c3t index c015ed0f3..bde41c2c3 100644 --- a/test/test_suite/statements/while_switch.c3t +++ b/test/test_suite/statements/while_switch.c3t @@ -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" diff --git a/test/test_suite/struct/simple_struct.c3t b/test/test_suite/struct/simple_struct.c3t index 35573c6ba..7208ae0f6 100644 --- a/test/test_suite/struct/simple_struct.c3t +++ b/test/test_suite/struct/simple_struct.c3t @@ -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 \ No newline at end of file diff --git a/test/test_suite/struct/struct_codegen.c3t b/test/test_suite/struct/struct_codegen.c3t index 4f974d3ae..b1edcdabc 100644 --- a/test/test_suite/struct/struct_codegen.c3t +++ b/test/test_suite/struct/struct_codegen.c3t @@ -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 diff --git a/test/test_suite/struct/struct_const_construct_simple.c3t b/test/test_suite/struct/struct_const_construct_simple.c3t index 618c4ea36..2938a8615 100644 --- a/test/test_suite/struct/struct_const_construct_simple.c3t +++ b/test/test_suite/struct/struct_const_construct_simple.c3t @@ -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 } diff --git a/test/test_suite/struct/struct_pack_and_align.c3t b/test/test_suite/struct/struct_pack_and_align.c3t index 81ff0d39a..1866ea728 100644 --- a/test/test_suite/struct/struct_pack_and_align.c3t +++ b/test/test_suite/struct/struct_pack_and_align.c3t @@ -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] }> diff --git a/test/test_suite/union/union_codegen_const.c3t b/test/test_suite/union/union_codegen_const.c3t index 36509c722..0704d9f03 100644 --- a/test/test_suite/union/union_codegen_const.c3t +++ b/test/test_suite/union/union_codegen_const.c3t @@ -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 diff --git a/test/test_suite/union/union_codegen_overwrite_call.c3t b/test/test_suite/union/union_codegen_overwrite_call.c3t index 4e24777d7..d99b80d02 100644 --- a/test/test_suite/union/union_codegen_overwrite_call.c3t +++ b/test/test_suite/union/union_codegen_overwrite_call.c3t @@ -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 diff --git a/test/test_suite/union/union_in_struct.c3t b/test/test_suite/union/union_in_struct.c3t index c5800d286..59e5e0286 100644 --- a/test/test_suite/union/union_in_struct.c3t +++ b/test/test_suite/union/union_in_struct.c3t @@ -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 }